- Added better string handling and canned messages - Added LED error function - Moved code around - Prepared the matrix code for multiple styles of scanning (changed at compile time)simple
SRC = $(TARGET).c \ | SRC = $(TARGET).c \ | ||||
print.c \ | print.c \ | ||||
usb_keyboard_debug.c \ | usb_keyboard_debug.c \ | ||||
scan_loop.c | |||||
#usb_keyboard.c | #usb_keyboard.c | ||||
#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 | |||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
#include <avr/interrupt.h> | #include <avr/interrupt.h> | ||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#include "usb_keys.h" | |||||
//#include "usb_keys.h" | |||||
#include "scan_loop.h" | #include "scan_loop.h" | ||||
//#include "layouts.h" | //#include "layouts.h" | ||||
//#include "usb_keyboard.h" | //#include "usb_keyboard.h" | ||||
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) | #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 | // Verified Keypress Defines | ||||
#define USB_TRANSFER_DIVIDER 10 // 1024 == 1 Send of keypresses per second, 1 == 1 Send of keypresses per ~1 millisecond | #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 <blank> | |||||
#define DRIVE_reg_11 <blank> | |||||
#define DRIVE_reg_12 <blank> | |||||
#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 <blank> | |||||
#define DRIVE_pin_11 <blank> | |||||
#define DRIVE_pin_12 <blank> | |||||
// 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 <blank> | |||||
#define DETECT_group_11 <blank> | |||||
#define DETECT_group_12 <blank> | |||||
#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 <blank> | |||||
#define DETECT_group_size_11 <blank> | |||||
#define DETECT_group_size_12 <blank> | |||||
// 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 <blank> | |||||
#define DETECT_group_array_11 <blank> | |||||
#define DETECT_group_array_12 <blank> | |||||
// 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 | // Error LED Control | ||||
void errorLED( uint8_t on ) | void errorLED( uint8_t on ) | ||||
{ | { | ||||
// Error LED On | // Error LED On | ||||
if ( on ) { | if ( on ) { | ||||
DDRD |= (1<<6); | |||||
PORTD |= (1<<6); | PORTD |= (1<<6); | ||||
} | } | ||||
// Error LED Off | // Error LED Off | ||||
else { | else { | ||||
DDRD &= ~(1<<6); | |||||
PORTD &= ~(1<<6); | PORTD &= ~(1<<6); | ||||
} | } | ||||
} | } | ||||
PORTE = 0x00; | PORTE = 0x00; | ||||
PORTF = 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 ) | int main( void ) | ||||
{ | { | ||||
TCCR0B = 0x03; | TCCR0B = 0x03; | ||||
TIMSK0 = (1 << TOIE0); | TIMSK0 = (1 << TOIE0); | ||||
uint16_t led = 0; | |||||
// Main Detection Loop | // Main Detection Loop | ||||
while ( 1 ) { | while ( 1 ) { | ||||
scan_loop(); | |||||
//scan_loop(); | |||||
// Loop should never get here (indicate error) | // Loop should never get here (indicate error) | ||||
errorLED( 1 ); | 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 | // Timer Interrupt for flagging a send of the sampled key detection data to the USB host | ||||
uint16_t sendKeypressCounter = 0; | |||||
ISR( TIMER0_OVF_vect ) | ISR( TIMER0_OVF_vect ) | ||||
{ | { | ||||
sendKeypressCounter++; | sendKeypressCounter++; |
/* 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 | |||||
} | |||||
/* 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 | |||||
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
* THE SOFTWARE. | * THE SOFTWARE. | ||||
*/ | */ | ||||
// Version 1.0: Initial Release | |||||
// Compiler Includes | |||||
#include <stdarg.h> | |||||
// AVR Includes | |||||
#include <avr/io.h> | #include <avr/io.h> | ||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
// Project Includes | |||||
#include "print.h" | #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; | 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); | 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; | |||||
// 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 phex(unsigned char c) | |||||
void int16ToStr( uint16_t in, char* out ) | |||||
{ | { | ||||
phex1(c >> 4); | |||||
phex1(c & 15); | |||||
// 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 phex16(unsigned int i) | |||||
void hexToStr_op( uint16_t in, char* out, uint8_t op ) | |||||
{ | { | ||||
phex(i >> 8); | |||||
phex(i); | |||||
// 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 pint8(unsigned char c) | |||||
void revsStr( char* in ) | |||||
{ | { | ||||
// 100's | |||||
if ( c > 99 ) | |||||
usb_debug_putchar( c / 100 + '0' ); | |||||
// Iterators | |||||
int i, j; | |||||
// 10's - Note: Uses dropping of decimal of float/double types | |||||
if ( c > 9 ) | |||||
usb_debug_putchar( c / 10 - (c / 100) * 10 + '0' ); | |||||
// Temp storage | |||||
char c; | |||||
// 1's | |||||
usb_debug_putchar( c % 10 + '0' ); | |||||
// 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); | |||||
} | |||||
/* 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__ | #ifndef print_h__ | ||||
#define print_h__ | #define print_h__ | ||||
// AVR Includes | |||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
// Project Includes | |||||
#include "usb_keyboard_debug.h" | #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" | |||||
/* 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 | |||||
void print_P(const char *s); | |||||
void phex(unsigned char c); | |||||
void phex16(unsigned int i); | |||||
void pint8(unsigned char c); | |||||
// 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 | #endif | ||||
/* 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 <stdint.h> | |||||
#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 ); | |||||
} | |||||
} | |||||
/* 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 | |||||
#!/bin/bash | |||||
#| Loads the hex file onto the teensy 2.0 | |||||
sudo teensy-loader-cli -mmcu=atmega32u4 -w Build/main.hex | |||||
exit 0 | |||||