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