]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/DPH/scan_loop.c
25977e57a64a2ef2b1a450e42dc02692bc9c3d6e
[kiibohd-controller.git] / Scan / DPH / scan_loop.c
1 /* Copyright (C) 2011-2013 by Joseph Makuch
2  * Additions by Jacob Alexander (2013-2014)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 3.0 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 // ----- Includes -----
19
20 // Compiler Includes
21 #include <Lib/ScanLib.h>
22
23 // Project Includes
24 #include <cli.h>
25 #include <led.h>
26 #include <print.h>
27
28 // Local Includes
29 #include "scan_loop.h"
30
31
32
33 // ----- Defines -----
34
35 // TODO dfj defines...needs commenting and maybe some cleaning...
36 #define MAX_PRESS_DELTA_MV 450 // As measured from the Teensy ADC pin
37 #define THRESHOLD_MV (MAX_PRESS_DELTA_MV >> 1)
38 //(2560 / (0x3ff/2)) ~= 5
39 #define MV_PER_ADC 5
40 #define THRESHOLD (THRESHOLD_MV / MV_PER_ADC)
41
42 #define STROBE_SETTLE 1
43
44 #define TEST_KEY_STROBE (0x05)
45 #define TEST_KEY_MASK (1 << 0)
46
47 #define ADHSM 7
48
49 #define RIGHT_JUSTIFY 0
50 #define LEFT_JUSTIFY (0xff)
51
52 // set left or right justification here:
53 #define JUSTIFY_ADC RIGHT_JUSTIFY
54 #define ADLAR_MASK (1 << ADLAR)
55
56 #ifdef JUSTIFY_ADC
57 #define ADLAR_BITS ((ADLAR_MASK) & (JUSTIFY_ADC))
58 #else // defaults to right justification.
59 #define ADLAR_BITS 0
60 #endif
61
62 // full muxmask
63 #define FULL_MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2) | (1 << MUX3) | (1 << MUX4))
64
65 // F0-f7 pins only muxmask.
66 #define MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2))
67
68 // Strobe Masks
69 #define D_MASK (0xff)
70 #define E_MASK (0x03)
71 #define C_MASK (0xff)
72
73 // set ADC clock prescale
74 #define PRESCALE_MASK ((1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2))
75 #define PRESCALE_SHIFT (ADPS0)
76 #define PRESCALE 3
77
78 // Max number of strobes supported by the hardware
79 // Strobe lines are detected at startup, extra strobes cause anomalies like phantom keypresses
80 #define MAX_STROBES 18
81
82 // Number of consecutive samples required to pass debounce
83 #define DEBOUNCE_THRESHOLD 5
84
85 #define MUXES_COUNT 8
86 #define MUXES_COUNT_XSHIFT 3
87
88 #define WARMUP_LOOPS ( 1024 )
89 #define WARMUP_STOP (WARMUP_LOOPS - 1)
90
91 #define SAMPLE_CONTROL 3
92
93 #define KEY_COUNT ((MAX_STROBES) * (MUXES_COUNT))
94
95 #define RECOVERY_CONTROL 1
96 #define RECOVERY_SOURCE  0
97 #define RECOVERY_SINK    2
98
99 #define ON  1
100 #define OFF 0
101
102 // mix in 1/4 of the current average to the running average. -> (@mux_mix = 2)
103 #define MUX_MIX 2
104
105 #define IDLE_COUNT_MASK 0xff
106 #define IDLE_COUNT_SHIFT 8
107
108 // av = (av << shift) - av + sample; av >>= shift
109 // e.g. 1 -> (av + sample) / 2 simple average of new and old
110 //      2 -> (3 * av + sample) / 4 i.e. 3:1 mix of old to new.
111 //      3 -> (7 * av + sample) / 8 i.e. 7:1 mix of old to new.
112 #define KEYS_AVERAGES_MIX_SHIFT 3
113
114
115
116 // ----- Macros -----
117
118 // Select mux
119 #define SET_FULL_MUX(X) ((ADMUX) = (((ADMUX) & ~(FULL_MUX_MASK)) | ((X) & (FULL_MUX_MASK))))
120
121
122
123 // ----- Function Declarations -----
124
125 void cliFunc_echo      ( char* args );
126 void cliFunc_keyDebug  ( char* args );
127 void cliFunc_senseDebug( char* args );
128
129
130
131 // ----- Variables -----
132
133 // Buffer used to inform the macro processing module which keys have been detected as pressed
134 volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
135 volatile uint8_t KeyIndex_BufferUsed;
136
137
138 // Scan Module command dictionary
139 char*       scanCLIDictName = "DPH Module Commands";
140 CLIDictItem scanCLIDict[] = {
141         { "echo",       "Example command, echos the arguments.", cliFunc_echo },
142         { "keyDebug",   "Enables long debug for each keypress." NL "\t\tkeycode - [strobe:mux] : sense val : threshold+delta=total : margin", cliFunc_keyDebug },
143         { "senseDebug", "Prints out the current sense table N times." NL "\t\tsense:threshold:delta.", cliFunc_senseDebug },
144         { 0, 0, 0 } // Null entry for dictionary end
145 };
146
147 // CLI Control Variables
148 uint8_t enableKeyDebug  = 1; // XXX Debugging on by default for now -HaaTa
149 uint8_t senseDebugCount = 0;
150
151
152 // TODO dfj variables...needs cleaning up and commenting
153
154 // Variables used to calculate the starting sense value (averaging)
155 uint32_t full_avg = 0;
156 uint32_t high_avg = 0;
157 uint32_t  low_avg = 0;
158
159 uint8_t  high_count = 0;
160 uint8_t   low_count = 0;
161
162
163 uint16_t samples[MAX_STROBES][MUXES_COUNT];
164
165 uint8_t cur_keymap[MAX_STROBES];
166
167 uint8_t keymap_change;
168
169 uint16_t threshold = THRESHOLD;
170
171 uint8_t column = 0;
172
173 uint16_t keys_averages_acc[KEY_COUNT];
174 uint16_t keys_averages    [KEY_COUNT];
175 uint8_t  keys_debounce    [KEY_COUNT]; // Contains debounce statistics
176 uint8_t  keys_problem     [KEY_COUNT]; // Marks keys that should be ignored (determined by averaging at startup)
177
178 uint8_t full_samples[KEY_COUNT];
179
180 // TODO: change this to 'booting', then count down.
181 uint16_t boot_count = 0;
182
183 uint16_t idle_count = 0;
184 uint8_t idle = 1;
185
186 uint8_t error = 0;
187 uint16_t error_data = 0;
188
189 uint8_t total_strobes = MAX_STROBES;
190 uint8_t strobe_map[MAX_STROBES];
191
192
193
194 // ----- Function Declarations -----
195
196 void dumpSenseTable();
197
198 void recovery( uint8_t on );
199
200 int sampleColumn( uint8_t column );
201
202 void capsense_scan();
203
204 void setup_ADC();
205
206 void strobe_w( uint8_t strobe_num );
207
208 uint8_t testColumn( uint8_t strobe );
209
210
211
212 // ----- Functions -----
213
214 // Initial setup for cap sense controller
215 inline void Scan_setup()
216 {
217         // Register Scan CLI dictionary
218         CLI_registerDictionary( scanCLIDict, scanCLIDictName );
219
220         // TODO dfj code...needs cleanup + commenting...
221         setup_ADC();
222
223         DDRC  = C_MASK;
224         PORTC = 0;
225         DDRD  = D_MASK;
226         PORTD = 0;
227         DDRE  = E_MASK;
228         PORTE = 0 ;
229
230         // Hardcoded strobes for debugging
231         // Strobes start at 0 and go to 17 (18), not all Model Fs use all of the available strobes
232         // The single row ribbon connector Model Fs only have a max of 16 strobes
233 #define KEYPAD_50KEY
234 //#define KISHSAVER_STROBE
235 //#define KISHSAVER_OLD_STROBE
236 //#define TERMINAL_6110668_OLD_STROBE
237 //#define UNSAVER_OLD_STROBE
238 #ifdef KISHSAVER_OLD_STROBE
239         total_strobes = 9;
240
241         strobe_map[0] = 2; // Kishsaver doesn't use strobe 0 and 1
242         strobe_map[1] = 3;
243         strobe_map[2] = 4;
244         strobe_map[3] = 5;
245         strobe_map[4] = 6;
246         strobe_map[5] = 7;
247         strobe_map[6] = 8;
248         strobe_map[7] = 9;
249         strobe_map[8] = 15; // Test point strobe (3 test points, sense 1, 4, 5)
250 #elif defined(KISHSAVER_STROBE)
251         total_strobes = 9;
252
253         strobe_map[0] = 15; // Kishsaver doesn't use strobe 0 and 1
254         strobe_map[1] = 14;
255         strobe_map[2] = 13;
256         strobe_map[3] = 12;
257         strobe_map[4] = 11;
258         strobe_map[5] = 10;
259         strobe_map[6] = 9;
260         strobe_map[7] = 8;
261         strobe_map[8] = 2; // Test point strobe (3 test points, sense 1, 4, 5)
262 #elif defined(KEYPAD_50KEY)
263         total_strobes = 8;
264
265         strobe_map[0] = 14;
266         strobe_map[1] = 13;
267         strobe_map[2] = 12;
268         strobe_map[3] = 11;
269         strobe_map[4] = 10;
270         strobe_map[5] = 9;
271         strobe_map[6] = 8;
272         strobe_map[7] = 0;
273 #elif defined(TERMINAL_6110668_OLD_STROBE)
274         total_strobes = 16;
275
276         strobe_map[0] = 0;
277         strobe_map[1] = 1;
278         strobe_map[2] = 2;
279         strobe_map[3] = 3;
280         strobe_map[4] = 4;
281         strobe_map[5] = 5;
282         strobe_map[6] = 6;
283         strobe_map[7] = 7;
284         strobe_map[8] = 8;
285         strobe_map[9] = 9;
286         strobe_map[10] = 10;
287         strobe_map[11] = 11;
288         strobe_map[12] = 12;
289         strobe_map[13] = 13;
290         strobe_map[14] = 14;
291         strobe_map[15] = 15;
292 #elif defined(UNSAVER_OLD_STROBE)
293         total_strobes = 14;
294
295         strobe_map[0] = 0;
296         strobe_map[1] = 1;
297         strobe_map[2] = 2;
298         strobe_map[3] = 3;
299         strobe_map[4] = 4;
300         strobe_map[5] = 5;
301         strobe_map[6] = 6;
302         strobe_map[7] = 7;
303         strobe_map[8] = 8;
304         strobe_map[9] = 9;
305         strobe_map[10] = 10;
306         strobe_map[11] = 11;
307         strobe_map[12] = 12;
308         strobe_map[13] = 13;
309 #else
310         // Strobe detection
311         // TODO
312 #endif
313
314         // TODO all this code should probably be in Scan_resetKeyboard
315         for ( int i = 0; i < total_strobes; ++i)
316         {
317                 cur_keymap[i] = 0;
318         }
319
320         // Reset debounce table
321         for ( int i = 0; i < KEY_COUNT; ++i )
322         {
323                 keys_debounce[i] = 0;
324         }
325
326         // Warm things up a bit before we start collecting data, taking real samples.
327         for ( uint8_t i = 0; i < total_strobes; ++i )
328         {
329                 sampleColumn( strobe_map[i] );
330         }
331 }
332
333
334 // Main Detection Loop
335 // This is where the important stuff happens
336 inline uint8_t Scan_loop()
337 {
338         capsense_scan();
339
340         // Error case, should not occur in normal operation
341         if ( error )
342         {
343                 erro_msg("Problem detected... ");
344
345                 // Keymap scan debug
346                 for ( uint8_t i = 0; i < total_strobes; ++i )
347                 {
348                         printHex(cur_keymap[strobe_map[i]]);
349                         print(" ");
350                 }
351
352                 print(" : ");
353                 printHex(error);
354                 error = 0;
355                 print(" : ");
356                 printHex(error_data);
357                 error_data = 0;
358
359                 // Display sense table if warmup completede
360                 if ( boot_count >= WARMUP_LOOPS )
361                 {
362                         dumpSenseTable();
363                 }
364         }
365
366
367         // Return non-zero if macro and USB processing should be delayed
368         // Macro processing will always run if returning 0
369         // USB processing only happens once the USB send timer expires, if it has not, Scan_loop will be called
370         //  after the macro processing has been completed
371         return 0;
372 }
373
374
375 // Signal KeyIndex_Buffer that it has been properly read
376 // NOTE: Only really required for implementing "tricks" in converters for odd protocols
377 void Scan_finishedWithBuffer( uint8_t sentKeys )
378 {
379         // Convenient place to clear the KeyIndex_Buffer
380         KeyIndex_BufferUsed = 0;
381         return;
382 }
383
384
385 // Signal KeyIndex_Buffer that it has been properly read and sent out by the USB module
386 // NOTE: Only really required for implementing "tricks" in converters for odd protocols
387 void Scan_finishedWithUSBBuffer( uint8_t sentKeys )
388 {
389         return;
390 }
391
392
393 inline void capsense_scan()
394 {
395         // Accumulated average used for the next scan
396         uint32_t cur_full_avg = 0;
397         uint32_t cur_high_avg = 0;
398
399         // Reset average counters
400         low_avg = 0;
401         low_count = 0;
402
403         high_count = 0;
404
405         // Scan each of the mapped strobes in the matrix
406         for ( uint8_t strober = 0; strober < total_strobes; ++strober )
407         {
408                 uint8_t map_strobe = strobe_map[strober];
409
410                 uint8_t tries = 1;
411                 while ( tries++ && sampleColumn( map_strobe ) ) { tries &= 0x7; } // don't waste this one just because the last one was poop.
412
413                 // Only process sense data if warmup is finished
414                 if ( boot_count >= WARMUP_LOOPS )
415                 {
416                         column = testColumn( map_strobe );
417
418                         idle |= column; // if column has any pressed keys, then we are not idle.
419
420                         // TODO Is this needed anymore? Really only helps debug -HaaTa
421                         if( column != cur_keymap[map_strobe] && ( boot_count >= WARMUP_LOOPS ) )
422                         {
423                                 cur_keymap[map_strobe] = column;
424                                 keymap_change = 1;
425                         }
426
427                         idle |= keymap_change; // if any keys have changed inc. released, then we are not idle.
428                 }
429
430                 if ( error == 0x50 )
431                 {
432                         error_data |= (((uint16_t)map_strobe) << 12);
433                 }
434
435                 uint8_t strobe_line = map_strobe << MUXES_COUNT_XSHIFT;
436                 for ( int mux = 0; mux < MUXES_COUNT; ++mux )
437                 {
438                         // discard sketchy low bit, and meaningless high bits.
439                         uint8_t sample = samples[map_strobe][mux] >> 1;
440                         full_samples[strobe_line + mux] = sample;
441                         keys_averages_acc[strobe_line + mux] += sample;
442                 }
443
444                 // Accumulate 3 total averages (used for determining starting average during warmup)
445                 //     full_avg - Average of all sampled lines on the previous scan set
446                 // cur_full_avg - Average of all sampled lines for this scan set
447                 //     high_avg - Average of all sampled lines above full_avg on the previous scan set
448                 // cur_high_avg - Average of all sampled lines above full_avg
449                 //      low_avg - Average of all sampled lines below or equal to full_avg
450                 if ( boot_count < WARMUP_LOOPS )
451                 {
452                         for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux )
453                         {
454                                 uint8_t sample = samples[map_strobe][mux] >> 1;
455
456                                 // Sample is high, add it to high avg
457                                 if ( sample > full_avg )
458                                 {
459                                         high_count++;
460                                         cur_high_avg += sample;
461                                 }
462                                 // Sample is low, add it to low avg
463                                 else
464                                 {
465                                         low_count++;
466                                         low_avg += sample;
467                                 }
468
469                                 // If sample is higher than previous high_avg, then mark as "problem key"
470                                 keys_problem[strobe_line + mux] = sample > high_avg ? sample : 0;
471
472                                 // Prepare for next average
473                                 cur_full_avg += sample;
474                         }
475                 }
476         } // for strober
477
478         // Update total sense average (only during warm-up)
479         if ( boot_count < WARMUP_LOOPS )
480         {
481                 full_avg = cur_full_avg / (total_strobes * MUXES_COUNT);
482                 high_avg = cur_high_avg / high_count;
483                 low_avg /= low_count;
484
485                 // Update the base average value using the low_avg (best chance of not ignoring a keypress)
486                 for ( int i = 0; i < KEY_COUNT; ++i )
487                 {
488                         keys_averages[i] = low_avg;
489                         keys_averages_acc[i] = low_avg;
490                 }
491         }
492
493 #ifdef VERIFY_TEST_PAD
494         // verify test key is not down.
495         if ( ( cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK ) )
496         {
497                 error = 0x05;
498                 error_data = cur_keymap[TEST_KEY_STROBE] << 8;
499                 error_data += full_samples[TEST_KEY_STROBE * 8];
500         }
501 #endif
502
503         /** aggregate if booting, or if idle;
504          * else, if not booting, check for dirty USB.
505          * */
506
507         idle_count++;
508         idle_count &= IDLE_COUNT_MASK;
509
510         // Warm up voltage references
511         if ( boot_count < WARMUP_LOOPS )
512         {
513                 boot_count++;
514
515                 switch ( boot_count )
516                 {
517                 // First loop
518                 case 1:
519                         // Show msg at first iteration only
520                         info_msg("Warming up the voltage references");
521                         break;
522                 // Middle iterations
523                 case 300:
524                 case 600:
525                 case 900:
526                 case 1200:
527                         print(".");
528                         break;
529                 // Last loop
530                 case WARMUP_STOP:
531                         print( NL );
532                         info_msg("Warmup finished using ");
533                         printInt16( WARMUP_LOOPS );
534                         print(" iterations" NL );
535
536                         // Display the final calculated averages of all the sensed strobes
537                         info_msg("Full average (");
538                         printInt8( total_strobes * MUXES_COUNT );
539                         print("): ");
540                         printHex( full_avg );
541
542                         print("  High average (");
543                         printInt8( high_count );
544                         print("): ");
545                         printHex( high_avg );
546
547                         print("  Low average (");
548                         printInt8( low_count );
549                         print("): ");
550                         printHex( low_avg );
551                         print( NL );
552
553                         // Display problem keys, and the sense value at the time
554                         for ( uint8_t key = 0; key < KEY_COUNT; key++ )
555                         {
556                                 if ( keys_problem[key] )
557                                 {
558                                         warn_msg("Problem key detected: ");
559                                         printHex( key );
560                                         print(" (");
561                                         printHex( keys_problem[key] );
562                                         print(")" NL );
563                                 }
564                         }
565
566                         info_print("If problem keys were detected, and were being held down, they will be reset as soon as let go");
567                         break;
568                 }
569         }
570         else
571         {
572                 // Reset accumulators and idle flag/counter
573                 if ( keymap_change )
574                 {
575                         for ( uint8_t c = 0; c < KEY_COUNT; ++c ) { keys_averages_acc[c] = 0; }
576                         idle_count = 0;
577                         idle = 0;
578
579                         keymap_change = 0;
580                 }
581
582                 if ( !idle_count )
583                 {
584                         if( idle )
585                         {
586                                 // aggregate
587                                 for ( uint8_t i = 0; i < KEY_COUNT; ++i )
588                                 {
589                                         uint16_t acc = keys_averages_acc[i] >> IDLE_COUNT_SHIFT;
590                                         uint32_t av = keys_averages[i];
591
592                                         av = (av << KEYS_AVERAGES_MIX_SHIFT) - av + acc;
593                                         av >>= KEYS_AVERAGES_MIX_SHIFT;
594
595                                         keys_averages[i] = av;
596                                         keys_averages_acc[i] = 0;
597                                 }
598                         }
599
600                         // If the debugging sense table is non-zero, display
601                         if ( senseDebugCount > 0 )
602                         {
603                                 senseDebugCount--;
604                                 print( NL );
605                                 dumpSenseTable();
606                         }
607                 }
608
609         }
610 }
611
612
613 void setup_ADC()
614 {
615         // disable adc digital pins.
616         DIDR1 |= (1 << AIN0D) | (1<<AIN1D); // set disable on pins 1,0.
617         DDRF = 0x0;
618         PORTF = 0x0;
619         uint8_t mux = 0 & 0x1f; // 0 == first. // 0x1e = 1.1V ref.
620
621         // 0 = external aref 1,1 = 2.56V internal ref
622         uint8_t aref = ((1 << REFS1) | (1 << REFS0)) & ((1 << REFS1) | (1 << REFS0));
623         uint8_t adate = (1 << ADATE) & (1 << ADATE); // trigger enable
624         uint8_t trig = 0 & ((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2)); // 0 = free running
625         // ps2, ps1 := /64 ( 2^6 ) ps2 := /16 (2^4), ps1 := 4, ps0 :=2, PS1,PS0 := 8 (2^8)
626         uint8_t prescale = ( ((PRESCALE) << PRESCALE_SHIFT) & PRESCALE_MASK ); // 001 == 2^1 == 2
627         uint8_t hispeed = (1 << ADHSM);
628         uint8_t en_mux = (1 << ACME);
629
630         ADCSRA = (1 << ADEN) | prescale; // ADC enable
631
632         // select ref.
633         //ADMUX |= ((1 << REFS1) | (1 << REFS0)); // 2.56 V internal.
634         //ADMUX |= ((1 << REFS0) ); // Vcc with external cap.
635         //ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // 0,0 : aref.
636         ADMUX = aref | mux | ADLAR_BITS;
637
638         // set free-running
639         ADCSRA |= adate; // trigger enable
640         ADCSRB  = en_mux | hispeed | trig | (ADCSRB & ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2))); // trigger select free running
641
642         ADCSRA |= (1 << ADEN); // ADC enable
643         ADCSRA |= (1 << ADSC); // start conversions q
644 }
645
646
647 void recovery( uint8_t on )
648 {
649         DDRB  |=  (1 << RECOVERY_CONTROL);
650         PORTB &= ~(1 << RECOVERY_SINK);   // SINK always zero
651         DDRB  &= ~(1 << RECOVERY_SOURCE); // SOURCE high imp
652
653         if ( on )
654         {
655                 // set strobes to sink to gnd.
656                 DDRC |= C_MASK;
657                 DDRD |= D_MASK;
658                 DDRE |= E_MASK;
659
660                 PORTC &= ~C_MASK;
661                 PORTD &= ~D_MASK;
662                 PORTE &= ~E_MASK;
663
664                 DDRB  |= (1 << RECOVERY_SINK);   // SINK pull
665                 PORTB |= (1 << RECOVERY_CONTROL);
666                 PORTB |= (1 << RECOVERY_SOURCE); // SOURCE high
667                 DDRB  |= (1 << RECOVERY_SOURCE);
668         }
669         else
670         {
671                 PORTB &= ~(1 << RECOVERY_CONTROL);
672                 DDRB  &= ~(1 << RECOVERY_SOURCE);
673                 PORTB &= ~(1 << RECOVERY_SOURCE); // SOURCE low
674                 DDRB  &= ~(1 << RECOVERY_SINK);   // SINK high-imp
675         }
676 }
677
678
679 void hold_sample( uint8_t on )
680 {
681         if ( !on )
682         {
683                 PORTB |= (1 << SAMPLE_CONTROL);
684                 DDRB  |= (1 << SAMPLE_CONTROL);
685         }
686         else
687         {
688                 DDRB  |=  (1 << SAMPLE_CONTROL);
689                 PORTB &= ~(1 << SAMPLE_CONTROL);
690         }
691 }
692
693
694 void strobe_w( uint8_t strobe_num )
695 {
696         PORTC &= ~(C_MASK);
697         PORTD &= ~(D_MASK);
698         PORTE &= ~(E_MASK);
699
700         // Strobe table
701         // Not all strobes are used depending on which are detected
702         switch ( strobe_num )
703         {
704
705         case 0:  PORTD |= (1 << 0); break;
706         case 1:  PORTD |= (1 << 1); break;
707         case 2:  PORTD |= (1 << 2); break;
708         case 3:  PORTD |= (1 << 3); break;
709         case 4:  PORTD |= (1 << 4); break;
710         case 5:  PORTD |= (1 << 5); break;
711         case 6:  PORTD |= (1 << 6); break;
712         case 7:  PORTD |= (1 << 7); break;
713
714         case 8:  PORTE |= (1 << 0); break;
715         case 9:  PORTE |= (1 << 1); break;
716
717         case 10: PORTC |= (1 << 0); break;
718         case 11: PORTC |= (1 << 1); break;
719         case 12: PORTC |= (1 << 2); break;
720         case 13: PORTC |= (1 << 3); break;
721         case 14: PORTC |= (1 << 4); break;
722         case 15: PORTC |= (1 << 5); break;
723         case 16: PORTC |= (1 << 6); break;
724         case 17: PORTC |= (1 << 7); break;
725
726         default:
727                 break;
728         }
729 }
730
731
732 inline uint16_t getADC(void)
733 {
734         ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
735
736         //wait for last read to complete.
737         while ( !( ADCSRA & (1 << ADIF) ) );
738
739         return ADC; // return sample
740 }
741
742
743 int sampleColumn( uint8_t column )
744 {
745         // ensure all probe lines are driven low, and chill for recovery delay.
746         ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions
747
748         PORTC &= ~C_MASK;
749         PORTD &= ~D_MASK;
750         PORTE &= ~E_MASK;
751
752         PORTF = 0;
753         DDRF  = 0;
754
755         recovery( OFF );
756         strobe_w( column );
757
758         hold_sample( OFF );
759         SET_FULL_MUX( 0 );
760
761         // Allow strobes to settle
762         for ( uint8_t i = 0; i < STROBE_SETTLE; ++i ) { getADC(); }
763
764         hold_sample( ON );
765
766         uint8_t mux = 0;
767         SET_FULL_MUX( mux );
768         getADC(); // throw away; unknown mux.
769         do {
770                 SET_FULL_MUX( mux + 1 ); // our *next* sample will use this
771
772                 // retrieve current read.
773                 samples[column][mux] = getADC();
774                 mux++;
775
776         } while ( mux < 8 );
777
778         hold_sample( OFF );
779         recovery( ON );
780
781         // turn off adc.
782         ADCSRA &= ~(1 << ADEN);
783
784         // pull all columns' strobe-lines low.
785         DDRC |= C_MASK;
786         DDRD |= D_MASK;
787         DDRE |= E_MASK;
788
789         PORTC &= ~C_MASK;
790         PORTD &= ~D_MASK;
791         PORTE &= ~E_MASK;
792
793         return 0;
794 }
795
796
797 uint8_t testColumn( uint8_t strobe )
798 {
799         uint16_t db_delta = 0;
800         uint8_t  db_sample = 0;
801         uint16_t db_threshold = 0;
802
803         uint8_t column = 0;
804         uint8_t bit = 1;
805
806         for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux )
807         {
808                 uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + mux];
809
810                 uint8_t key = (strobe << MUXES_COUNT_XSHIFT) + mux;
811
812                 // Check if this is a bad key (e.g. test point, or non-existent key)
813                 if ( keys_problem[key] )
814                 {
815                         // If the sample value of the problem key goes below full_avg (overall initial average)
816                         //  re-enable the key
817                         if ( (db_sample = samples[strobe][mux] >> 1) < full_avg )
818                         {
819                                 info_msg("Re-enabling problem key: ");
820                                 printHex( key );
821                                 print( NL );
822
823                                 keys_problem[key] = 0;
824                         }
825                         // Otherwise, don't waste any more cycles processing the problem key
826                         else
827                         {
828                                 continue;
829                         }
830                 }
831
832                 // Keypress detected
833                 //  db_sample (uint8_t), discard meaningless high bit, and garbage low bit
834                 if ( (db_sample = samples[strobe][mux] >> 1) > (db_threshold = threshold) + (db_delta = delta) )
835                 {
836                         column |= bit;
837
838                         // Only register keypresses once the warmup is complete, or not enough debounce info
839                         if ( keys_debounce[key] <= DEBOUNCE_THRESHOLD )
840                         {
841                                 // Add to the Macro processing buffer if debounce criteria met
842                                 // Automatically handles converting to a USB code and sending off to the PC
843                                 if ( keys_debounce[key] == DEBOUNCE_THRESHOLD )
844                                 {
845 //#define KEYSCAN_DEBOUNCE_DEBUG
846 #ifdef KEYSCAN_DEBOUNCE_DEBUG
847                                         // Debug message
848                                         print("0x");
849                                         printHex_op( key, 2 );
850                                         print(" ");
851 #endif
852
853                                         // Only add the key to the buffer once
854                                         // NOTE: Buffer can easily handle multiple adds, just more efficient
855                                         //        and nicer debug messages :P
856                                         //Macro_bufferAdd( key );
857                                 }
858
859                                 keys_debounce[key]++;
860
861                                 // Long form key debugging
862                                 if ( enableKeyDebug )
863                                 {
864                                         // Debug message
865                                         // <key> [<strobe>:<mux>] : <sense val> : <delta + threshold> : <margin>
866                                         dbug_msg("0x");
867                                         printHex_op( key, 2 );
868                                         print(" [");
869                                         printInt8( strobe );
870                                         print(":");
871                                         printInt8( mux );
872                                         print("] : ");
873                                         printHex( db_sample ); // Sense
874                                         print(" : ");
875                                         printHex( db_threshold );
876                                         print("+");
877                                         printHex( db_delta );
878                                         print("=");
879                                         printHex( db_threshold + db_delta ); // Sense compare
880                                         print(" : ");
881                                         printHex( db_sample - ( db_threshold + db_delta ) ); // Margin
882                                         print( NL );
883                                 }
884                         }
885                 }
886                 // Clear debounce entry if no keypress detected
887                 else
888                 {
889                         // If the key was previously pressed, remove from the buffer
890                         for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ )
891                         {
892                                 // Key to release found
893                                 if ( KeyIndex_Buffer[c] == key )
894                                 {
895                                         // Shift keys from c position
896                                         for ( uint8_t k = c; k < KeyIndex_BufferUsed - 1; k++ )
897                                                 KeyIndex_Buffer[k] = KeyIndex_Buffer[k + 1];
898
899                                         // Decrement Buffer
900                                         KeyIndex_BufferUsed--;
901
902                                         break;
903                                 }
904                         }
905
906
907                         // Clear debounce entry
908                         keys_debounce[key] = 0;
909                 }
910
911                 bit <<= 1;
912         }
913         return column;
914 }
915
916
917 void dumpSenseTable()
918 {
919         // Display the full strobe/sense table
920         for ( uint8_t strober = 0; strober < total_strobes; ++strober )
921         {
922                 uint8_t strobe = strobe_map[strober];
923
924                 // For each mux, display sense:threshold:delta
925                 for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux )
926                 {
927                         uint8_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + mux];
928                         uint8_t sample = samples[strobe][mux] >> 1; // TODO Make larger samples array (2d)
929
930                         printHex_op( sample, 2 );
931                         print(":");
932                         printHex_op( threshold, 2 );
933                         print(":");
934                         printHex_op( delta, 2 );
935                         print(" ");
936                 }
937
938                 // New line for each strobe
939                 print( NL );
940         }
941 }
942
943
944 // ----- CLI Command Functions -----
945
946 // XXX Just an example command showing how to parse arguments (more complex than generally needed)
947 void cliFunc_echo( char* args )
948 {
949         char* curArgs;
950         char* arg1Ptr;
951         char* arg2Ptr = args;
952
953         // Parse args until a \0 is found
954         while ( 1 )
955         {
956                 print( NL ); // No \r\n by default after the command is entered
957
958                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
959                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
960
961                 // Stop processing args if no more are found
962                 if ( *arg1Ptr == '\0' )
963                         break;
964
965                 // Print out the arg
966                 dPrint( arg1Ptr );
967         }
968 }
969
970 void cliFunc_keyDebug( char* args )
971 {
972         // Args ignored, just toggling
973         enableKeyDebug = enableKeyDebug ? 0 : 1;
974 }
975
976 void cliFunc_senseDebug( char* args )
977 {
978         // Parse code from argument
979         //  NOTE: Only first argument is used
980         char* arg1Ptr;
981         char* arg2Ptr;
982         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
983
984         // Default to a single print
985         senseDebugCount = 1;
986
987         // If there was an argument, use that instead
988         if ( *arg1Ptr != '\0' )
989         {
990                 senseDebugCount = decToInt( arg1Ptr );
991         }
992 }
993