diff --git a/Makefile b/Makefile index 3672962..4f86164 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ TARGET = main SRC = $(TARGET).c \ print.c \ usb_keyboard_debug.c \ + scan_loop.c #usb_keyboard.c diff --git a/keymap.h b/keymap.h new file mode 100644 index 0000000..a0a0739 --- /dev/null +++ b/keymap.h @@ -0,0 +1,228 @@ +#ifndef __KEYMAP_h +#define __KEYMAP_h + +#include "usb_keys.h" + +// Modifier Mask +#define MODIFIERS_KEYPAD 0 +#define MODIFIERS_KEYBOARD 4 +static uint8_t keypad_modifierMask[] = {}; +static uint8_t keyboard_modifierMask[] = { 1, 17, 33, 49 }; +static uint8_t alternate_modifierMask[] = { 1, 17, 33, 49, 62 }; + +// Default 1-indexed key mappings +static uint8_t keypadDefaultMap[] = { 0, + KEYPAD_7, + KEYPAD_8, + KEYPAD_9, + KEYPAD_SLASH, + KEYPAD_4, + KEYPAD_5, + KEYPAD_6, + KEYPAD_ASTERIX, + KEYPAD_1, + KEYPAD_2, + KEYPAD_3, + KEYPAD_MINUS, + KEYPAD_ENTER, + KEYPAD_0, + KEYPAD_PERIOD, + KEYPAD_PLUS }; + +static uint8_t defaultMap[] = { 0, + KEY_GUI, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSLASH, + KEY_TILDE, + KEY_BACKSPACE, + KEY_ALT, + KEY_TAB, + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFT_BRACE, + KEY_RIGHT_BRACE, + KEY_DELETE, + KEY_UP, + KEY_CTRL, + KEY_CAPS_LLOCK, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_QUOTE, + KEY_ENTER, + KEY_DOWN, + KEY_ESC, + KEY_LEFT_SHIFT, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_RIGHT_SHIFT, + KEY_LEFT, + KEY_RIGHT, + KEY_SPACE }; + +static uint8_t navigationMap[] = { 0, + KEY_GUI, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_INSERT, + KEY_DELETE, + KEY_BACKSPACE, + KEY_ALT, + KEY_CAPS_LOCK, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_SYSREQ_ATT, + KEY_SCROLL_LOCK, + KEY_PAUSE, + KEY_UP, + 0, + 0, + 0, + KEY_CTRL, + KEY_CAPS_LLOCK, + 0, + 0, + 0, + 0, + 0, + KEYPAD_ASTERIX, + KEYPAD_SLASH, + KEY_HOME, + KEY_PAGE_UP, + KEY_LEFT, + KEY_RIGHT, + KEY_ENTER, + 0, + KEY_ESC, + KEY_LEFT_SHIFT, + 0, + 0, + 0, + 0, + 0, + KEYPAD_PLUS, + KEYPAD_MINUS, + KEY_END, + KEY_PAGE_DOWN, + KEY_DOWN, + KEY_RIGHT_SHIFT, + 165, + KEY_RIGHT_ALT, + KEY_SPACE }; + +static uint8_t colemakMap[] = { 0, + KEY_GUI, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSLASH, + KEY_TILDE, + KEY_BACKSPACE, + KEY_ALT, + KEY_TAB, + KEY_Q, + KEY_W, + KEY_F, + KEY_P, + KEY_G, + KEY_J, + KEY_L, + KEY_U, + KEY_Y, + KEY_SEMICOLON, + KEY_LEFT_BRACE, + KEY_RIGHT_BRACE, + KEY_DELETE, + KEY_PAGE_UP, + KEY_CTRL, + KEY_CAPS_LLOCK, + KEY_A, + KEY_R, + KEY_S, + KEY_T, + KEY_D, + KEY_H, + KEY_N, + KEY_E, + KEY_I, + KEY_O, + KEY_QUOTE, + KEY_ENTER, + KEY_PAGE_DOWN, + KEY_ESC, + KEY_LEFT_SHIFT, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_K, + KEY_M, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_RIGHT_SHIFT, + 165, + KEY_RIGHT_ALT, + KEY_SPACE }; + +#endif + diff --git a/main.c b/main.c index 1689a9b..76abe51 100644 --- a/main.c +++ b/main.c @@ -23,7 +23,7 @@ #include #include #include -#include "usb_keys.h" +//#include "usb_keys.h" #include "scan_loop.h" //#include "layouts.h" //#include "usb_keyboard.h" @@ -35,226 +35,20 @@ #define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) -// Debouncing Defines -#define SAMPLE_THRESHOLD 110 -#define MAX_SAMPLES 127 // Max is 127, reaching 128 is very bad // Verified Keypress Defines #define USB_TRANSFER_DIVIDER 10 // 1024 == 1 Send of keypresses per second, 1 == 1 Send of keypresses per ~1 millisecond -/* -// Number of keys -#define KEYBOARD_SIZE 63 -#define KEYPAD_SIZE 16 - -// Drive Pin Defines -#define DRIVE_reg_1 PORTD -#define DRIVE_reg_2 PORTD -#define DRIVE_reg_3 PORTD -#define DRIVE_reg_4 PORTD -#define DRIVE_reg_5 PORTD -#define DRIVE_reg_6 PORTD -#define DRIVE_reg_7 PORTE -#define DRIVE_reg_8 PORTE -#define DRIVE_reg_9 PORTE -#define DRIVE_reg_10 -#define DRIVE_reg_11 -#define DRIVE_reg_12 - -#define DRIVE_pin_1 2 -#define DRIVE_pin_2 3 -#define DRIVE_pin_3 4 -#define DRIVE_pin_4 5 -#define DRIVE_pin_5 6 -#define DRIVE_pin_6 7 -#define DRIVE_pin_7 0 -#define DRIVE_pin_8 1 -#define DRIVE_pin_9 6 -#define DRIVE_pin_10 -#define DRIVE_pin_11 -#define DRIVE_pin_12 - -// Detect Pin/Group Defines -#define DETECT_group_1 1 -#define DETECT_group_2 2 -#define DETECT_group_3 3 -#define DETECT_group_4 4 -#define DETECT_group_5 5 -#define DETECT_group_6 6 -#define DETECT_group_7 7 -#define DETECT_group_8 8 -#define DETECT_group_9 9 -#define DETECT_group_10 -#define DETECT_group_11 -#define DETECT_group_12 - -#define DETECT_group_size_1 7 -#define DETECT_group_size_2 7 -#define DETECT_group_size_3 6 -#define DETECT_group_size_4 8 -#define DETECT_group_size_5 7 -#define DETECT_group_size_6 7 -#define DETECT_group_size_7 8 -#define DETECT_group_size_8 8 -#define DETECT_group_size_9 4 -#define DETECT_group_size_10 -#define DETECT_group_size_11 -#define DETECT_group_size_12 - -// Switch Codes -#define DETECT_group_array_1 {55,22,6 ,40,43,27,11} -#define DETECT_group_array_2 {56,23,7 ,41,58,26,10} -#define DETECT_group_array_3 {57,24,8 ,42,25,9} -#define DETECT_group_array_4 {54,21,5 ,39,44,28,12,59} -#define DETECT_group_array_5 {53,20,4 ,38,45,29,13} -#define DETECT_group_array_6 {52,19,3 ,37,46,30,14} -#define DETECT_group_array_7 {51,18,2 ,36,61,31,15,63} -#define DETECT_group_array_8 {50,17,1 ,35,47,32,16,62} -#define DETECT_group_array_9 {48,49,33,34} // 49/60 are the same line -#define DETECT_group_array_10 -#define DETECT_group_array_11 -#define DETECT_group_array_12 - - - -// Drive Macros (Generally don't need to be changed), except for maybe DRIVE_DETECT -// Sleep is for signal debouncing -#define DRIVE_DETECT(reg,pin,group) \ - reg &= ~(1 << pin); \ - detection(group); \ - reg |= (1 << pin); \ - _delay_us(1); - -#define DD_CASE(number) \ - case number:\ - DRIVE_DETECT(DRIVE_reg_##number, DRIVE_pin_##number, DETECT_group_##number) - -#define DD_CASE_ORD(number) \ - DD_CASE(number) \ - break; - -#define DD_CASE_END(number,var) \ - DD_CASE(number) \ - var = -1; \ - break; - - -// Updates the current detection sample and last sample bit -// Detection Macros (Probably don't need to be changed, but depending the matrix, may have to be) -// Determine if key is either normal or a modifier -#define DET_GROUP_CHECK(index,test) \ - if ( test ) { \ - keyDetectArray[groupArray[index]]++; \ - } - - -// XXX - Detection Groups -// Checks each of the specified pins, and then if press detected, determine if the key is normal or a modifier -// Inverse logic applies for the PINs - -// Used for 1 detection group (Special group) -#define DET_GROUP_1 \ - DET_GROUP_CHECK(0,!( PINB & (1 << 7) )) \ - DET_GROUP_CHECK(1,!( PINC & (1 << 0) )) \ - DET_GROUP_CHECK(2,!( PIND & (1 << 0) )) \ - DET_GROUP_CHECK(3,!( PIND & (1 << 1) )) \ - -// Used for 4 detection groups (Skips J1 P9) -#define DET_GROUP_2 \ - DET_GROUP_CHECK(0,!( PINE & (1 << 7) )) \ - DET_GROUP_CHECK(1,!( PINB & (1 << 0) )) \ - DET_GROUP_CHECK(2,!( PINB & (1 << 1) )) \ - DET_GROUP_CHECK(3,!( PINB & (1 << 2) )) \ - DET_GROUP_CHECK(4,!( PINB & (1 << 3) )) \ - DET_GROUP_CHECK(5,!( PINB & (1 << 4) )) \ - DET_GROUP_CHECK(6,!( PINB & (1 << 5) )) \ - -// Used for 1 detection group (Skips J1 P6 and J1 P9) -#define DET_GROUP_3 \ - DET_GROUP_CHECK(0,!( PINE & (1 << 7) )) \ - DET_GROUP_CHECK(1,!( PINB & (1 << 0) )) \ - DET_GROUP_CHECK(2,!( PINB & (1 << 1) )) \ - DET_GROUP_CHECK(3,!( PINB & (1 << 2) )) \ - DET_GROUP_CHECK(4,!( PINB & (1 << 4) )) \ - DET_GROUP_CHECK(5,!( PINB & (1 << 5) )) \ - -// Used for 3 detection groups (No skips, except special group 1) -#define DET_GROUP_4 \ - DET_GROUP_CHECK(0,!( PINE & (1 << 7) )) \ - DET_GROUP_CHECK(1,!( PINB & (1 << 0) )) \ - DET_GROUP_CHECK(2,!( PINB & (1 << 1) )) \ - DET_GROUP_CHECK(3,!( PINB & (1 << 2) )) \ - DET_GROUP_CHECK(4,!( PINB & (1 << 3) )) \ - DET_GROUP_CHECK(5,!( PINB & (1 << 4) )) \ - DET_GROUP_CHECK(6,!( PINB & (1 << 5) )) \ - DET_GROUP_CHECK(7,!( PINB & (1 << 6) )) \ - -// Combines the DET_GROUP_Xs above for the given groupArray -#define DET_GROUP(group,det_group) \ - case group: \ - { \ - uint8_t groupArray[DETECT_group_size_##group] = DETECT_group_array_##group; \ - _delay_us(1); \ - DET_GROUP_##det_group \ - } \ - break; - - -// Loop over all of the sampled keys of the given array -// If the number of samples is higher than the sample threshold, flag the high bit, clear otherwise -// This should be resetting VERY quickly, cutting off a potentially valid keypress is not an issue -#define DEBOUNCE_ASSESS(table,size) \ - for ( uint8_t key = 1; key < size + 1; key++ ) {\ - table[key] = ( table[key] & ~(1 << 7) ) > SAMPLE_THRESHOLD ? (1 << 7) : 0x00; \ - } \ - - -// Keypad detection -// Each switch has it's own detection line, inverse logic -#define KEYPAD_DETECT(test,switch_code) \ - if ( !(test) ) { \ - keypadDetectArray[switch_code]++; \ - } \ - - -// NOTE: Highest Bit: Valid keypress (0x80 is valid keypress) -// Other Bits: Pressed state sample counter -uint8_t keyboardDetectArray[KEYBOARD_SIZE + 1]; - -// Interrupt Variables -uint16_t sendKeypressCounter = 0; -volatile uint8_t sendKeypresses = 0; - - -void detection( int group ) -{ - // XXX Modify for different detection groups <-> groupArray mappings - switch ( group ) { - DET_GROUP(1,2) - DET_GROUP(2,2) - DET_GROUP(3,3) - DET_GROUP(4,4) - DET_GROUP(5,2) - DET_GROUP(6,2) - DET_GROUP(7,4) - DET_GROUP(8,4) - DET_GROUP(9,1) - } -} -*/ - // Error LED Control void errorLED( uint8_t on ) { // Error LED On if ( on ) { - DDRD |= (1<<6); PORTD |= (1<<6); } // Error LED Off else { - DDRD &= ~(1<<6); PORTD &= ~(1<<6); } } @@ -282,39 +76,6 @@ inline void pinSetup(void) PORTE = 0x00; PORTF = 0x00; } -/* -// Given a sampling array, and the current number of detected keypress -// Add as many keypresses from the sampling array to the USB key send array as possible. -void keyPressDetection( uint8_t *keys, uint8_t *validKeys, uint8_t numberOfKeys, uint8_t *modifiers, uint8_t numberOfModifiers, uint8_t *map ) { - for ( uint8_t key = 0; key < numberOfKeys + 1; key++ ) { - if ( keys[key] & (1 << 7) ) { - pint8( key ); - //print(" "); - uint8_t modFound = 0; - - // Determine if the key is a modifier - for ( uint8_t mod = 0; mod < numberOfModifiers; mod++ ) { - // Modifier found - if ( modifiers[mod] == key ) { - keyboard_modifier_keys |= map[key]; - modFound = 1; - break; - } - } - if ( modFound ) - continue; - - // Too many keys - if ( *validKeys == 6 ) - break; - - // Allow ignoring keys with 0's - if ( map[key] != 0 ) - keyboard_keys[(*validKeys)++] = map[key]; - } - } -} -*/ int main( void ) { @@ -340,117 +101,22 @@ int main( void ) TCCR0B = 0x03; TIMSK0 = (1 << TOIE0); + uint16_t led = 0; // Main Detection Loop while ( 1 ) { - scan_loop(); + //scan_loop(); // Loop should never get here (indicate error) errorLED( 1 ); - // TODO HID Debug message + // HID Debug Error message + erro_print("Detection loop error, this is very bad...bug report!"); } } -/* - int8_t group = 1; - uint8_t count = 0; - for ( ;;group++ ) { - // XXX Change number of ORDs if number of lines (RowsxColumns) differ - // Determine which keys are being pressed - switch ( group ) { - DD_CASE_ORD(1) - DD_CASE_ORD(2) - DD_CASE_ORD(3) - DD_CASE_ORD(4) - DD_CASE_ORD(5) - DD_CASE_ORD(6) - DD_CASE_ORD(7) - DD_CASE_ORD(8) - DD_CASE_END(9,group) - } - - // Check all Keyboard keys first - if ( group != -1 ) - continue; - - // Check Keypad keys - KEYPAD_DETECT(PINA & (1 << 0),11) - KEYPAD_DETECT(PINA & (1 << 1),3) - KEYPAD_DETECT(PINA & (1 << 2),7) - KEYPAD_DETECT(PINA & (1 << 3),4) - KEYPAD_DETECT(PINA & (1 << 4),15) - KEYPAD_DETECT(PINA & (1 << 5),6) - KEYPAD_DETECT(PINA & (1 << 6),2) - KEYPAD_DETECT(PINA & (1 << 7),10) - KEYPAD_DETECT(PINF & (1 << 0),8) - KEYPAD_DETECT(PINF & (1 << 1),12) - KEYPAD_DETECT(PINF & (1 << 2),16) - KEYPAD_DETECT(PINF & (1 << 3),13) - KEYPAD_DETECT(PINF & (1 << 4),1) - KEYPAD_DETECT(PINF & (1 << 5),5) - KEYPAD_DETECT(PINF & (1 << 6),9) - KEYPAD_DETECT(PINF & (1 << 7),14) - - // Check count to see if the sample threshold may have been reached, otherwise collect more data - count++; - if ( count < MAX_SAMPLES ) - continue; - - // Reset Sample Counter - count = 0; - - // Assess debouncing sample table - DEBOUNCE_ASSESS(keyDetectArray,KEYBOARD_SIZE) - DEBOUNCE_ASSESS(keypadDetectArray,KEYPAD_SIZE) - - // Send keypresses over USB if the ISR has signalled that it's time - if ( !sendKeypresses ) - continue; - - // Detect Valid Keypresses - TODO - uint8_t validKeys = 0; - - uint8_t *keyboard_MODMASK = keyboard_modifierMask; - uint8_t keyboard_NUMMODS = MODIFIERS_KEYBOARD; - uint8_t *keyboard_MAP = defaultMap; - uint8_t *keypad_MODMASK = keypad_modifierMask; - uint8_t keypad_NUMMODS = MODIFIERS_KEYPAD; - uint8_t *keypad_MAP = keypadDefaultMap; - - // Map selection - CapsLock FN - if ( keyDetectArray[34] & (1 << 7) ) { // CapsLock FN Modifier - keyboard_MAP = colemakMap; - keyboard_MODMASK = alternate_modifierMask; - keyboard_NUMMODS = 5; - - // Function Key - if ( keyDetectArray[61] & (1 << 7) ) { - keyboard_MAP = navigationMap; - } - } - - keyPressDetection( keyDetectArray, &validKeys, KEYBOARD_SIZE, keyboard_MODMASK, keyboard_NUMMODS, keyboard_MAP ); - keyPressDetection( keypadDetectArray, &validKeys, KEYPAD_SIZE, keypad_MODMASK, keypad_NUMMODS, keypad_MAP ); - //print(":\n"); - - // TODO undo potentially old keys - for ( uint8_t c = validKeys; c < 6; c++ ) - keyboard_keys[c] = 0; - - // Send keypresses - usb_keyboard_send(); - - // Clear sendKeypresses Flag - sendKeypresses = 0; - - // Clear modifiers - keyboard_modifier_keys = 0; - } - - return 0; -} -*/ // Timer Interrupt for flagging a send of the sampled key detection data to the USB host +uint16_t sendKeypressCounter = 0; + ISR( TIMER0_OVF_vect ) { sendKeypressCounter++; diff --git a/matrix.c b/matrix.c new file mode 100644 index 0000000..8bf3f62 --- /dev/null +++ b/matrix.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2011 by Jacob Alexander + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "matrix.h" + +#define REG_SET(reg) reg |= (1 << ( matrix[row][col] % 10 ) ) + +#define PIN_SET_COL(pin) \ + switch ( scanMode ) { \ + case scanCol: \ + case scanCol_powrRow: \ + case scanDual: \ + REG_SET(port##pin); break; \ + case scanRow_powrCol: REG_SET(ddr##pin); REG_SET(port##pin); break; \ + } \ + break + +#define PIN_SET_ROW(pin) \ + switch ( scanMode ) { \ + case scanRow: \ + case scanRow_powrCol: \ + case scanDual: \ + REG_SET(port##pin); break; \ + case scanCol_powrRow: REG_SET(ddr##pin); REG_SET(port##pin); break; \ + } \ + break + +#define PIN_CASE(pinLetter) \ + case pin##pinLetter##0: \ + case pin##pinLetter##1: \ + case pin##pinLetter##2: \ + case pin##pinLetter##3: \ + case pin##pinLetter##4: \ + case pin##pinLetter##5: \ + case pin##pinLetter##6: \ + case pin##pinLetter##7 + +#define PIN_TEST_COL(pin) \ + if ( !( pin & ( 1 << ( matrix[0][col] % 10 ) ) \ + detectArray[matrix[row][col]]++; \ + break + + +void matrix_pinSetup( uint8_t *matrix ) +{ + // Setup the variables + uint8_t portA = 0x00; + uint8_t portB = 0x00; + uint8_t portC = 0x00; + uint8_t portD = 0x00; + uint8_t portE = 0x00; + uint8_t portF = 0x00; + + uint8_t ddrA = 0x00; + uint8_t ddrB = 0x00; + uint8_t ddrC = 0x00; + uint8_t ddrD = 0x00; + uint8_t ddrE = 0x00; + uint8_t ddrF = 0x00; + + // Loop through all the pin assignments, for the initial pin settings + int row, col; + + // Rows + for ( row = 1; row < sizeof(matrix); row++ ) { + switch ( matrix[row][col] ) { + PIN_CASE(A): + PIN_SET_ROW(A); + PIN_CASE(B): + PIN_SET_ROW(B); + PIN_CASE(C): + PIN_SET_ROW(C); + PIN_CASE(D): + PIN_SET_ROW(D); + PIN_CASE(E): + PIN_SET_ROW(E); + PIN_CASE(F): + PIN_SET_ROW(F); + + default: + continue; + } + } + + // Columns + for ( col = 1; col < sizeof(matrix[0]); row++ ) { + switch ( matrix[row][col] ) { + PIN_CASE(A): + PIN_SET_COL(A); + PIN_CASE(B): + PIN_SET_COL(B); + PIN_CASE(C): + PIN_SET_COL(C); + PIN_CASE(D): + PIN_SET_COL(D); + PIN_CASE(E): + PIN_SET_COL(E); + PIN_CASE(F): + PIN_SET_COL(F); + + default: + continue; + } + } + + // Setting the pins + DDRA = ddrA; + DDRB = ddrB; + DDRC = ddrC; + DDRD = ddrD; + DDRE = ddrE; + DDRF = ddrF; + + PORTA = portA; + PORTB = portB; + PORTC = portC; + PORTD = portD; + PORTE = portE; + PORTF = portF; +} + +// TODO Proper matrix scanning +void matrix_scan( uint8_t *matrix, uint8_t *detectArray ) +{ + // Column Scan +#if scanMode == scanCol + uint8_t col = 1; + uint8_t row = 1; + for ( ; col < sizeof(matrix[1]); col++ ) { + switch ( matrix[0][col] / 10 ) { + case 0: // PINA + PIN_TEST_COL(PINA); + case 1: // PINB + PIN_TEST_COL(PINB); + case 2: // PINC + PIN_TEST_COL(PINC); + case 3: // PIND + PIN_TEST_COL(PIND); + case 4: // PINE + PIN_TEST_COL(PINE); + case 5: // PINF + PIN_TEST_COL(PINF); + } + } +#endif + + // Row Scan +#if scanMode == scanRow +#endif + + // Column Scan, Power Row +#if scanMode == scanCol_powrRow +#endif + + // Row Scan, Power Column +#if scanMode == scanRow_powrCol +#endif + + // Dual Scan +#if scanMode == scanDual +#endif +} + diff --git a/matrix.h b/matrix.h new file mode 100644 index 0000000..4b728df --- /dev/null +++ b/matrix.h @@ -0,0 +1,151 @@ +/* Copyright (C) 2011 by Jacob Alexander + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MATRIX_H +#define __MATRIX_H + +// ----- Quick Map (don't change) ----- +#define pinA0 0 +#define pinA1 1 +#define pinA2 2 +#define pinA3 3 +#define pinA4 4 +#define pinA5 5 +#define pinA6 6 +#define pinA7 7 + +#define pinB0 10 +#define pinB1 11 +#define pinB2 12 +#define pinB3 13 +#define pinB4 14 +#define pinB5 15 +#define pinB6 16 +#define pinB7 17 + +#define pinC0 20 +#define pinC1 21 +#define pinC2 22 +#define pinC3 23 +#define pinC4 24 +#define pinC5 25 +#define pinC6 26 +#define pinC7 27 + +#define pinD0 30 +#define pinD1 31 +#define pinD2 32 +#define pinD3 33 +#define pinD4 34 +#define pinD5 35 +#define pinD6 36 +#define pinD7 37 + +#define pinE0 40 +#define pinE1 41 +#define pinE2 42 +#define pinE3 43 +#define pinE4 44 +#define pinE5 45 +#define pinE6 46 +#define pinE7 47 + +#define pinF0 50 +#define pinF1 51 +#define pinF2 52 +#define pinF3 53 +#define pinF4 54 +#define pinF5 55 +#define pinF6 56 +#define pinF7 57 + +#define pinNULL 128 + + + +// ----- Scan Mode (usually dual-scan) ----- +// Ordered by increasing memory/CPU usage +#define scanRow 0 // Needed for powered switches (Hall-Effect) +#define scanCol 1 // Opposite of scanRow +#define scanRow_powrCol 2 // NKRO supported (simple detection) +#define scanCol_powrRow 3 // Opposite of scanRow_powrCol +#define scanDual 4 // Typical ~2KRO matrix + + + +// ----- Scan Mode Setting ----- +#define scanMode scanCol + + + +// ----- Key Settings ----- +#define keyboardSize 16 // # of keys + + + +// ----- Matrix Configuration ----- +static uint8_t matrix_pinout[][] = { + + + +// Just layout the matrix by rows and columns +// Usually you'll want to set the scanMode above to scanDual or scanCol_powrRow/scanRow_powrCol +// The mode allows for optimization in the kind of scanning algorithms that are done +// +// The key numbers are used to translate into the keymap table (array) (and always start from 1, not 0). +// See the keymap.h file for the various preconfigured arrays. + +// Scan Mode | Col 1 | Col 2 | Col 3 | Col 4 | Col 4 | ... +// ------------------------------------------------------- +// Row 1 | Key 1 Key 7 Key32 ... +// Row 2 | Key 3 Key92 ... +// Row 3 | Key23 ... +// Row 4 | ... +// Row 5 | +// ... | + + + { scanMode, pinF4, pinA6, pinA1, pinA3, pinF5, pinA5, pinA2, pinF0, pinF6, pinA7, pinA0, pinF1, pinF3, pinF7, pinA4, pinF2 }, + { pinNULL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + + +// Example Rows +//{ pinE0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, +//{ pinE1, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, }, + + +}; + + +// ----- Variables ----- + +// NOTE: Highest Bit: Valid keypress (0x80 is valid keypress) +// Other Bits: Pressed state sample counter +uint8_t keyboardDetectArray[keyboardSize + 1]; + + + +// ----- Functions ----- + + +#endif // __MATRIX_H + + diff --git a/print.c b/print.c index b49a1dd..e721ec4 100644 --- a/print.c +++ b/print.c @@ -1,6 +1,4 @@ -/* Very basic print functions, intended to be used with usb_debug_only.c - * http://www.pjrc.com/teensy/ - * Copyright (c) 2008 PJRC.COM, LLC +/* Copyright (C) 2011 by Jacob Alexander * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,54 +19,172 @@ * THE SOFTWARE. */ -// Version 1.0: Initial Release +// Compiler Includes +#include +// AVR Includes #include #include +// Project Includes #include "print.h" -void print_P(const char *s) +// Defines + + +// USB HID String Output +void usb_debug_putstr( char* s ) +{ + while ( *s != '\0' ) + usb_debug_putchar( *s++ ); +} + +// Multiple string Output +void usb_debug_putstrs( char* first, ... ) +{ + // Initialize the variadic function parameter list + va_list ap; + + // Get the first parameter + va_start( ap, first ); + char *cur = first; + + // Loop through the variadic list until "\0\0\0" is found + while ( !( cur[0] == '\0' && cur[1] == '\0' && cur[2] == '\0' ) ) + { + // Print out the given string + usb_debug_putstr( cur ); + + // Get the next argument ready + cur = va_arg( ap, char* ); + } + + va_end( ap ); // Not required, but good practice +} + +// Print a constant string +void _print(const char *s) { char c; - while (1) { - c = pgm_read_byte(s++); - if (!c) break; - if (c == '\n') usb_debug_putchar('\r'); + // Acquire the character from flash, and print it, as long as it's not NULL + // Also, if a newline is found, print a carrige return as well + while ( ( c = pgm_read_byte(s++) ) != '\0' ) + { + if ( c == '\n' ) + usb_debug_putchar('\r'); usb_debug_putchar(c); } } -void phex1(unsigned char c) + + + +// String Functions +void int8ToStr( uint8_t in, char* out ) { - usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10)); -} + // Position and sign containers + uint8_t pos; + pos = 0; -void phex(unsigned char c) -{ - phex1(c >> 4); - phex1(c & 15); -} + // Evaluate through digits as decimal + do + { + out[pos++] = in % 10 + '0'; + } + while ( (in /= 10) > 0 ); -void phex16(unsigned int i) -{ - phex(i >> 8); - phex(i); -} + // Append null + out[pos] = '\0'; -void pint8(unsigned char c) -{ - // 100's - if ( c > 99 ) - usb_debug_putchar( c / 100 + '0' ); - - // 10's - Note: Uses dropping of decimal of float/double types - if ( c > 9 ) - usb_debug_putchar( c / 10 - (c / 100) * 10 + '0' ); - - // 1's - usb_debug_putchar( c % 10 + '0' ); + // Reverse the string to the correct order + revsStr(out); } +void int16ToStr( uint16_t in, char* out ) +{ + // Position and sign containers + uint16_t pos; + pos = 0; + + // Evaluate through digits as decimal + do + { + out[pos++] = in % 10 + '0'; + } + while ( (in /= 10) > 0 ); + + // Append null + out[pos] = '\0'; + + // Reverse the string to the correct order + revsStr(out); +} + + +void hexToStr_op( uint16_t in, char* out, uint8_t op ) +{ + // Position container + uint16_t pos = 0; + + // Evaluate through digits as hex + do + { + uint16_t cur = in % 16; + out[pos++] = cur + (( cur < 10 ) ? '0' : 'A' - 10); + } + while ( (in /= 16) > 0 ); + + // Output formatting options + switch ( op ) + { + case 1: // Add 0x + out[pos++] = 'x'; + out[pos++] = '0'; + break; + case 2: // 8-bit padding + case 4: // 16-bit padding + while ( pos < op ) + out[pos++] = '0'; + break; + } + + // Append null + out[pos] = '\0'; + + // Reverse the string to the correct order + revsStr(out); +} + + +void revsStr( char* in ) +{ + // Iterators + int i, j; + + // Temp storage + char c; + + // Loop through the string, and reverse the order of the characters + for ( i = 0, j = lenStr( in ) - 1; i < j; i++, j-- ) + { + c = in[i]; + in[i] = in[j]; + in[j] = c; + } +} + + +uint16_t lenStr( char* in ) +{ + // Iterator + char *pos; + + // Loop until null is found + for ( pos = in; *pos; pos++ ); + + // Return the difference between the pointers of in and pos (which is the string length) + return (pos - in); +} + diff --git a/print.h b/print.h index 1415792..f792623 100644 --- a/print.h +++ b/print.h @@ -1,17 +1,87 @@ +/* Copyright (C) 2011 by Jacob Alexander + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #ifndef print_h__ #define print_h__ +// AVR Includes #include + +// Project Includes #include "usb_keyboard_debug.h" -// this macro allows you to write print("some text") and -// the string is automatically placed into flash memory :) -#define print(s) print_P(PSTR(s)) -#define pchar(c) usb_debug_putchar(c) +// Defines +#define NL "\r\n" -void print_P(const char *s); -void phex(unsigned char c); -void phex16(unsigned int i); -void pint8(unsigned char c); + +/* XXX + * Note that all the variadic functions below, take comma separated string lists, they are purposely not printf style (simplicity) + */ + +// Function Aliases +#define dPrint(c) usb_debug_putchar(c) +#define dPrintStr(c) usb_debug_putstr (c) +#define dPrintStrs(...) usb_debug_putstrs(__VA_ARGS__, "\0\0\0") // Convenience Variadic Macro +#define dPrintStrNL(c) dPrintStrs (c, NL) // Appends New Line Macro +#define dPrintStrsNL(...) usb_debug_putstrs(__VA_ARGS__, NL, "\0\0\0") // Appends New Line Macro + +// Special Msg Constructs (Uses VT100 tags) +#define dPrintMsg(colour_code_str,msg,...) \ + usb_debug_putstrs("\033[", colour_code_str, "m", msg, "\033[0m - ", __VA_ARGS__, NL, "\0\0\0") +#define printMsg(colour_code_str,msg,str) \ + print("\033[" colour_code_str "m" msg "\033[0m - " str NL) + +// Info Messages +#define info_dPrint(...) dPrintMsg ("1;32", "INFO", __VA_ARGS__) // Info Msg +#define info_print(str) printMsg ("1;32", "INFO", str) // Info Msg + +// Warning Messages +#define warn_dPrint(...) dPrintMsg ("1;33", "WARNING", __VA_ARGS__) // Warning Msg +#define warn_print(str) printMsg ("1;33", "WARNING", str) // Warning Msg + +// Error Messages +#define erro_dPrint(...) dPrintMsg ("1;5;31", "ERROR", __VA_ARGS__) // Error Msg +#define erro_print(str) printMsg ("1;5;31", "ERROR", str) // Error Msg + +// Debug Messages +#define dbug_dPrint(...) dPrintMsg ("1;35", "DEBUG", __VA_ARGS__) // Debug Msg +#define dbug_print(str) printMsg ("1;35", "DEBUG", str) // Debug Msg + +// Static String Printing +#define print(s) _print(PSTR(s)) + +void _print(const char *s); +void usb_debug_putstr( char* s ); +void usb_debug_putstrs( char* first, ... ); + + + +// String Functions +#define hexToStr(hex, out) hexToStr_op(hex, out, 1) + +void int8ToStr ( uint8_t in, char* out ); +void int16ToStr ( uint16_t in, char* out ); +void hexToStr_op( uint16_t in, char* out, uint8_t op ); +void revsStr ( char* in ); +uint16_t lenStr ( char* in ); #endif + diff --git a/scan_loop.c b/scan_loop.c new file mode 100644 index 0000000..69b3084 --- /dev/null +++ b/scan_loop.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2011 by Jacob Alexander + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include +#include "usb_keyboard_debug.h" +#include "keymap.h" +// Debouncing Defines +#define SAMPLE_THRESHOLD 110 +#define MAX_SAMPLES 127 // Max is 127, reaching 128 is very bad +// Loop over all of the sampled keys of the given array +// If the number of samples is higher than the sample threshold, flag the high bit, clear otherwise +// This should be resetting VERY quickly, cutting off a potentially valid keypress is not an issue +#define DEBOUNCE_ASSESS(table,size) \ + for ( uint8_t key = 1; key < size + 1; key++ ) {\ + table[key] = ( table[key] & ~(1 << 7) ) > SAMPLE_THRESHOLD ? (1 << 7) : 0x00; \ + } \ + +// NOTE: Highest Bit: Valid keypress (0x80 is valid keypress) +// Other Bits: Pressed state sample counter +#define KEYBOARD_SIZE 23 +uint8_t keyboardDetectArray[KEYBOARD_SIZE + 1]; + +// Interrupt Variable +volatile uint8_t sendKeypresses = 0; + +// USB Data Send +void usb_send( uint8_t validKeys ) +{ + // TODO undo potentially old keys + for ( uint8_t c = validKeys; c < 6; c++ ) + keyboard_keys[c] = 0; + + // Send keypresses + usb_keyboard_send(); + + // Clear sendKeypresses Flag + sendKeypresses = 0; + + // Clear modifiers + keyboard_modifier_keys = 0; +} + + +// Given a sampling array, and the current number of detected keypress +// Add as many keypresses from the sampling array to the USB key send array as possible. +void keyPressDetection( uint8_t *keys, uint8_t *validKeys, uint8_t numberOfKeys, uint8_t *modifiers, uint8_t numberOfModifiers, uint8_t *map ) { + for ( uint8_t key = 0; key < numberOfKeys + 1; key++ ) { + if ( keys[key] & (1 << 7) ) { + pint8( key ); + //print(" "); + uint8_t modFound = 0; + + // Determine if the key is a modifier + for ( uint8_t mod = 0; mod < numberOfModifiers; mod++ ) { + // Modifier found + if ( modifiers[mod] == key ) { + keyboard_modifier_keys |= map[key]; + modFound = 1; + break; + } + } + if ( modFound ) + continue; + + // Too many keys + if ( *validKeys == 6 ) + break; + + // Allow ignoring keys with 0's + if ( map[key] != 0 ) + keyboard_keys[(*validKeys)++] = map[key]; + } + } +} + + +// Main Detection Loop +void scan_loop( void ) +{ + //matrix_pinSetup( matrix_pinout ); + uint8_t count = 0; + + for ( ;; ) { + //matrix_scan( matrix_pinout, keyboardDetectArray ); + + // Check count to see if the sample threshold may have been reached, otherwise collect more data + if ( count++ < MAX_SAMPLES ) + continue; + + // Reset Sample Counter + count = 0; + + // Assess debouncing sample table + //DEBOUNCE_ASSESS(keyDetectArray,KEYBOARD_SIZE) + + // Send keypresses over USB if the ISR has signalled that it's time + if ( !sendKeypresses ) + continue; + + // Layout Setup + uint8_t validKeys = 0; + + uint8_t *keyboard_MODMASK = keyboard_modifierMask; + uint8_t keyboard_NUMMODS = MODIFIERS_KEYBOARD; + uint8_t *keyboard_MAP = defaultMap; + + // TODO Layout Switching + + // TODO Macro Processing + + // Debounce Sampling Array to USB Data Array + keyPressDetection( keyboardDetectArray, &validKeys, KEYBOARD_SIZE, keyboard_MODMASK, keyboard_NUMMODS, keyboard_MAP ); + + // Send USB Data + usb_send( validKeys ); + } +} + diff --git a/scan_loop.h b/scan_loop.h new file mode 100644 index 0000000..52c358d --- /dev/null +++ b/scan_loop.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2011 by Jacob Alexander + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __SCAN_LOOP_H +#define __SCAN_LOOP_H + +//extern uint8_t keyboardDetectArray[KEYBOARDZ +extern volatile uint8_t sendKeypresses; + +void scan_loop( void ); + +#endif // __SCAN_LOOP_H + diff --git a/sload b/sload new file mode 100755 index 0000000..26b2f24 --- /dev/null +++ b/sload @@ -0,0 +1,8 @@ +#!/bin/bash + +#| Loads the hex file onto the teensy 2.0 + +sudo teensy-loader-cli -mmcu=atmega32u4 -w Build/main.hex + +exit 0 +