-/* Keyboard example with debug channel, for Teensy USB Development Board\r
- * http://www.pjrc.com/teensy/usb_keyboard.html\r
- * Copyright (c) 2008 PJRC.COM, LLC\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy\r
- * of this software and associated documentation files (the "Software"), to deal\r
- * in the Software without restriction, including without limitation the rights\r
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
- * copies of the Software, and to permit persons to whom the Software is\r
- * furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in\r
- * all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
- * THE SOFTWARE.\r
- */\r
-\r
-#include <avr/io.h>\r
-#include <avr/pgmspace.h>\r
-#include <avr/interrupt.h>\r
-#include <util/delay.h>\r
-#include "usb_keyboard_debug.h"\r
-#include "print.h"\r
-\r
-#define LED_CONFIG (DDRD |= (1<<6))\r
-#define LED_ON (PORTD &= ~(1<<6))\r
-#define LED_OFF (PORTD |= (1<<6))\r
-#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))\r
-\r
-#define THRESHOLD 0x0a\r
-#define BUMP_THRESHOLD 0x50\r
-//((THRESHOLD) * 3)\r
-#define BUMP_REST_US 1200\r
-\r
-#define HYST 1\r
-#define HYST_T 0x10\r
-\r
-#define TEST_KEY_STROBE (0x05)\r
-#define TEST_KEY_MASK (1 << 0)\r
-\r
-#define ADHSM 7\r
-\r
-/** Whether to use all of D and C, vs using E0, E1 instead of D6, D7,\r
- * or alternately all of D, and E0,E1 and C0,..5 */\r
-//#define ALL_D_C\r
-//#define SHORT_D\r
-#define SHORT_C\r
-\r
-// rough offset voltage: one diode drop, about 50mV = 0x3ff * 50/3560 = 20\r
-//#define OFFSET_VOLTAGE 0x14\r
-#define OFFSET_VOLTAGE 0x28\r
-\r
-volatile uint8_t idle_count=1;\r
-\r
-uint8_t blink=0;\r
-\r
-volatile uint16_t full_av = 0;\r
-\r
-#define RIGHT_JUSTIFY 0\r
-#define LEFT_JUSTIFY (0xff)\r
-\r
-// set left or right justification here:\r
-#define JUSTIFY_ADC RIGHT_JUSTIFY\r
-\r
-#define ADLAR_MASK (1 << ADLAR)\r
-#ifdef JUSTIFY_ADC\r
-#define ADLAR_BITS ((ADLAR_MASK) & (JUSTIFY_ADC))\r
-#else // defaults to right justification.\r
-#define ADLAR_BITS 0\r
-#endif\r
-\r
-\r
-// full muxmask\r
-#define FULL_MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2) | (1 << MUX3) | (1 << MUX4))\r
-\r
-// F0-f7 pins only muxmask.\r
-#define MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2))\r
-\r
-#define SET_MUX(X) ((ADMUX) = (((ADMUX) & ~(MUX_MASK)) | ((X) & (MUX_MASK))))\r
-#define SET_FULL_MUX(X) ((ADMUX) = (((ADMUX) & ~(FULL_MUX_MASK)) | ((X) & (FULL_MUX_MASK))))\r
-\r
-#define MUX_1_1 0x1e\r
-#define MUX_GND 0x1f\r
-\r
-\r
- // set ADC clock prescale\r
-#define PRESCALE_MASK ((1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2))\r
-#define PRESCALE_SHIFT (ADPS0)\r
-#define PRESCALE 3\r
-\r
-\r
-/**/ uint8_t ze_strober = 0;\r
-\r
-#ifdef EXTENDED_STROBE\r
-\r
-#define STROBE_LINES 18\r
-\r
-#else\r
-\r
-#define STROBE_LINES 16\r
-\r
-#endif\r
-\r
-#define STROBE_LINES_XSHIFT 4\r
-#define STROBE_LINES_MASK 0x0f\r
-#define MUXES_COUNT 8\r
-#define MUXES_COUNT_XSHIFT 3\r
-#define MUXES_MASK 0x7\r
-\r
-#define WARMUP_LOOPS ( 1024 )\r
-\r
-#define RECOVERY_US 6\r
-\r
-#define SAMPLES 10\r
-int16_t samples [SAMPLES];\r
-\r
-//int16_t gsamples [SAMPLES];\r
-\r
-#define SAMPLE_OFFSET ((SAMPLES) - MUXES_COUNT)\r
-//#define SAMPLE_OFFSET 9\r
-#define STROBE_OFFSET 0\r
-\r
-/**/ int16_t adc_mux_averages[MUXES_COUNT];\r
-/**/ int16_t adc_strobe_averages[STROBE_LINES];\r
-\r
-\r
-/**/ uint8_t cur_keymap[STROBE_LINES];\r
-// /**/ int8_t last_keymap[STROBE_LINES];\r
-/**/ uint8_t usb_keymap[STROBE_LINES];\r
-uint8_t dirty;\r
-uint8_t unstable;\r
-uint8_t usb_dirty;\r
-\r
-int16_t threshold = THRESHOLD;\r
-uint16_t tests = 0;\r
-\r
-uint8_t col_a=0;\r
-uint8_t col_b=0;\r
-uint8_t col_c=0;\r
-\r
-uint8_t column=0;\r
-\r
-#define KEY_COUNT ((STROBE_LINES) * (MUXES_COUNT))\r
-\r
-int16_t keys_averages_acc[KEY_COUNT];\r
-uint16_t keys_averages[KEY_COUNT];\r
-\r
-uint8_t full_samples[KEY_COUNT];\r
-\r
-/* viable starting biases for near 0.830V offset. and adc PRESCALE 3\r
-0017 0016 001B 001A 0016 0016 000F 000E 001B 001E 001E 0018 0017 0015 000E 001D\r
-001B 001A 0016 0016 000F 000E 001C 001B 001E 0018 0017 0015 000E 001D 0024 001F\r
-0016 0016 000F 000E 001C 001B 001E 001E 0017 0015 000E 001D 0024 001F 0020 001F\r
-000F 000E 001C 001B 001E 001E 0018 0017 000E 001D 0024 001F 0020 001F 0020 0017\r
-001C 001B 001E 001E 0018 0017 0015 000E 0024 001F 0020 001F 0020 0017 0010 001D\r
-001E 001E 0018 0017 0015 000E 001D 0024 0020 001F 0020 0017 0010 001D 0024 0021\r
-0018 0017 0015 000E 001D 0024 001F 0020 0020 0017 0010 001D 0024 0021 0021 0021\r
-0015 000E 001D 0024 001F 0020 001F 0020 0010 001D 0024 0021 0021 0021 0021 0018\r
-*/\r
-\r
-/*** starting bias relative to fixed offset estimate of 820mV (0x50)\r
- * 77 69 65 5B 50 4E 4C 45 66 53 4D 49 45 3F 3E 35\r
- * 68 54 4F 49 45 40 3F 34 74 66 5F 56 4E 4D 4C 3F\r
- * 6D 5D 53 4C 49 46 45 38 6D 5A 53 4E 49 48 45 3E\r
- * 6F 5D 56 4E 4B 48 48 3A 6D 5C 54 4E 48 48 45 37\r
- * 75 68 5F 57 4F 4D 4C 3F 60 4E 48 41 3C 3C 39 2F\r
- * 65 53 4E 49 41 3F 3E 34 65 54 4E 49 43 3F 3E 34\r
- * 60 51 4A 45 3F 3E 3C 30 57 4C 45 3E 3B 37 37 2E\r
- * 64 4E 48 44 3C 3B 39 2F 5D 4F 48 45 3E 3C 3B 30\r
- */\r
-\r
-/*volatile*/ uint16_t count = 0;\r
-\r
-\r
-\r
-/*volatile*/ uint8_t error = 0;\r
-uint16_t error_data = 0;\r
-\r
-void dump(void);\r
-void dumpkeys(void);\r
-\r
-static const uint8_t PROGMEM matrix122F_to_set3[] = {\r
-0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x84, // (), npenter, np3, (), np+, np9, np*, np-\r
-0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // np0, np., np2, np5, np6, np8, numlck, np/\r
-0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, //\r
-0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\r
-0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\r
-0x00, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 0x50 vanishes - is test key.\r
-0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, // 0x48 vanishes - else roll back.\r
-0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\r
-0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,\r
-0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,\r
-0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,\r
-0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\r
-0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,\r
-0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\r
-0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,\r
-0x01, 0x83, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 0x02 is replaced with 0x83.\r
-};\r
-\r
-#define LX2FX\r
-\r
-static const uint8_t PROGMEM page3_2_USB[133] = {\r
-0x0, // 00 00 // no key.\r
-\r
-#ifndef LX2FX\r
-\r
-0xe3, // 01 Enl Help -> windows. (e3)\r
-0x0, // 02 // no key.\r
-0x80, // 03 A4 ExSel SetUp print, -> paste 7d -> vol up 80\r
-0x46, // 04 A3 CrSel Properties -> copy 7c -> mute 7f-> prt-scrn\r
-0x29, // 05 9A Attn SysRq // good place fer escape. (29)\r
-0x47, // 06 9C Clear -> kp / 54 -> scroll-lock (47)\r
-0x3a, // 07 3A F1\r
-0x68, // 08 68 F13\r
-0x65, // 09 Ctrl // record/pause // -> kb application (65)\r
-0x74, // 0A Copy Test // play/test -> execute 74 -> kp + 57\r
-0x75, // 0B // no key. help (75) -> kp - 56\r
-0x48, // 0C Pause ErInp erase input. -> cut 7b -> kp * 55 -> pause 48\r
-\r
-#else\r
-\r
-/*\r
-0x42, // 01 L9\r
-0x0, // 02 // no key.\r
-0x3e, // 03 L5\r
-0x3c, // 04 L3\r
-0x3a, // 05 L1\r
-0x3b, // 06 L2\r
-0x3a, // 07 3A F1\r
-0x68, // 08 68 F13\r
-0x43, // 09 L10\r
-0x41, // 0A L8\r
-0x3f, // 0B L6\r
-0x3d, // 0C L4\r
-*/\r
-0x61, // 01 L9 -> num 9 0x61\r
-0x0, // 02 // no key.\r
-0x5d, // 03 L5 -> num 5 0x5d\r
-0x5b, // 04 L3 -> num 3 0x5b\r
-0x59, // 05 L1 -> num 1 0x59\r
-0x5a, // 06 L2 -> num 2 0x5a\r
-0x3a, // 07 3A F1\r
-0x68, // 08 68 F13\r
-0x62, // 09 L10 -> num 0 0x62\r
-0x60, // 0A L8 -> num 8 0x60\r
-0x5e, // 0B L6 -> num 6 0x5e\r
-0x5c, // 0C L4 -> num 4 0x5c\r
-#endif\r
-\r
-\r
-0x2b, // 0D 2B Tab\r
-0x29, // 0E 35 ~ ` -> escape 29\r
-0x3b, // 0F 3B F2\r
-0x69, // 10 69 F14\r
-0xe0, // 11 E0 Ctrl L\r
-0xe1, // 12 E1 Shift L\r
-0xe1, // 13 64 left of z. -> l shift e1\r
-0x39, // 14 39 Caps Lock\r
-0x14, // 15 14 Q\r
-0x1e, // 16 1E ! 1\r
-0x3c, // 17 3C F3\r
-0x6a, // 18 6A F15\r
-0xe2, // 19 E2 Alt L\r
-0x1d, // 1A 1D Z\r
-0x16, // 1B 16 S\r
-0x04, // 1C 04 A\r
-0x1a, // 1D 1A W\r
-0x1f, // 1E 1F @ 2\r
-0x3d, // 1F 3D F4\r
-0x6b, // 20 6B F16\r
-0x06, // 21 06 C\r
-0x1b, // 22 1B X\r
-0x07, // 23 07 D\r
-0x08, // 24 08 E\r
-0x21, // 25 21 $ 4\r
-0x20, // 26 20 # 3\r
-0x3e, // 27 3E F5\r
-0x6c, // 28 6C F17\r
-0x2c, // 29 2C Space\r
-0x19, // 2A 19 V\r
-0x09, // 2B 09 F\r
-0x17, // 2C 17 T\r
-0x15, // 2D 15 R\r
-0x22, // 2E 22 % 5\r
-0x3f, // 2F 3F F6\r
-0x6d, // 30 6D F18\r
-0x11, // 31 11 N\r
-0x05, // 32 05 B\r
-0x0b, // 33 0B H\r
-0x0a, // 34 0A G\r
-0x1c, // 35 1C Y\r
-0x23, // 36 23 ^ 6\r
-0x40, // 37 40 F7\r
-0x6e, // 38 6E F19\r
-0xe6, // 39 E6 Alt R\r
-0x10, // 3A 10 M\r
-0x0d, // 3B 0D J\r
-0x18, // 3C 18 U\r
-0x24, // 3D 24 & 7\r
-0x25, // 3E 25 * 8\r
-0x41, // 3F 41 F8\r
-0x6f, // 40 6F F20\r
-0x36, // 41 36 < ,\r
-0x0e, // 42 0E K\r
-0x0c, // 43 0C I\r
-0x12, // 44 12 O\r
-0x27, // 45 27 ) 0\r
-0x26, // 46 26 ( 9\r
-0x42, // 47 42 F9\r
-0x70, // 48 70 F21\r
-0x37, // 49 37 > .\r
-0x38, // 4A 38 ? /\r
-0x0f, // 4B 0F L\r
-0x33, // 4C 33 : ;\r
-0x13, // 4D 13 P\r
-0x2d, // 4E 2D _ -\r
-0x43, // 4F 43 F10\r
-0x71, // 50 71 F22\r
-0xe5, // 51 87 likely a shift - e.g. kp shift -> e5\r
-0x34, // 52 34 " '\r
-0x31, // 53 (INT 2) -> keypad enter. 58 -> |/\ (31)\r
-0x2f, // 54 2F { [\r
-0x2e, // 55 2E + =\r
-0x44, // 56 44 F11\r
-0x72, // 57 72 F23 -> vol up.\r
-0xe4, // 58 E4 Ctrl R\r
-0xe5, // 59 E5 Shift R\r
-0x28, // 5A 28 Enter\r
-0x30, // 5B 30 } ]\r
-0x31, // 5C 31 | '\'\r
-0x35, // 5D -> kp = 67 -> ~` 35\r
-0x45, // 5E 45 F12\r
-0x73, // 5F 73 F24 -> vol down.\r
-0x51, // 60 51 Down CP\r
-0x50, // 61 50 Left CP\r
-0x51, //0x0,// 62 Rule // centre cp. //62 48 Pause/Bk\r
-0x52, // 63 52 Up CP\r
-0x4c, // 64 4C Del CP\r
-0x4d, // 65 4D End CP\r
-0x2a, // 66 2A Back Space\r
-0x49, // 67 49 Ins CP\r
-0x48, // 68 // under kp0 => kp 0 (62) 48 -> pause (48)\r
-0x59, // 69 59 1 End KP\r
-0x4f, // 6A 4F Right CP\r
-0x5c, // 6B 5C 4 Left KP\r
-0x5f, // 6C 5F 7 Home KP\r
-0x4e, // 6D 4E PgDn CP\r
-0x4a, // 6E 4A Home CP\r
-0x4b, // 6F 4B PgUp CP\r
-0x62, // 70 62 0 Ins KP -> pause (+48) -> kp-0 (62)\r
-0x63, // 71 63 . Del KP\r
-0x5a, // 72 5A 2 Down KP\r
-0x5d, // 73 97 5 KP\r
-0x5e, // 74 5E 6 Right KP\r
-0x60, // 75 60 8 Up KP\r
-0x53, // 76 53 Num Lock\r
-0x54, // 77 54 / KP\r
-0x47, // 78 Undo // under enter -> scroll-lock 47\r
-0x58, // 79 58 Enter KP -> enter kp\r
-0x5b, // 7A 5B 3 PgDn KP\r
-0x46, // 7B (INT 5) // under + -> print screen (46\r
-0x57, // 7C 57 + KP\r
-0x61, // 7D 61 9 PgUp KP\r
-0x55, // 7E 55 * KP\r
-0x0, // 7F no such key?\r
-0x0, // 80 no such key\r
-0x0, // 81 Paste?\r
-0x0, // 82 Find?\r
-#ifndef LX2FX\r
-0x81, // 83 Print Ident -> undo 7a -> vol down 81\r
-#else\r
-//0x40, // 83 L7 (f1) 3a\r
-0x5f, // 83 L7 (f1) 3a -> num 7 0x5f\r
-#endif\r
-0x56 // 84 56 - KP\r
-};\r
-\r
-void\r
-_delay_loop(uint8_t __count)\r
-{\r
- __asm__ volatile (\r
- "1: dec %0" "\n\t"\r
- "brne 1b"\r
- : "=r" (__count)\r
- : "0" (__count)\r
- );\r
-}\r
-\r
-\r
-void setup_ADC (void) {\r
- // disable adc digital pins.\r
- DIDR1 |= (1 << AIN0D) | (1<<AIN1D); // set disable on pins 1,0.\r
- //DIDR0 = 0xff; // disable all. (port F, usually). - testing w/o disable.\r
- DDRF = 0x0;\r
- PORTF = 0x0;\r
- uint8_t mux = 0 & 0x1f; // 0 == first. // 0x1e = 1.1V ref.\r
-\r
- // 0 = external aref 1,1 = 2.56V internal ref\r
- uint8_t aref = ((1 << REFS1) | (1 << REFS0)) & ((1 << REFS1) | (1 << REFS0));\r
-// uint8_t adlar = 0xff & (1 << ADLAR); // 1 := left justify bits, 0 := right\r
- uint8_t adate = (1 << ADATE) & (1 << ADATE); // trigger enable\r
- uint8_t trig = 0 & ((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2)); // 0 = free running\r
- // ps2, ps1 := /64 ( 2^6 ) ps2 := /16 (2^4), ps1 := 4, ps0 :=2, PS1,PS0 := 8 (2^8)\r
- uint8_t prescale = ( ((PRESCALE) << PRESCALE_SHIFT) & PRESCALE_MASK ); // 001 == 2^1 == 2\r
- uint8_t hispeed = (1 << ADHSM);\r
- uint8_t en_mux = (1 << ACME);\r
-\r
- //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS1) | (1 << ADPS2)); // 2, 1 := /64 ( 2^6 )\r
- //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS0) | (1 << ADPS2)); // 2, 0 := /32 ( 2^5 )\r
- //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS2)); // 2 := /16 ( 2^4 )\r
-\r
- ADCSRA = (1 << ADEN) | prescale; // ADC enable\r
-\r
- // select ref.\r
- //ADMUX |= ((1 << REFS1) | (1 << REFS0)); // 2.56 V internal.\r
- //ADMUX |= ((1 << REFS0) ); // Vcc with external cap.\r
- //ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // 0,0 : aref.\r
- ADMUX = aref | mux | ADLAR_BITS;\r
-\r
- // enable MUX\r
- // ADCSRB |= (1 << ACME); // enable\r
- // ADCSRB &= ~(1 << ADEN); // ?\r
-\r
- // select first mux.\r
- //ADMUX = (ADMUX & ~MUXES); // start at 000 = ADC0\r
-\r
- // clear adlar to left justify data\r
- //ADMUX = ~();\r
-\r
- // set adlar to right justify data\r
- //ADMUX |= (1 << ADLAR);\r
-\r
-\r
- // set free-running\r
- ADCSRA |= adate; // trigger enable\r
- ADCSRB = en_mux | hispeed | trig | (ADCSRB & ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2))); // trigger select free running\r
-\r
-// ADCSRA |= (1 << ADATE); // tiggger enable\r
-\r
- ADCSRA |= (1 << ADEN); // ADC enable\r
- ADCSRA |= (1 << ADSC); // start conversions q\r
-\r
-}\r
-\r
-\r
-#define RECOVERY_CONTROL 1\r
-\r
-#define RECOVERY_SOURCE 0\r
-#define RECOVERY_SINK 2\r
-#define RECOVERY_MASK 0x03\r
-\r
-void recovery(uint8_t on) {\r
- DDRB |= (1 << RECOVERY_CONTROL);\r
-\r
- PORTB &= ~(1 << RECOVERY_SINK); // SINK always zero\r
- DDRB &= ~(1 << RECOVERY_SOURCE); // SOURCE high imp\r
-\r
- if(on) {\r
- DDRB |= (1 << RECOVERY_SINK); // SINK pull\r
-\r
-\r
- PORTB |= (1 << RECOVERY_CONTROL);\r
-\r
- PORTB |= (1 << RECOVERY_SOURCE); // SOURCE high\r
- DDRB |= (1 << RECOVERY_SOURCE);\r
- } else {\r
- _delay_loop(10);\r
- PORTB &= ~(1 << RECOVERY_CONTROL);\r
-\r
- DDRB &= ~(1 << RECOVERY_SOURCE);\r
- PORTB &= ~(1 << RECOVERY_SOURCE); // SOURCE low\r
- DDRB &= ~(1 << RECOVERY_SINK); // SINK high-imp\r
-\r
- //DDRB &= ~(1 << RECOVERY_SINK);\r
- }\r
-}\r
-\r
-void strobe_w(uint8_t strobe_num) {\r
-\r
-#ifdef ALL_D_C\r
-\r
-#define D_MASK (0xff)\r
-#define D_SHIFT 0\r
-\r
-#define E_MASK (0x00)\r
-#define E_SHIFT 0\r
-\r
-#define C_MASK (0xff)\r
-#define C_SHIFT 8\r
-\r
-#else\r
-#if defined(SHORT_D)\r
-\r
-#define D_MASK (0x3f)\r
-#define D_SHIFT 0\r
-\r
-#define E_MASK (0x03)\r
-#define E_SHIFT 6\r
-\r
-#define C_MASK (0xff)\r
-#define C_SHIFT 8\r
-\r
-#else\r
-#if defined(SHORT_C)\r
-\r
-#define D_MASK (0xff)\r
-#define D_SHIFT 0\r
-\r
-#define E_MASK (0x03)\r
-#define E_SHIFT 6\r
-\r
-#define C_MASK (0xff)\r
-#define C_SHIFT 8\r
-#endif\r
-#endif\r
-#endif\r
-\r
-\r
-\r
-#define STROBE_CASE(SC_CASE, SC_REG_A) case (SC_CASE): PORT##SC_REG_A = \\r
- (( (PORT##SC_REG_A) & ~(1 << (SC_CASE - SC_REG_A##_SHIFT)) ) | (1 << (SC_CASE - SC_REG_A##_SHIFT)))\r
-\r
- PORTC &= ~(D_MASK);\r
- PORTD &= ~(D_MASK);\r
- PORTE &= ~(E_MASK);\r
-\r
-#ifdef SHORT_C\r
- strobe_num = 15 - strobe_num;\r
-#endif\r
-\r
- switch(strobe_num) {\r
-\r
- case 0: PORTD |= (1 << 0); break;\r
- case 1: PORTD |= (1 << 1); break;\r
- case 2: PORTD |= (1 << 2); break;\r
- case 3: PORTD |= (1 << 3); break;\r
- case 4: PORTD |= (1 << 4); break;\r
- case 5: PORTD |= (1 << 5); break;\r
-\r
-#ifdef ALL_D\r
-\r
- case 6: PORTD |= (1 << 6); break;\r
- case 7: PORTD |= (1 << 7); break;\r
-\r
- case 8: PORTC |= (1 << 0); break;\r
- case 9: PORTC |= (1 << 1); break;\r
- case 10: PORTC |= (1 << 2); break;\r
- case 11: PORTC |= (1 << 3); break;\r
- case 12: PORTC |= (1 << 4); break;\r
- case 13: PORTC |= (1 << 5); break;\r
- case 14: PORTC |= (1 << 6); break;\r
- case 15: PORTC |= (1 << 7); break;\r
-\r
- case 16: PORTE |= (1 << 0); break;\r
- case 17: PORTE |= (1 << 1); break;\r
-\r
-#else\r
-#ifdef SHORT_D\r
-\r
- case 6: PORTE |= (1 << 0); break;\r
- case 7: PORTE |= (1 << 1); break;\r
-\r
- case 8: PORTC |= (1 << 0); break;\r
- case 9: PORTC |= (1 << 1); break;\r
- case 10: PORTC |= (1 << 2); break;\r
- case 11: PORTC |= (1 << 3); break;\r
- case 12: PORTC |= (1 << 4); break;\r
- case 13: PORTC |= (1 << 5); break;\r
- case 14: PORTC |= (1 << 6); break;\r
- case 15: PORTC |= (1 << 7); break;\r
-\r
-#else\r
-#ifdef SHORT_C\r
-\r
- case 6: PORTD |= (1 << 6); break;\r
- case 7: PORTD |= (1 << 7); break;\r
-\r
- case 8: PORTE |= (1 << 0); break;\r
- case 9: PORTE |= (1 << 1); break;\r
-\r
- case 10: PORTC |= (1 << 0); break;\r
- case 11: PORTC |= (1 << 1); break;\r
- case 12: PORTC |= (1 << 2); break;\r
- case 13: PORTC |= (1 << 3); break;\r
- case 14: PORTC |= (1 << 4); break;\r
- case 15: PORTC |= (1 << 5); break;\r
-\r
- case 16: PORTC |= (1 << 6); break;\r
- case 17: PORTC |= (1 << 7); break;\r
-\r
-#endif\r
-#endif\r
-#endif\r
-\r
- default:\r
- break;\r
- }\r
-\r
-}\r
-\r
-\r
-int sampleColumn_i(uint8_t column, uint8_t muxes, int16_t * buffer) {\r
-\r
- // ensure all probe lines are driven low, and chill for recovery delay.\r
- PORTC &= ~C_MASK;\r
- PORTD &= ~D_MASK;\r
- PORTE &= ~E_MASK;\r
- recovery(1);\r
- _delay_us(RECOVERY_US);\r
- recovery(0);\r
-\r
- uint8_t index = 0;\r
-\r
- for (uint8_t i=0; i<8; ++i) {\r
- if(muxes & (1 << i)) {\r
- buffer[index++] = i;\r
- }\r
- }\r
-\r
- SET_FULL_MUX(MUX_1_1); // crap sample will use this.\r
- ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
-\r
- uint16_t sample;\r
-\r
- while (! (ADCSRA & (1 << ADIF))); // wait until ready.\r
- sample = ADC; // 1st sample, icky.\r
-\r
- strobe_w(column);\r
- //recovery(0);\r
-\r
- /**\r
- * we are running in continuous mode, so we must setup the next\r
- * read _before_ the current read completes.\r
- *\r
- * setup 0,\r
- * read garbage,\r
- * do not store\r
- *\r
- * setup 1,\r
- * read 0,\r
- * store 0,\r
- *\r
- * ...\r
- *\r
- * setup junk,\r
- * read n\r
- * store n\r
- *\r
- * */\r
-\r
-\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- //wait for last read to complete.\r
- while (! (ADCSRA & (1 << ADIF)));\r
- sample = ADC; // throw away strobe'd value.\r
-\r
-#if 0\r
- for (uint8_t i=0; i <= index; ++i) {\r
-\r
- // setup i'th read.\r
- SET_FULL_MUX(buffer[i]); // _next_ read will use this.\r
- // wait for i-1'th read to complete:\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- while (! (ADCSRA & (1 << ADIF)));\r
-\r
- // retrieve last (i-1'th) read.\r
- if (i) {\r
- buffer[i-1] = ADC - OFFSET_VOLTAGE;\r
- } /*else {\r
- buffer[0] = ADC - OFFSET_VOLTAGE;\r
- }*/\r
-\r
- //index++;\r
- }\r
-#else\r
- for (uint8_t i=0; i < index; ++i) {\r
-\r
- // setup i'th read.\r
- SET_FULL_MUX(buffer[i]); // _next_ read will use this.\r
-\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- while (! (ADCSRA & (1 << ADIF)));\r
- sample = ADC; // throw away warmup value.\r
-\r
-\r
-\r
- /*\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- while (! (ADCSRA & (1 << ADIF)));\r
- sample = ADC; // throw away warmup value.\r
-*/\r
-\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- while (! (ADCSRA & (1 << ADIF)));\r
-\r
- // retrieve current read.\r
- buffer[i] = ADC - OFFSET_VOLTAGE;\r
-\r
-\r
- }\r
-#endif\r
-\r
-\r
- // turn off adc.\r
- ADCSRA &= ~(1 << ADEN);\r
-\r
- // pull all columns' probe-lines low.\r
- PORTC &= ~C_MASK;\r
- PORTD &= ~D_MASK;\r
- PORTE &= ~E_MASK;\r
-\r
- // test for humps. :/\r
- /*uint16_t delta = full_av;\r
- if(buffer[0] > BUMP_THRESHOLD + delta) {\r
- // ze horror.\r
- return 1;\r
- } else {\r
- return 0; //all good.\r
- }*/\r
- return 0;\r
-\r
-}\r
-\r
-int sampleColumn_k(uint8_t column, int16_t * buffer) {\r
- // ensure all probe lines are driven low, and chill for recovery delay.\r
- uint16_t sample;\r
-\r
- ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
-\r
- // sync up with adc clock:\r
- while (! (ADCSRA & (1 << ADIF))); // wait until ready.\r
- sample = ADC; // throw it away.\r
-\r
- for(uint8_t mux=0; mux < 8; ++mux) {\r
-\r
- PORTC &= ~C_MASK;\r
- PORTD &= ~D_MASK;\r
- PORTE &= ~E_MASK;\r
-\r
- SET_FULL_MUX(mux); // our sample will use this\r
-\r
- for(uint8_t i=0; i < 2; ++i) {\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- //wait for last read to complete.\r
- while (! (ADCSRA & (1 << ADIF)));\r
- sample = ADC; // throw away strobe'd value.\r
- }\r
-\r
- recovery(0);\r
- strobe_w(column);\r
-\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- //wait for last read to complete.\r
- while (! (ADCSRA & (1 << ADIF)));\r
- sample = ADC; // throw away strobe'd value.\r
-\r
- ADCSRA |= (1 << ADIF); // clear int flag by writing 1.\r
- while (! (ADCSRA & (1 << ADIF)));\r
-\r
- // retrieve current read.\r
- buffer[mux] = ADC - OFFSET_VOLTAGE;\r
- recovery(1);\r
-\r
- }\r
-\r
- // turn off adc.\r
- ADCSRA &= ~(1 << ADEN);\r
-\r
- // pull all columns' probe-lines low.\r
- PORTC &= ~C_MASK;\r
- PORTD &= ~D_MASK;\r
- PORTE &= ~E_MASK;\r
-// recovery(1);\r
-\r
-\r
- return 0;\r
-}\r
-\r
-int sampleColumn(uint8_t column) {\r
- int rval = 0;\r
-\r
- /*\r
- sampleColumn_i(column, 0x0f, samples+SAMPLE_OFFSET);\r
- sampleColumn_i(column, 0xf0, samples+SAMPLE_OFFSET + 4 );\r
-*/\r
-\r
- rval = sampleColumn_k(column, samples+SAMPLE_OFFSET);\r
-\r
- for(uint8_t i=0; i<8; ++i) {\r
- if(samples[SAMPLE_OFFSET + i] - adc_mux_averages[i] > BUMP_THRESHOLD) {\r
- // was a hump\r
-\r
- _delay_us(BUMP_REST_US);\r
- rval++;\r
- error = 0x50;\r
- error_data = samples[SAMPLE_OFFSET +i]; // | ((uint16_t)i << 8);\r
- return rval;\r
- }\r
- }\r
-\r
- return rval;\r
-}\r
-\r
-\r
-\r
-uint8_t testColumn(uint8_t strobe) {\r
- uint8_t column = 0;\r
- uint8_t bit = 1;\r
- for (uint8_t i=0; i < MUXES_COUNT; ++i) {\r
- uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + i];\r
- if ((int16_t)samples[SAMPLE_OFFSET + i] > threshold + delta) {\r
- column |= bit;\r
- }\r
- bit <<= 1;\r
- }\r
- return column;\r
-}\r
-\r
-int main(void) {\r
- // set for 16 MHz clock\r
- CPU_PRESCALE(0);\r
-\r
- // Initialize the USB, and then wait for the host to set configuration.\r
- // If the Teensy is powered without a PC connected to the USB port,\r
- // this will wait forever.\r
- usb_init();\r
- while (!usb_configured()) /* wait */ ;\r
-\r
- // Wait an extra second for the PC's operating system to load drivers\r
- // and do whatever it does to actually be ready for input\r
- _delay_ms(1000);\r
-\r
- LED_CONFIG;\r
-\r
- setup_ADC();\r
-\r
- // Configure timer 0 to generate a timer overflow interrupt every\r
- // 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock\r
- // This demonstrates how to use interrupts to implement a simple\r
- // inactivity timeout.\r
- //TCCR0A = 0x00;\r
- //TCCR0B = 0x05;\r
- //TIMSK0 = (1<<TOIE0);\r
-\r
- DDRC = C_MASK;\r
- PORTC = 0;\r
- DDRD = D_MASK;\r
- PORTD = 0;\r
- DDRE = E_MASK;\r
- PORTE = 0 ;\r
-\r
- //DDRC |= (1 << 6);\r
- //PORTC &= ~(1<< 6);\r
-\r
- //uint16_t strobe = 1;\r
-\r
-\r
- uint8_t strober = 0;\r
- uint32_t full_av_acc = 0;\r
-\r
- for (int i=0; i< STROBE_LINES; ++i) {\r
- cur_keymap[i] = 0;\r
- //last_keymap[i] = 0;\r
- usb_keymap[i] = 0;\r
- }\r
-\r
- int16_t mux_averages[MUXES_COUNT];\r
- for(int i=0; i < MUXES_COUNT; ++i) {\r
- adc_mux_averages[i] = 0x20; // experimentally determined.\r
- }\r
- int16_t strobe_averages[STROBE_LINES];\r
- for(int i=0; i < STROBE_LINES; ++i) {\r
- adc_strobe_averages[i] = 0x20; // yup.\r
- }\r
-\r
- for(int i=0; i< KEY_COUNT; ++i) {\r
- keys_averages[i] = 0x40;\r
- keys_averages_acc[i] = (0x400);\r
- }\r
-\r
- /** warm things up a bit before we start collecting data, taking real samples. */\r
- for(uint8_t i = 0; i< STROBE_LINES; ++i) {\r
- sampleColumn(i);\r
- }\r
-\r
- while(1) {\r
-\r
- for (strober = 0; strober < STROBE_LINES; ++strober) {\r
-\r
- uint8_t tries;\r
- tries = 1;\r
- while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.\r
- column = testColumn(strober);\r
-\r
- if( column != cur_keymap[strober] && (count >= WARMUP_LOOPS) ) {\r
- tests++;\r
-\r
- tries = 1;\r
- while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.\r
- col_a = testColumn(strober);\r
-\r
- tries = 1;\r
- while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.\r
- col_b = testColumn(strober);\r
-\r
- tries = 1;\r
- while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.\r
- col_c = testColumn(strober);\r
-\r
- if( (col_a == col_b) && (col_b == col_c) && (cur_keymap[strober] != col_a) ) {\r
- cur_keymap[strober] = col_a;\r
- usb_dirty = 1;\r
- }\r
- }\r
-\r
- if(error == 0x50) {\r
- error_data |= (((uint16_t)strober) << 12);\r
- }\r
-\r
- for(int i=0; i<MUXES_COUNT; ++i) {\r
- full_samples[(strober << MUXES_COUNT_XSHIFT) + i] = samples[SAMPLE_OFFSET + i];\r
- }\r
-\r
- strobe_averages[strober] = 0;\r
- for (uint8_t i = SAMPLE_OFFSET; i < (SAMPLE_OFFSET + MUXES_COUNT); ++i) {\r
- //samples[i] -= samples[i-SAMPLE_OFFSET]; // av; // + full_av); // -something.\r
- //samples[i] -= OFFSET_VOLTAGE; // moved to sampleColumn.\r
-\r
- full_av_acc += (samples[i]);\r
- mux_averages[i - SAMPLE_OFFSET] += samples[i];\r
- strobe_averages[strober] += samples[i];\r
- //samples[i] -= (full_av - HYST_T);\r
-\r
- //++count;\r
- }\r
- adc_strobe_averages[strober] += strobe_averages[strober] >> 3;\r
- adc_strobe_averages[strober] >>= 1;\r
-\r
- /** test if we went negative. */\r
- if ((adc_strobe_averages[strober] & 0xFF00) && (count\r
- >= WARMUP_LOOPS)) {\r
- //count = 0; // TODO : constrain properly.\r
- error = 0xf; error_data = adc_strobe_averages[strober];\r
- }\r
-\r
- uint8_t strobe_line = strober << MUXES_COUNT_XSHIFT;\r
- for (int i = 0; i < MUXES_COUNT; ++i) {\r
- keys_averages_acc[strobe_line + i]\r
- += samples[SAMPLE_OFFSET + i];\r
- }\r
-\r
- } // for strober\r
-\r
- if (count < WARMUP_LOOPS) {\r
- error = 0x0C;\r
- error_data = count;\r
- count++;\r
- }\r
-\r
- // verify test key is not down.\r
- if((cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK) ) {\r
- //count=0;\r
- error = 0x05;\r
- error_data = cur_keymap[TEST_KEY_STROBE] << 8;\r
- error_data += full_samples[TEST_KEY_STROBE * 8];\r
- //threshold++;\r
- }\r
-\r
- // calc mux averages.\r
- if (count < WARMUP_LOOPS) {\r
- full_av += (full_av_acc >> (7));\r
- full_av >>= 1;\r
- //full_av = full_av_acc / count;\r
- full_av_acc = 0;\r
- for (int i=0; i < MUXES_COUNT; ++i) {\r
-\r
-// mix in 1/4 of the current average to the running average. -> (@mux_mix = 2)\r
-#define MUX_MIX 2\r
-\r
- adc_mux_averages[i] = (adc_mux_averages[i] << MUX_MIX) - adc_mux_averages[i];\r
- adc_mux_averages[i] += (mux_averages[i] >> 4);\r
- adc_mux_averages[i] >>= MUX_MIX;\r
-\r
- mux_averages[i] = 0;\r
- }\r
-\r
- }\r
-\r
-#define IDLE_COUNT_MASK 0xff\r
-#define MAX_ICS 8\r
-\r
-#define IDLE_COUNT_SHIFT 4\r
-#define KEYS_AVERAGES_MIX 2\r
-\r
- idle_count++;\r
- idle_count &= IDLE_COUNT_MASK;\r
-\r
- if (/*usb_dirty &&*/ (count >= WARMUP_LOOPS) ) {\r
- for (int i=0; i<STROBE_LINES; ++i) {\r
- usb_keymap[i] = cur_keymap[i];\r
- }\r
-\r
- dumpkeys();\r
- usb_dirty=0;\r
- _delay_ms(2);\r
- }\r
-\r
- if (count < WARMUP_LOOPS) {\r
- for (uint8_t i = 0; i < KEY_COUNT; ++i) {\r
- uint16_t acc = keys_averages_acc[i];\r
- uint32_t av = keys_averages[i];\r
-\r
- av = av + av + av + acc;\r
- av >>= 2;\r
-\r
- keys_averages[i] = av;\r
- keys_averages_acc[i] = 0;\r
- }\r
- }\r
-\r
-\r
- if(!idle_count) {\r
-\r
- for (int i=0; i< KEY_COUNT; ++i) {\r
- keys_averages_acc[i] = 0;\r
- }\r
-\r
- sampleColumn(0x0); // to resync us if we dumped a mess 'o text.\r
- }\r
- }\r
-}\r
-\r
-\r
-void debug_println() {\r
- usb_debug_putchar('\r');\r
- usb_debug_putchar('\n');\r
-}\r
-\r
-\r
-// This interrupt routine is run approx 61 times per second.\r
-// A very simple inactivity timeout is implemented, where we\r
-// will send a space character and print a message to the\r
-// hid_listen debug message window.\r
-ISR(TIMER0_OVF_vect) {\r
- //idle_count++;\r
- /*\r
- if (idle_count > 61) {\r
- idle_count = 0;\r
- }*/\r
-\r
-}\r
-\r
-void dumpkeys(void) {\r
- //print(" \n");\r
- if(error) {\r
- for (uint8_t i=0; i < STROBE_LINES; ++i) {\r
- phex(usb_keymap[i]);\r
- usb_debug_putchar(' ');\r
-\r
- //print(" ");\r
- }\r
- if (count >= WARMUP_LOOPS && error) {\r
- dump();\r
- }\r
-\r
- print(" : ");\r
- phex(error);\r
- error = 0;\r
- print(" : ");\r
- phex16(error_data);\r
- error_data = 0;\r
- print(" : ");\r
- debug_println();\r
- }\r
-\r
-\r
- for(uint8_t i = 0; i < 6; ++i) {\r
- keyboard_keys[i] = 0;\r
- }\r
- keyboard_modifier_keys = 0;\r
- uint8_t usbkeycount = 0;\r
- for (uint8_t i=0; i < STROBE_LINES; ++i) {\r
- for(uint8_t j=0; j<MUXES_COUNT; ++j) {\r
- if ( usb_keymap[i] & (1 << j) ) {\r
- uint8_t key = pgm_read_byte(matrix122F_to_set3 + ( (i << MUXES_COUNT_XSHIFT) + j) );\r
- if(usb_dirty) phex( key );\r
- if(usbkeycount < 6) {\r
- uint8_t usbkey = pgm_read_byte(page3_2_USB + key);\r
-\r
- if ((usbkey >= 0xe0) && (usbkey <= 0xe7)) { // metas\r
- keyboard_modifier_keys |= (1 << (usbkey & 0x07));\r
- } else {\r
- keyboard_keys[usbkeycount++] = usbkey;\r
- }\r
- }\r
- if (usb_dirty) usb_debug_putchar(' ');\r
- }\r
- }\r
- }\r
- if(usb_dirty) {\r
- debug_println();\r
- }\r
-\r
- /** shall we send actual keyboard events? */\r
-#if 0\r
- usb_keyboard_send();\r
-#endif\r
-\r
-}\r
-\r
-// taken from the datasheet.\r
-uint8_t readEE(uint16_t offset) {\r
- /* Wait for completion of previous write */\r
- while(EECR & (1<<EEPE))\r
- ;\r
- /* Set up address register */\r
- EEAR = offset;\r
- /* Start eeprom read by writing EERE */\r
- EECR |= (1<<EERE);\r
- /* Return data from Data Register */\r
- return EEDR;\r
-}\r
-\r
-// taken from the datasheet - note: writing is very slow. >1ms/byte.\r
-void writeEE(uint16_t offset, uint8_t data) {\r
- /* Wait for completion of previous write */\r
- while(EECR & (1<<EEPE))\r
- ;\r
- /* Set up address and Data Registers */\r
- EEAR = offset;\r
- EEDR = data;\r
- /* Write logical one to EEMPE */\r
- EECR |= (1<<EEMPE);\r
- /* Start eeprom write by setting EEPE */\r
- EECR |= (1<<EEPE);\r
-}\r
-\r
-uint8_t dump_count = 0;\r
-void dump(void) {\r
-\r
-#if 0\r
- static char once = 0;\r
- uint8_t eb;\r
-\r
- if(!once) {\r
- print("\nwriting ee");\r
- eb = readEE(0x10);\r
- eb++;\r
- writeEE(0x10, eb);\r
-\r
- once++;\r
- }\r
-\r
-\r
- print("\n ee: ");\r
- for(uint16_t i=0x10; i< 0x18; ++i) {\r
- phex(readEE(i));\r
- pchar(0x20);\r
- }\r
-#endif\r
-\r
- if(!dump_count) { // we don't want to debug-out during the measurements.\r
-\r
- for(int i =0; i< KEY_COUNT; ++i) {\r
- if(!(i & 0x0f)) {\r
- print("\n");\r
- } else if (!(i & 0x07)) {\r
- print(" ");\r
- }\r
- usb_debug_putchar(' ');\r
- //phex16 (keys_averages[(i >> MUXES_COUNT_XSHIFT) + (i & STROBE_LINES_MASK) ]);\r
- phex (keys_averages[i]);\r
- }\r
-\r
- print("\n");\r
-\r
- for(int i =0; i< KEY_COUNT; ++i) {\r
- if(!(i & 0x0f)) {\r
- print("\n");\r
- } else if (!(i & 0x07)) {\r
- print(" ");\r
- }\r
- usb_debug_putchar(' ');\r
- //phex16 (keys_averages[(i >> MUXES_COUNT_XSHIFT) + (i & STROBE_LINES_MASK) ]);\r
- //phex16 (keys_averages_acc[i]);\r
- phex(full_samples[i]);\r
- }\r
- }\r
-\r
-\r
- //}\r
-\r
-// uint8_t cur_strober = 0xe;\r
- uint8_t cur_strober = ze_strober;\r
- print("\n");\r
-\r
- phex(cur_strober);\r
- //print(": ");\r
- print(": ");\r
-#if 1\r
- print("\n");\r
- for (uint8_t i=0; i < MUXES_COUNT; ++i) {\r
- usb_debug_putchar(' ');\r
- phex16(full_samples[(cur_strober << MUXES_COUNT_XSHIFT) + i]);\r
- }\r
-\r
- print("\n");\r
-// phex(threshold);\r
-// print(": ");\r
-\r
- for (uint8_t i=0; i < MUXES_COUNT; ++i) {\r
- usb_debug_putchar(' ');\r
- phex16(keys_averages[(cur_strober << MUXES_COUNT_XSHIFT) + i]);\r
- }\r
-\r
-#endif\r
- /*\r
- for (uint8_t i=0; i< SAMPLES; ++i) {\r
- print(" ");\r
- phex16(samples[i]);\r
- //phex16(ADC);\r
- }*/\r
- //print(" : ");\r
- //usb_debug_putchar((was_active)?' ':'*');\r
-\r
- //phex16(keymap[TEST_KEY_STROBE] & TEST_KEY_MASK);\r
- /*print(" "); */\r
- //phex(keymap[TEST_KEY_STROBE]);\r
-\r
-\r
- //print("\n");\r
- //print(":");\r
- //phex(full_av);\r
- //phex16(count);\r
- //print(" : ");\r
- print("\n");\r
-\r
- for (uint8_t i=0; i < STROBE_LINES; ++i) {\r
- phex(cur_keymap[i]);\r
- usb_debug_putchar(' ');\r
-\r
- //print(" ");\r
- }\r
-\r
-\r
- //print(": ");\r
- //phex(adc_strobe_averages[ze_strober]);\r
- //usb_debug_putchar(' ');\r
-\r
-\r
-\r
- for (uint8_t i=0; i < MUXES_COUNT; ++i) {\r
- usb_debug_putchar(' ');\r
- //phex16(adc_mux_averages[i] + adc_strobe_averages[ze_strober] - full_av);\r
- //phex16((adc_mux_averages[i] + adc_strobe_averages[ze_strober]) >> 1);\r
- //phex16((adc_mux_averages[i] * 3 + adc_strobe_averages[ze_strober]) >> 2);\r
- //phex16(adc_mux_averages[i] + threshold);\r
- //phex16(gsamples[i + SAMPLE_OFFSET] - (adc_mux_averages[i] + threshold) + 0x100);\r
- //phex16(keys_averages[(ze_strober << MUXES_COUNT_XSHIFT) + i] + (uint8_t)threshold);\r
- phex16(keys_averages[(ze_strober << MUXES_COUNT_XSHIFT) + i]);\r
- }\r
-\r
- if(error) {\r
- usb_debug_putchar(' ');\r
- phex (error);\r
- usb_debug_putchar(' ');\r
- phex16(error_data);\r
- error = 0;\r
- error_data = 0;\r
- }\r
- //print("\n");\r
-\r
- ze_strober++;\r
- ze_strober &= 0xf;\r
-\r
-\r
- dump_count++;\r
- dump_count &= 0x0f;\r
-\r
-\r
-\r
- //ze_strobe = (1 << (ze_strober ) );\r
-\r
-\r
-\r
- //phex(ADCSRA);\r
- //print(" ");\r
- //print("\n");\r
- //usb_keyboard_press(KEY_SPACE, 0);\r
-\r
-// if(blink) {\r
-// LED_ON;\r
-// } else {\r
-// LED_OFF;\r
-// }\r
-// blink ^= 1;\r
-}\r
-\r
-\r
-/*\r
-int oldmain(void) {\r
- uint8_t b, d, mask, i, reset_idle;\r
- uint8_t b_prev=0xFF, d_prev=0xFF;\r
-\r
- // set for 16 MHz clock\r
- CPU_PRESCALE(0);\r
-\r
- // Configure all port B and port D pins as inputs with pullup resistors.\r
- // See the "Using I/O Pins" page for details.\r
- // http://www.pjrc.com/teensy/pins.html\r
- DDRD = 0x00;\r
- DDRB = 0x00;\r
- PORTB = 0xFF;\r
- PORTD = 0xFF;\r
-\r
- // Initialize the USB, and then wait for the host to set configuration.\r
- // If the Teensy is powered without a PC connected to the USB port,\r
- // this will wait forever.\r
- usb_init();\r
- while (!usb_configured()) ;\r
-\r
- // Wait an extra second for the PC's operating system to load drivers\r
- // and do whatever it does to actually be ready for input\r
- _delay_ms(1000);\r
-\r
- // Configure timer 0 to generate a timer overflow interrupt every\r
- // 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock\r
- // This demonstrates how to use interrupts to implement a simple\r
- // inactivity timeout.\r
- TCCR0A = 0x00;\r
- TCCR0B = 0x05;\r
- TIMSK0 = (1<<TOIE0);\r
-\r
- print("Begin keyboard example program\n");\r
- print("All Port B or Port D pins are inputs with pullup resistors.\n");\r
- print("Any connection to ground on Port B or D pins will result in\n");\r
- print("keystrokes sent to the PC (and debug messages here).\n");\r
- while (1) {\r
- // read all port B and port D pins\r
- b = PINB;\r
- d = PIND;\r
- // check if any pins are low, but were high previously\r
- mask = 1;\r
- reset_idle = 0;\r
- for (i=0; i<8; i++) {\r
- if (((b & mask) == 0) && (b_prev & mask) != 0) {\r
- usb_keyboard_press(KEY_B, KEY_SHIFT);\r
- usb_keyboard_press(number_keys[i], 0);\r
- print("Port B, bit ");\r
- phex(i);\r
- print("\n");\r
- reset_idle = 1;\r
- }\r
- if (((d & mask) == 0) && (d_prev & mask) != 0) {\r
- usb_keyboard_press(KEY_D, KEY_SHIFT);\r
- usb_keyboard_press(number_keys[i], 0);\r
- print("Port D, bit ");\r
- phex(i);\r
- print("\n");\r
- reset_idle = 1;\r
- }\r
- mask = mask << 1;\r
- }\r
- // if any keypresses were detected, reset the idle counter\r
- if (reset_idle) {\r
- // variables shared with interrupt routines must be\r
- // accessed carefully so the interrupt routine doesn't\r
- // try to use the variable in the middle of our access\r
- cli();\r
- idle_count = 0;\r
- sei();\r
- }\r
- // now the current pins will be the previous, and\r
- // wait a short delay so we're not highly sensitive\r
- // to mechanical "bounce".\r
- b_prev = b;\r
- d_prev = d;\r
- _delay_ms(2);\r
- }\r
-}\r
-*/\r
-\r
+/* Copyright (C) 2011-2013 by Joseph Makuch
+ * Additions by Jacob Alexander (2013)
+ *
+ * dfj, put whatever license here you want -HaaTa
+ */
+
+// ----- Includes -----
+
+// Compiler Includes
+#include <Lib/ScanLib.h>
+
+// Project Includes
+#include <led.h>
+#include <print.h>
+
+// Local Includes
+#include "scan_loop.h"
+
+
+
+// ----- Defines -----
+
+// TODO dfj defines...needs cleaning up and commenting...
+#define THRESHOLD 0x0a
+#define BUMP_THRESHOLD 0x50
+//((THRESHOLD) * 3)
+#define BUMP_REST_US 1200
+
+#define HYST 1
+#define HYST_T 0x10
+
+#define TEST_KEY_STROBE (0x05)
+#define TEST_KEY_MASK (1 << 0)
+
+#define ADHSM 7
+
+/** Whether to use all of D and C, vs using E0, E1 instead of D6, D7,
+ * or alternately all of D, and E0,E1 and C0,..5 */
+//#define ALL_D_C
+//#define SHORT_D
+#define SHORT_C
+
+// rough offset voltage: one diode drop, about 50mV = 0x3ff * 50/3560 = 20
+//#define OFFSET_VOLTAGE 0x14
+#define OFFSET_VOLTAGE 0x28
+
+
+#define RIGHT_JUSTIFY 0
+#define LEFT_JUSTIFY (0xff)
+
+// set left or right justification here:
+#define JUSTIFY_ADC RIGHT_JUSTIFY
+
+#define ADLAR_MASK (1 << ADLAR)
+#ifdef JUSTIFY_ADC
+#define ADLAR_BITS ((ADLAR_MASK) & (JUSTIFY_ADC))
+#else // defaults to right justification.
+#define ADLAR_BITS 0
+#endif
+
+
+// full muxmask
+#define FULL_MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2) | (1 << MUX3) | (1 << MUX4))
+
+// F0-f7 pins only muxmask.
+#define MUX_MASK ((1 << MUX0) | (1 << MUX1) | (1 << MUX2))
+
+#define MUX_1_1 0x1e
+#define MUX_GND 0x1f
+
+
+ // set ADC clock prescale
+#define PRESCALE_MASK ((1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2))
+#define PRESCALE_SHIFT (ADPS0)
+#define PRESCALE 3
+
+
+#ifdef EXTENDED_STROBE
+
+#define STROBE_LINES 18
+
+#else
+
+#define STROBE_LINES 16
+
+#endif
+
+#define STROBE_LINES_XSHIFT 4
+#define STROBE_LINES_MASK 0x0f
+#define MUXES_COUNT 8
+#define MUXES_COUNT_XSHIFT 3
+#define MUXES_MASK 0x7
+
+#define WARMUP_LOOPS ( 1024 )
+
+#define RECOVERY_US 6
+
+#define SAMPLES 10
+
+
+#define SAMPLE_OFFSET ((SAMPLES) - MUXES_COUNT)
+//#define SAMPLE_OFFSET 9
+#define STROBE_OFFSET 0
+
+
+#define KEY_COUNT ((STROBE_LINES) * (MUXES_COUNT))
+
+#define LX2FX
+
+
+#define RECOVERY_CONTROL 1
+
+#define RECOVERY_SOURCE 0
+#define RECOVERY_SINK 2
+#define RECOVERY_MASK 0x03
+
+
+// mix in 1/4 of the current average to the running average. -> (@mux_mix = 2)
+#define MUX_MIX 2
+
+
+#define IDLE_COUNT_MASK 0xff
+#define MAX_ICS 8
+
+#define IDLE_COUNT_SHIFT 4
+#define KEYS_AVERAGES_MIX 2
+
+
+#ifdef ALL_D_C
+
+#define D_MASK (0xff)
+#define D_SHIFT 0
+
+#define E_MASK (0x00)
+#define E_SHIFT 0
+
+#define C_MASK (0xff)
+#define C_SHIFT 8
+
+#else
+#if defined(SHORT_D)
+
+#define D_MASK (0x3f)
+#define D_SHIFT 0
+
+#define E_MASK (0x03)
+#define E_SHIFT 6
+
+#define C_MASK (0xff)
+#define C_SHIFT 8
+
+#else
+#if defined(SHORT_C)
+
+#define D_MASK (0xff)
+#define D_SHIFT 0
+
+#define E_MASK (0x03)
+#define E_SHIFT 6
+
+#define C_MASK (0xff)
+#define C_SHIFT 8
+#endif
+#endif
+#endif
+
+
+
+
+
+// ----- Macros -----
+
+// Make sure we haven't overflowed the buffer
+#define bufferAdd(byte) \
+ if ( KeyIndex_BufferUsed < KEYBOARD_BUFFER ) \
+ KeyIndex_Buffer[KeyIndex_BufferUsed++] = byte
+
+
+// TODO dfj macros...needs cleaning up and commenting...
+#define STROBE_CASE(SC_CASE, SC_REG_A) case (SC_CASE): PORT##SC_REG_A = \
+ (( (PORT##SC_REG_A) & ~(1 << (SC_CASE - SC_REG_A##_SHIFT)) ) | (1 << (SC_CASE - SC_REG_A##_SHIFT)))
+
+#define SET_MUX(X) ((ADMUX) = (((ADMUX) & ~(MUX_MASK)) | ((X) & (MUX_MASK))))
+#define SET_FULL_MUX(X) ((ADMUX) = (((ADMUX) & ~(FULL_MUX_MASK)) | ((X) & (FULL_MUX_MASK))))
+
+
+
+
+
+// ----- Variables -----
+
+// Buffer used to inform the macro processing module which keys have been detected as pressed
+volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
+volatile uint8_t KeyIndex_BufferUsed;
+
+
+// TODO dfj variables...needs cleaning up and commenting
+ uint8_t blink = 0;
+volatile uint8_t idle_count = 1;
+volatile uint16_t full_av = 0;
+
+/**/ uint8_t ze_strober = 0;
+
+int16_t samples [SAMPLES];
+
+//int16_t gsamples [SAMPLES];
+
+/**/ int16_t adc_mux_averages[MUXES_COUNT];
+/**/ int16_t adc_strobe_averages[STROBE_LINES];
+
+
+/**/ uint8_t cur_keymap[STROBE_LINES];
+// /**/ int8_t last_keymap[STROBE_LINES];
+/**/ uint8_t usb_keymap[STROBE_LINES];
+uint8_t dirty;
+uint8_t unstable;
+uint8_t usb_dirty;
+
+int16_t threshold = THRESHOLD;
+uint16_t tests = 0;
+
+uint8_t col_a=0;
+uint8_t col_b=0;
+uint8_t col_c=0;
+
+uint8_t column=0;
+
+
+int16_t keys_averages_acc[KEY_COUNT];
+uint16_t keys_averages[KEY_COUNT];
+
+uint8_t full_samples[KEY_COUNT];
+
+/* viable starting biases for near 0.830V offset. and adc PRESCALE 3
+0017 0016 001B 001A 0016 0016 000F 000E 001B 001E 001E 0018 0017 0015 000E 001D
+001B 001A 0016 0016 000F 000E 001C 001B 001E 0018 0017 0015 000E 001D 0024 001F
+0016 0016 000F 000E 001C 001B 001E 001E 0017 0015 000E 001D 0024 001F 0020 001F
+000F 000E 001C 001B 001E 001E 0018 0017 000E 001D 0024 001F 0020 001F 0020 0017
+001C 001B 001E 001E 0018 0017 0015 000E 0024 001F 0020 001F 0020 0017 0010 001D
+001E 001E 0018 0017 0015 000E 001D 0024 0020 001F 0020 0017 0010 001D 0024 0021
+0018 0017 0015 000E 001D 0024 001F 0020 0020 0017 0010 001D 0024 0021 0021 0021
+0015 000E 001D 0024 001F 0020 001F 0020 0010 001D 0024 0021 0021 0021 0021 0018
+*/
+
+/*** starting bias relative to fixed offset estimate of 820mV (0x50)
+ * 77 69 65 5B 50 4E 4C 45 66 53 4D 49 45 3F 3E 35
+ * 68 54 4F 49 45 40 3F 34 74 66 5F 56 4E 4D 4C 3F
+ * 6D 5D 53 4C 49 46 45 38 6D 5A 53 4E 49 48 45 3E
+ * 6F 5D 56 4E 4B 48 48 3A 6D 5C 54 4E 48 48 45 37
+ * 75 68 5F 57 4F 4D 4C 3F 60 4E 48 41 3C 3C 39 2F
+ * 65 53 4E 49 41 3F 3E 34 65 54 4E 49 43 3F 3E 34
+ * 60 51 4A 45 3F 3E 3C 30 57 4C 45 3E 3B 37 37 2E
+ * 64 4E 48 44 3C 3B 39 2F 5D 4F 48 45 3E 3C 3B 30
+ */
+
+/*volatile*/ uint16_t count = 0;
+
+/*volatile*/ uint8_t error = 0;
+uint16_t error_data = 0;
+
+
+int16_t mux_averages[MUXES_COUNT];
+int16_t strobe_averages[STROBE_LINES];
+
+uint8_t dump_count = 0;
+
+
+
+// ----- Function Declarations -----
+
+void dump ( void );
+void dumpkeys( void );
+
+void recovery( uint8_t on );
+
+int sampleColumn ( uint8_t column );
+int sampleColumn_i( uint8_t column, uint8_t muxes, int16_t * buffer); // XXX Not currently used
+int sampleColumn_k( uint8_t column, int16_t *buffer );
+
+void setup_ADC( void );
+
+void strobe_w( uint8_t strobe_num );
+
+uint8_t testColumn( uint8_t strobe );
+
+
+
+// ----- Functions -----
+
+// Initial setup for cap sense controller
+inline void scan_setup()
+{
+ // TODO dfj code...needs cleanup + commenting...
+ setup_ADC();
+
+ // Configure timer 0 to generate a timer overflow interrupt every
+ // 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock
+ // This demonstrates how to use interrupts to implement a simple
+ // inactivity timeout.
+ //TCCR0A = 0x00;
+ //TCCR0B = 0x05;
+ //TIMSK0 = (1<<TOIE0);
+
+ DDRC = C_MASK;
+ PORTC = 0;
+ DDRD = D_MASK;
+ PORTD = 0;
+ DDRE = E_MASK;
+ PORTE = 0 ;
+
+ //DDRC |= (1 << 6);
+ //PORTC &= ~(1<< 6);
+
+ //uint16_t strobe = 1;
+
+
+ // TODO all this code should probably be in scan_resetKeyboard
+ for (int i=0; i< STROBE_LINES; ++i) {
+ cur_keymap[i] = 0;
+ //last_keymap[i] = 0;
+ usb_keymap[i] = 0;
+ }
+
+ for(int i=0; i < MUXES_COUNT; ++i) {
+ adc_mux_averages[i] = 0x20; // experimentally determined.
+ }
+ for(int i=0; i < STROBE_LINES; ++i) {
+ adc_strobe_averages[i] = 0x20; // yup.
+ }
+
+ for(int i=0; i< KEY_COUNT; ++i) {
+ keys_averages[i] = 0x40;
+ keys_averages_acc[i] = (0x400);
+ }
+
+ /** warm things up a bit before we start collecting data, taking real samples. */
+ for(uint8_t i = 0; i< STROBE_LINES; ++i) {
+ sampleColumn(i);
+ }
+
+
+ // Reset the keyboard before scanning, we might be in a wierd state
+ // Also sets the KeyIndex_BufferUsed to 0
+ scan_resetKeyboard();
+}
+
+
+// Main Detection Loop
+// This is where the important stuff happens
+inline uint8_t scan_loop()
+{
+ // TODO dfj code...needs commenting + cleanup...
+ uint8_t strober = 0;
+ uint32_t full_av_acc = 0;
+
+ for (strober = 0; strober < STROBE_LINES; ++strober) {
+
+ uint8_t tries;
+ tries = 1;
+ while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.
+ column = testColumn(strober);
+
+ if( column != cur_keymap[strober] && (count >= WARMUP_LOOPS) ) {
+ tests++;
+
+ tries = 1;
+ while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.
+ col_a = testColumn(strober);
+
+ tries = 1;
+ while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.
+ col_b = testColumn(strober);
+
+ tries = 1;
+ while (tries++ && sampleColumn(strober)) { tries &= 0x7; } // don't waste this one just because the last one was poop.
+ col_c = testColumn(strober);
+
+ if( (col_a == col_b) && (col_b == col_c) && (cur_keymap[strober] != col_a) ) {
+ cur_keymap[strober] = col_a;
+ usb_dirty = 1;
+ }
+ }
+
+ if(error == 0x50) {
+ error_data |= (((uint16_t)strober) << 12);
+ }
+
+ for(int i=0; i<MUXES_COUNT; ++i) {
+ full_samples[(strober << MUXES_COUNT_XSHIFT) + i] = samples[SAMPLE_OFFSET + i];
+ }
+
+ strobe_averages[strober] = 0;
+ for (uint8_t i = SAMPLE_OFFSET; i < (SAMPLE_OFFSET + MUXES_COUNT); ++i) {
+ //samples[i] -= samples[i-SAMPLE_OFFSET]; // av; // + full_av); // -something.
+ //samples[i] -= OFFSET_VOLTAGE; // moved to sampleColumn.
+
+ full_av_acc += (samples[i]);
+ mux_averages[i - SAMPLE_OFFSET] += samples[i];
+ strobe_averages[strober] += samples[i];
+ //samples[i] -= (full_av - HYST_T);
+
+ //++count;
+ }
+ adc_strobe_averages[strober] += strobe_averages[strober] >> 3;
+ adc_strobe_averages[strober] >>= 1;
+
+ /** test if we went negative. */
+ if ((adc_strobe_averages[strober] & 0xFF00) && (count
+ >= WARMUP_LOOPS)) {
+ //count = 0; // TODO : constrain properly.
+ error = 0xf; error_data = adc_strobe_averages[strober];
+ }
+
+ uint8_t strobe_line = strober << MUXES_COUNT_XSHIFT;
+ for (int i = 0; i < MUXES_COUNT; ++i) {
+ keys_averages_acc[strobe_line + i]
+ += samples[SAMPLE_OFFSET + i];
+ }
+
+ } // for strober
+
+ if (count < WARMUP_LOOPS) {
+ error = 0x0C;
+ error_data = count;
+ count++;
+ }
+
+ // verify test key is not down.
+ if((cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK) ) {
+ //count=0;
+ error = 0x05;
+ error_data = cur_keymap[TEST_KEY_STROBE] << 8;
+ error_data += full_samples[TEST_KEY_STROBE * 8];
+ //threshold++;
+ }
+
+ // calc mux averages.
+ if (count < WARMUP_LOOPS) {
+ full_av += (full_av_acc >> (7));
+ full_av >>= 1;
+ //full_av = full_av_acc / count;
+ full_av_acc = 0;
+ for (int i=0; i < MUXES_COUNT; ++i) {
+
+ adc_mux_averages[i] = (adc_mux_averages[i] << MUX_MIX) - adc_mux_averages[i];
+ adc_mux_averages[i] += (mux_averages[i] >> 4);
+ adc_mux_averages[i] >>= MUX_MIX;
+
+ mux_averages[i] = 0;
+ }
+
+ }
+
+ idle_count++;
+ idle_count &= IDLE_COUNT_MASK;
+
+ if (/*usb_dirty &&*/ (count >= WARMUP_LOOPS) ) {
+ for (int i=0; i<STROBE_LINES; ++i) {
+ usb_keymap[i] = cur_keymap[i];
+ }
+
+ dumpkeys();
+ usb_dirty=0;
+ _delay_ms(2);
+ }
+
+ if (count < WARMUP_LOOPS) {
+ for (uint8_t i = 0; i < KEY_COUNT; ++i) {
+ uint16_t acc = keys_averages_acc[i];
+ uint32_t av = keys_averages[i];
+
+ av = av + av + av + acc;
+ av >>= 2;
+
+ keys_averages[i] = av;
+ keys_averages_acc[i] = 0;
+ }
+ }
+
+
+ if(!idle_count) {
+
+ for (int i=0; i< KEY_COUNT; ++i) {
+ keys_averages_acc[i] = 0;
+ }
+
+ sampleColumn(0x0); // to resync us if we dumped a mess 'o text.
+ }
+
+
+ // Return non-zero if macro and USB processing should be delayed
+ // Macro processing will always run if returning 0
+ // USB processing only happens once the USB send timer expires, if it has not, scan_loop will be called
+ // after the macro processing has been completed
+ return 0;
+}
+
+
+// Reset Keyboard
+void scan_resetKeyboard( void )
+{
+ // Empty buffer, now that keyboard has been reset
+ KeyIndex_BufferUsed = 0;
+}
+
+
+// Send data to keyboard
+// NOTE: Only used for converters, since the scan module shouldn't handle sending data in a controller
+uint8_t scan_sendData( uint8_t dataPayload )
+{
+ return 0;
+}
+
+
+// Reset/Hold keyboard
+// NOTE: Only used for converters, not needed for full controllers
+void scan_lockKeyboard( void )
+{
+}
+
+// NOTE: Only used for converters, not needed for full controllers
+void scan_unlockKeyboard( void )
+{
+}
+
+
+// Signal KeyIndex_Buffer that it has been properly read
+// NOTE: Only really required for implementing "tricks" in converters for odd protocols
+void scan_finishedWithBuffer( uint8_t sentKeys )
+{
+ // Convenient place to clear the KeyIndex_Buffer
+ KeyIndex_BufferUsed = 0;
+ return;
+}
+
+
+// Signal KeyIndex_Buffer that it has been properly read and sent out by the USB module
+// NOTE: Only really required for implementing "tricks" in converters for odd protocols
+void scan_finishedWithUSBBuffer( uint8_t sentKeys )
+{
+ return;
+}
+
+
+void
+_delay_loop(uint8_t __count)
+{
+ __asm__ volatile (
+ "1: dec %0" "\n\t"
+ "brne 1b"
+ : "=r" (__count)
+ : "0" (__count)
+ );
+}
+
+
+void setup_ADC (void) {
+ // disable adc digital pins.
+ DIDR1 |= (1 << AIN0D) | (1<<AIN1D); // set disable on pins 1,0.
+ //DIDR0 = 0xff; // disable all. (port F, usually). - testing w/o disable.
+ DDRF = 0x0;
+ PORTF = 0x0;
+ uint8_t mux = 0 & 0x1f; // 0 == first. // 0x1e = 1.1V ref.
+
+ // 0 = external aref 1,1 = 2.56V internal ref
+ uint8_t aref = ((1 << REFS1) | (1 << REFS0)) & ((1 << REFS1) | (1 << REFS0));
+// uint8_t adlar = 0xff & (1 << ADLAR); // 1 := left justify bits, 0 := right
+ uint8_t adate = (1 << ADATE) & (1 << ADATE); // trigger enable
+ uint8_t trig = 0 & ((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2)); // 0 = free running
+ // ps2, ps1 := /64 ( 2^6 ) ps2 := /16 (2^4), ps1 := 4, ps0 :=2, PS1,PS0 := 8 (2^8)
+ uint8_t prescale = ( ((PRESCALE) << PRESCALE_SHIFT) & PRESCALE_MASK ); // 001 == 2^1 == 2
+ uint8_t hispeed = (1 << ADHSM);
+ uint8_t en_mux = (1 << ACME);
+
+ //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS1) | (1 << ADPS2)); // 2, 1 := /64 ( 2^6 )
+ //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS0) | (1 << ADPS2)); // 2, 0 := /32 ( 2^5 )
+ //ADCSRA = (ADCSRA & ~PRESCALES) | ((1 << ADPS2)); // 2 := /16 ( 2^4 )
+
+ ADCSRA = (1 << ADEN) | prescale; // ADC enable
+
+ // select ref.
+ //ADMUX |= ((1 << REFS1) | (1 << REFS0)); // 2.56 V internal.
+ //ADMUX |= ((1 << REFS0) ); // Vcc with external cap.
+ //ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // 0,0 : aref.
+ ADMUX = aref | mux | ADLAR_BITS;
+
+ // enable MUX
+ // ADCSRB |= (1 << ACME); // enable
+ // ADCSRB &= ~(1 << ADEN); // ?
+
+ // select first mux.
+ //ADMUX = (ADMUX & ~MUXES); // start at 000 = ADC0
+
+ // clear adlar to left justify data
+ //ADMUX = ~();
+
+ // set adlar to right justify data
+ //ADMUX |= (1 << ADLAR);
+
+
+ // set free-running
+ ADCSRA |= adate; // trigger enable
+ ADCSRB = en_mux | hispeed | trig | (ADCSRB & ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2))); // trigger select free running
+
+// ADCSRA |= (1 << ADATE); // tiggger enable
+
+ ADCSRA |= (1 << ADEN); // ADC enable
+ ADCSRA |= (1 << ADSC); // start conversions q
+
+}
+
+
+void recovery(uint8_t on) {
+ DDRB |= (1 << RECOVERY_CONTROL);
+
+ PORTB &= ~(1 << RECOVERY_SINK); // SINK always zero
+ DDRB &= ~(1 << RECOVERY_SOURCE); // SOURCE high imp
+
+ if(on) {
+ DDRB |= (1 << RECOVERY_SINK); // SINK pull
+
+
+ PORTB |= (1 << RECOVERY_CONTROL);
+
+ PORTB |= (1 << RECOVERY_SOURCE); // SOURCE high
+ DDRB |= (1 << RECOVERY_SOURCE);
+ } else {
+ _delay_loop(10);
+ PORTB &= ~(1 << RECOVERY_CONTROL);
+
+ DDRB &= ~(1 << RECOVERY_SOURCE);
+ PORTB &= ~(1 << RECOVERY_SOURCE); // SOURCE low
+ DDRB &= ~(1 << RECOVERY_SINK); // SINK high-imp
+
+ //DDRB &= ~(1 << RECOVERY_SINK);
+ }
+}
+
+
+void strobe_w(uint8_t strobe_num) {
+
+ PORTC &= ~(D_MASK);
+ PORTD &= ~(D_MASK);
+ PORTE &= ~(E_MASK);
+
+#ifdef SHORT_C
+ strobe_num = 15 - strobe_num;
+#endif
+
+ switch(strobe_num) {
+
+ case 0: PORTD |= (1 << 0); break;
+ case 1: PORTD |= (1 << 1); break;
+ case 2: PORTD |= (1 << 2); break;
+ case 3: PORTD |= (1 << 3); break;
+ case 4: PORTD |= (1 << 4); break;
+ case 5: PORTD |= (1 << 5); break;
+
+#ifdef ALL_D
+
+ case 6: PORTD |= (1 << 6); break;
+ case 7: PORTD |= (1 << 7); break;
+
+ case 8: PORTC |= (1 << 0); break;
+ case 9: PORTC |= (1 << 1); break;
+ case 10: PORTC |= (1 << 2); break;
+ case 11: PORTC |= (1 << 3); break;
+ case 12: PORTC |= (1 << 4); break;
+ case 13: PORTC |= (1 << 5); break;
+ case 14: PORTC |= (1 << 6); break;
+ case 15: PORTC |= (1 << 7); break;
+
+ case 16: PORTE |= (1 << 0); break;
+ case 17: PORTE |= (1 << 1); break;
+
+#else
+#ifdef SHORT_D
+
+ case 6: PORTE |= (1 << 0); break;
+ case 7: PORTE |= (1 << 1); break;
+
+ case 8: PORTC |= (1 << 0); break;
+ case 9: PORTC |= (1 << 1); break;
+ case 10: PORTC |= (1 << 2); break;
+ case 11: PORTC |= (1 << 3); break;
+ case 12: PORTC |= (1 << 4); break;
+ case 13: PORTC |= (1 << 5); break;
+ case 14: PORTC |= (1 << 6); break;
+ case 15: PORTC |= (1 << 7); break;
+
+#else
+#ifdef SHORT_C
+
+ case 6: PORTD |= (1 << 6); break;
+ case 7: PORTD |= (1 << 7); break;
+
+ case 8: PORTE |= (1 << 0); break;
+ case 9: PORTE |= (1 << 1); break;
+
+ case 10: PORTC |= (1 << 0); break;
+ case 11: PORTC |= (1 << 1); break;
+ case 12: PORTC |= (1 << 2); break;
+ case 13: PORTC |= (1 << 3); break;
+ case 14: PORTC |= (1 << 4); break;
+ case 15: PORTC |= (1 << 5); break;
+
+ case 16: PORTC |= (1 << 6); break;
+ case 17: PORTC |= (1 << 7); break;
+
+#endif
+#endif
+#endif
+
+ default:
+ break;
+ }
+
+}
+
+
+int sampleColumn_i(uint8_t column, uint8_t muxes, int16_t * buffer) {
+
+ // ensure all probe lines are driven low, and chill for recovery delay.
+ PORTC &= ~C_MASK;
+ PORTD &= ~D_MASK;
+ PORTE &= ~E_MASK;
+ recovery(1);
+ _delay_us(RECOVERY_US);
+ recovery(0);
+
+ uint8_t index = 0;
+
+ for (uint8_t i=0; i<8; ++i) {
+ if(muxes & (1 << i)) {
+ buffer[index++] = i;
+ }
+ }
+
+ SET_FULL_MUX(MUX_1_1); // crap sample will use this.
+ ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+
+ //uint16_t sample;
+
+ while (! (ADCSRA & (1 << ADIF))); // wait until ready.
+ //sample = ADC; // 1st sample, icky.
+ ADC; // 1st sample, icky. XXX Not sure if the compiler throws this away, but less compiler warnings -HaaTa
+
+ strobe_w(column);
+ //recovery(0);
+
+ /**
+ * we are running in continuous mode, so we must setup the next
+ * read _before_ the current read completes.
+ *
+ * setup 0,
+ * read garbage,
+ * do not store
+ *
+ * setup 1,
+ * read 0,
+ * store 0,
+ *
+ * ...
+ *
+ * setup junk,
+ * read n
+ * store n
+ *
+ * */
+
+
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ //wait for last read to complete.
+ while (! (ADCSRA & (1 << ADIF)));
+ //sample = ADC; // throw away strobe'd value.
+ ADC; // throw away strobe'd value.
+
+#if 0
+ for (uint8_t i=0; i <= index; ++i) {
+
+ // setup i'th read.
+ SET_FULL_MUX(buffer[i]); // _next_ read will use this.
+ // wait for i-1'th read to complete:
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ while (! (ADCSRA & (1 << ADIF)));
+
+ // retrieve last (i-1'th) read.
+ if (i) {
+ buffer[i-1] = ADC - OFFSET_VOLTAGE;
+ } /*else {
+ buffer[0] = ADC - OFFSET_VOLTAGE;
+ }*/
+
+ //index++;
+ }
+#else
+ for (uint8_t i=0; i < index; ++i) {
+
+ // setup i'th read.
+ SET_FULL_MUX(buffer[i]); // _next_ read will use this.
+
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ while (! (ADCSRA & (1 << ADIF)));
+ //sample = ADC; // throw away warmup value.
+ ADC; // throw away warmup value.
+
+
+
+ /*
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ while (! (ADCSRA & (1 << ADIF)));
+ //sample = ADC; // throw away warmup value.
+ ADC; // throw away warmup value.
+*/
+
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ while (! (ADCSRA & (1 << ADIF)));
+
+ // retrieve current read.
+ buffer[i] = ADC - OFFSET_VOLTAGE;
+
+
+ }
+#endif
+
+
+ // turn off adc.
+ ADCSRA &= ~(1 << ADEN);
+
+ // pull all columns' probe-lines low.
+ PORTC &= ~C_MASK;
+ PORTD &= ~D_MASK;
+ PORTE &= ~E_MASK;
+
+ // test for humps. :/
+ /*uint16_t delta = full_av;
+ if(buffer[0] > BUMP_THRESHOLD + delta) {
+ // ze horror.
+ return 1;
+ } else {
+ return 0; //all good.
+ }*/
+ return 0;
+
+}
+
+
+int sampleColumn_k(uint8_t column, int16_t * buffer) {
+ // ensure all probe lines are driven low, and chill for recovery delay.
+ //uint16_t sample;
+
+ ADCSRA |= (1 << ADEN) | (1 << ADSC); // enable and start conversions
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+
+ // sync up with adc clock:
+ while (! (ADCSRA & (1 << ADIF))); // wait until ready.
+ ADC; // throw it away. // XXX Not sure if the compiler throws this away, but less compiler warnings -HaaTa
+ //sample = ADC; // throw it away.
+
+ for(uint8_t mux=0; mux < 8; ++mux) {
+
+ PORTC &= ~C_MASK;
+ PORTD &= ~D_MASK;
+ PORTE &= ~E_MASK;
+
+ SET_FULL_MUX(mux); // our sample will use this
+
+ for(uint8_t i=0; i < 2; ++i) {
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ //wait for last read to complete.
+ while (! (ADCSRA & (1 << ADIF)));
+ //sample = ADC; // throw away strobe'd value.
+ ADC; // throw away strobe'd value.
+ }
+
+ recovery(0);
+ strobe_w(column);
+
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ //wait for last read to complete.
+ while (! (ADCSRA & (1 << ADIF)));
+ //sample = ADC; // throw away strobe'd value.
+ ADC; // throw away strobe'd value.
+
+ ADCSRA |= (1 << ADIF); // clear int flag by writing 1.
+ while (! (ADCSRA & (1 << ADIF)));
+
+ // retrieve current read.
+ buffer[mux] = ADC - OFFSET_VOLTAGE;
+ recovery(1);
+
+ }
+
+ // turn off adc.
+ ADCSRA &= ~(1 << ADEN);
+
+ // pull all columns' probe-lines low.
+ PORTC &= ~C_MASK;
+ PORTD &= ~D_MASK;
+ PORTE &= ~E_MASK;
+// recovery(1);
+
+
+ return 0;
+}
+
+
+int sampleColumn(uint8_t column) {
+ int rval = 0;
+
+ /*
+ sampleColumn_i(column, 0x0f, samples+SAMPLE_OFFSET);
+ sampleColumn_i(column, 0xf0, samples+SAMPLE_OFFSET + 4 );
+*/
+
+ rval = sampleColumn_k(column, samples+SAMPLE_OFFSET);
+
+ for(uint8_t i=0; i<8; ++i) {
+ if(samples[SAMPLE_OFFSET + i] - adc_mux_averages[i] > BUMP_THRESHOLD) {
+ // was a hump
+
+ _delay_us(BUMP_REST_US);
+ rval++;
+ error = 0x50;
+ error_data = samples[SAMPLE_OFFSET +i]; // | ((uint16_t)i << 8);
+ return rval;
+ }
+ }
+
+ return rval;
+}
+
+
+uint8_t testColumn(uint8_t strobe) {
+ uint8_t column = 0;
+ uint8_t bit = 1;
+ for (uint8_t i=0; i < MUXES_COUNT; ++i) {
+ uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + i];
+ if ((int16_t)samples[SAMPLE_OFFSET + i] > threshold + delta) {
+ column |= bit;
+ }
+ bit <<= 1;
+ }
+ return column;
+}
+
+
+void dumpkeys(void) {
+ //print(" \n");
+ if(error) {
+ for (uint8_t i=0; i < STROBE_LINES; ++i) {
+ printHex(usb_keymap[i]);
+ print(" ");
+
+ //print(" ");
+ }
+ if (count >= WARMUP_LOOPS && error) {
+ dump();
+ }
+
+ print(" : ");
+ printHex(error);
+ error = 0;
+ print(" : ");
+ printHex(error_data);
+ error_data = 0;
+ print(" : " NL);
+ }
+
+ // XXX Will be cleaned up eventually, but this will do for now :P -HaaTa
+ for (uint8_t i=0; i < STROBE_LINES; ++i) {
+ for(uint8_t j=0; j<MUXES_COUNT; ++j) {
+ if ( usb_keymap[i] & (1 << j) ) {
+ uint8_t key = (i << MUXES_COUNT_XSHIFT) + j;
+
+ // Add to the Macro processing buffer
+ // Automatically handles converting to a USB code and sending off to the PC
+ bufferAdd( key );
+
+ if(usb_dirty) {
+ printHex( key );
+ print(" ");
+ }
+ }
+ }
+ }
+ if(usb_dirty) print("\n");
+ usb_keyboard_send();
+}
+
+
+void dump(void) {
+
+ if(!dump_count) { // we don't want to debug-out during the measurements.
+
+ for(int i =0; i< KEY_COUNT; ++i) {
+ if(!(i & 0x0f)) {
+ print("\n");
+ } else if (!(i & 0x07)) {
+ print(" ");
+ }
+ print(" ");
+ //printHex (keys_averages[(i >> MUXES_COUNT_XSHIFT) + (i & STROBE_LINES_MASK) ]);
+ printHex (keys_averages[i]);
+ }
+
+ print("\n");
+
+ for(int i =0; i< KEY_COUNT; ++i) {
+ if(!(i & 0x0f)) {
+ print("\n");
+ } else if (!(i & 0x07)) {
+ print(" ");
+ }
+ print(" ");
+ //printHex (keys_averages[(i >> MUXES_COUNT_XSHIFT) + (i & STROBE_LINES_MASK) ]);
+ //printHex (keys_averages_acc[i]);
+ printHex(full_samples[i]);
+ }
+ }
+
+
+ //}
+
+// uint8_t cur_strober = 0xe;
+ uint8_t cur_strober = ze_strober;
+ print("\n");
+
+ printHex(cur_strober);
+ //print(": ");
+ print(": ");
+#if 1
+ print("\n");
+ for (uint8_t i=0; i < MUXES_COUNT; ++i) {
+ print(" ");
+ printHex(full_samples[(cur_strober << MUXES_COUNT_XSHIFT) + i]);
+ }
+
+ print("\n");
+// printHex(threshold);
+// print(": ");
+
+ for (uint8_t i=0; i < MUXES_COUNT; ++i) {
+ print(" ");
+ printHex(keys_averages[(cur_strober << MUXES_COUNT_XSHIFT) + i]);
+ }
+
+#endif
+ /*
+ for (uint8_t i=0; i< SAMPLES; ++i) {
+ print(" ");
+ printHex(samples[i]);
+ //printHex(ADC);
+ }*/
+ //print(" : ");
+ //dPrint((was_active)?" ":"*");
+
+ //printHex(keymap[TEST_KEY_STROBE] & TEST_KEY_MASK);
+ /*print(" "); */
+ //printHex(keymap[TEST_KEY_STROBE]);
+
+
+ //print("\n");
+ //print(":");
+ //printHex(full_av);
+ //printHex(count);
+ //print(" : ");
+ print("\n");
+
+ for (uint8_t i=0; i < STROBE_LINES; ++i) {
+ printHex(cur_keymap[i]);
+ print(" ");
+
+ //print(" ");
+ }
+
+
+ //print(": ");
+ //printHex(adc_strobe_averages[ze_strober]);
+ //print(" ");
+
+
+
+ for (uint8_t i=0; i < MUXES_COUNT; ++i) {
+ print(" ");
+ //printHex(adc_mux_averages[i] + adc_strobe_averages[ze_strober] - full_av);
+ //printHex((adc_mux_averages[i] + adc_strobe_averages[ze_strober]) >> 1);
+ //printHex((adc_mux_averages[i] * 3 + adc_strobe_averages[ze_strober]) >> 2);
+ //printHex(adc_mux_averages[i] + threshold);
+ //printHex(gsamples[i + SAMPLE_OFFSET] - (adc_mux_averages[i] + threshold) + 0x100);
+ //printHex(keys_averages[(ze_strober << MUXES_COUNT_XSHIFT) + i] + (uint8_t)threshold);
+ printHex(keys_averages[(ze_strober << MUXES_COUNT_XSHIFT) + i]);
+ }
+
+ if(error) {
+ print(" ");
+ printHex(error);
+ print(" ");
+ printHex(error_data);
+ error = 0;
+ error_data = 0;
+ }
+ //print("\n");
+
+ ze_strober++;
+ ze_strober &= 0xf;
+
+
+ dump_count++;
+ dump_count &= 0x0f;
+
+
+
+ //ze_strobe = (1 << (ze_strober ) );
+
+
+
+ //printHex(ADCSRA);
+ //print(" ");
+ //print("\n");
+}
+