# HG changeset patch # User Jacob Alexander # Date 1455999182 28800 # Node ID 2d286e185cff310f7948bceec685e277209092f1 # Parent 06b8d295518eef9162a87dd334a2e48939b7b4d4# Parent 060aa589b307d267a682637eb9c9c9feef6b3826 Merge pull request #93 from cryham/master Added support for ghosting matrices and code for elimination. diff -r 06b8d295518e -r 2d286e185cff Scan/CK3/defaultMap.kll --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/CK3/defaultMap.kll Sat Feb 20 12:13:02 2016 -0800 @@ -0,0 +1,85 @@ +Name = CK3; +Version = 0.3; +Author = "Crystal Hammer 2016"; +KLL = 0.3c; + +# Modified Date +Date = 2016-02-19; + + +S0x00 : U"Esc"; +S0x01 : U"1"; +S0x02 : U"2"; +S0x03 : U"3"; +S0x04 : U"4"; +S0x05 : U"5"; +S0x06 : U"6"; +S0x07 : U"7"; +S0x08 : U"8"; +S0x09 : U"9"; +S0x0A : U"0"; +S0x0B : U"Minus"; +S0x0C : U"Equal"; +S0x0D : U"Backslash"; +S0x0E : U"Backtick"; +S0x0F : U"Tab"; +S0x10 : U"Q"; +S0x11 : U"W"; +S0x12 : U"E"; +S0x13 : U"R"; +S0x14 : U"T"; +S0x15 : U"Y"; +S0x16 : U"U"; +S0x17 : U"I"; +S0x18 : U"O"; +S0x19 : U"P"; +S0x1A : U"LBrace"; +S0x1B : U"RBrace"; +S0x1C : U"Backspace"; +S0x1D : U"Ctrl"; +S0x1E : U"A"; +S0x1F : U"S"; +S0x20 : U"D"; +S0x21 : U"F"; +S0x22 : U"G"; +S0x23 : U"H"; +S0x24 : U"J"; +S0x25 : U"K"; +S0x26 : U"L"; +S0x27 : U"Semicolon"; +S0x28 : U"Quote"; +S0x29 : U"Enter"; +S0x2A : U"LShift"; +S0x2B : U"Z"; +S0x2C : U"X"; +S0x2D : U"C"; +S0x2E : U"V"; +S0x2F : U"B"; +S0x30 : U"N"; +S0x31 : U"M"; +S0x32 : U"Comma"; +S0x33 : U"Period"; +S0x34 : U"Slash"; +S0x35 : U"RShift"; +S0x36 : U"Function1"; # Fun key +S0x37 : U"Function2"; # Left Blank Key +S0x38 : U"LAlt"; +S0x39 : U"LGui"; +S0x3A : U"Space"; +S0x3B : U"RGui"; +S0x3C : U"RAlt"; +S0x3D : U"Function3"; # Right Blank Key 1 +S0x3E : U"Function4"; # Right Blank Key 2 + + +# Custom Action Examples + +# Example capability, prints to cli +action1 => CustomAction_action1_capability(); # No arguments + +# Blocks given USB Code, must be used with blockLink +# Simple example, supports only blocking a single key at a time +# Keys must be specified using numbers see Macro/PartialMap/usb_hid.h +blockHold => CustomAction_blockHold_capability( usbCode : 1 ); # Single 8-bit argument +blockKey => CustomAction_blockKey_capability( usbCode : 1 ); + diff -r 06b8d295518e -r 2d286e185cff Scan/CK3/matrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/CK3/matrix.h Sat Feb 20 12:13:02 2016 -0800 @@ -0,0 +1,54 @@ +/* Copyright (C) 2014-2015 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. + */ + +#pragma once + +// ----- Includes ----- + +// Project Includes +#include + + + +// ----- Matrix Definition ----- + +// Freescale ARM MK20's support GPIO PTA, PTB, PTC, PTD and PTE 0..31 +// Not all chips have access to all of these pins (most don't have 160 pins :P) +// +// NOTE: +// Before using a pin, make sure it supports being a GPIO *and* doesn't have a default pull-up/pull-down +// Checking this is completely on the ownness of the user + +// +// Columns (Strobe) // PTB0..3,16,17 PTC4,5 PTD0 +// Rows (Sense) // PTD1..7 + +// Define Rows (Sense) and Columns (Strobes) +GPIO_Pin Matrix_cols[] = { gpio(B,0), gpio(B,1), gpio(B,2), gpio(B,3), gpio(B,16), gpio(B,17), gpio(C,4), gpio(C,6), gpio(D,0) }; +GPIO_Pin Matrix_rows[] = { gpio(D,1), gpio(D,2), gpio(D,3), gpio(D,4), gpio(D,5), gpio(D,6), gpio(D,7) }; + +// Define type of scan matrix +Config Matrix_type = Config_Pulldown; + + +// Define this if your matrix has ghosting (i.e. regular keyboard without diodes) +// this will enable the anti-ghosting code +#define GHOSTING_MATRIX diff -r 06b8d295518e -r 2d286e185cff Scan/CK3/scan_loop.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/CK3/scan_loop.c Sat Feb 20 12:13:02 2016 -0800 @@ -0,0 +1,204 @@ +/* Copyright (C) 2014 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. + */ + +// ----- Includes ----- + +// Compiler Includes +#include + +// Project Includes +#include +#include +#include +#include +#include + +// Local Includes +#include "scan_loop.h" + + + +// ----- Function Declarations ----- + +// CLI Functions +void cliFunc_echo( char* args ); + + + +// ----- Variables ----- + +// Scan Module command dictionary +CLIDict_Entry( echo, "Example command, echos the arguments." ); + +CLIDict_Def( scanCLIDict, "Scan Module Commands" ) = { + CLIDict_Item( echo ), + { 0, 0, 0 } // Null entry for dictionary end +}; + +// Number of scans since the last USB send +uint16_t Scan_scanCount = 0; + + + +// ----- Functions ----- + +// Setup +inline void Scan_setup() +{ + // Register Scan CLI dictionary + CLI_registerDictionary( scanCLIDict, scanCLIDictName ); + + // Setup GPIO pins for matrix scanning + Matrix_setup(); + + // Reset scan count + Scan_scanCount = 0; +} + + +// Main Detection Loop +inline uint8_t Scan_loop() +{ + Matrix_scan( Scan_scanCount++ ); + + return 0; +} + + +// Signal from Macro Module that all keys have been processed (that it knows about) +inline void Scan_finishedWithMacro( uint8_t sentKeys ) +{ +} + + +// Signal from Output Module that all keys have been processed (that it knows about) +inline void Scan_finishedWithOutput( uint8_t sentKeys ) +{ + // Reset scan loop indicator (resets each key debounce state) + // TODO should this occur after USB send or Macro processing? + Scan_scanCount = 0; +} + + + +// ----- Capabilities ----- + +// Custom capability examples +// Refer to kll.h in Macros/PartialMap for state and stateType information +void CustomAction_action1_capability( uint8_t state, uint8_t stateType, uint8_t *args ) +{ + // Display capability name + // XXX This is required for debug cli to give you a list of capabilities + if ( stateType == 0xFF && state == 0xFF ) + { + print("CustomAction_action1_capability()"); + return; + } + + // Prints Action1 info message to the debug cli + info_print("Action1"); +} + +uint8_t CustomAction_blockHold_storage = 0; +void CustomAction_blockHold_capability( uint8_t state, uint8_t stateType, uint8_t *args ) +{ + // Display capability name + if ( stateType == 0xFF && state == 0xFF ) + { + print("CustomAction_blockHold_capability(usbCode)"); + return; + } + + // Retrieve 8-bit argument + uint8_t key = args[0]; + + // We only care about normal keys + if ( stateType == 0x00 ) + { + // Block given key if we're in the "Press" or "Hold" state + if ( ( state == 0x01 || state == 0x02 ) + && CustomAction_blockHold_storage == 0 ) + { + CustomAction_blockHold_storage = key; + info_msg("Blocking Key: "); + printHex( key ); + print( NL ); + } + // Release if in the "Off" or "Release" state and we're blocking + else if ( ( state == 0x00 || state == 0x03 ) + && key == CustomAction_blockHold_storage ) + { + info_msg("Unblocking Key: "); + printHex( CustomAction_blockHold_storage ); + print( NL ); + CustomAction_blockHold_storage = 0; + } + } +} + +void CustomAction_blockKey_capability( uint8_t state, uint8_t stateType, uint8_t *args ) +{ + // Display capability name + if ( stateType == 0xFF && state == 0xFF ) + { + print("CustomAction_blockKey_capability(usbCode)"); + return; + } + + // Retrieve 8-bit argument + uint8_t key = args[0]; + + // If key is not blocked, process + if ( key != CustomAction_blockHold_storage ) + { + extern void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); + Output_usbCodeSend_capability( state, stateType, &key ); + } +} + + + +// ----- CLI Command Functions ----- + +// XXX Just an example command showing how to parse arguments (more complex than generally needed) +void cliFunc_echo( char* args ) +{ + char* curArgs; + char* arg1Ptr; + char* arg2Ptr = args; + + // Parse args until a \0 is found + while ( 1 ) + { + print( NL ); // No \r\n by default after the command is entered + + curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list + CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr ); + + // Stop processing args if no more are found + if ( *arg1Ptr == '\0' ) + break; + + // Print out the arg + dPrint( arg1Ptr ); + } +} + diff -r 06b8d295518e -r 2d286e185cff Scan/CK3/scan_loop.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/CK3/scan_loop.h Sat Feb 20 12:13:02 2016 -0800 @@ -0,0 +1,48 @@ +/* Copyright (C) 2014-2015 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. + */ + +#pragma once + +// ----- Includes ----- + +// Compiler Includes +#include + + + +// ----- Functions ----- + +// Functions to be called by main.c +void Scan_setup( void ); +uint8_t Scan_loop( void ); + +// Call-backs +void Scan_finishedWithMacro( uint8_t sentKeys ); // Called by Macro Module +void Scan_finishedWithOutput( uint8_t sentKeys ); // Called by Output Module + + +// ----- Capabilities ----- + +// Example capabilities +void CustomAction_action1_capability( uint8_t state, uint8_t stateType, uint8_t *args ); +void CustomAction_blockHold_capability( uint8_t state, uint8_t stateType, uint8_t *args ); +void CustomAction_blockKey_capability( uint8_t state, uint8_t stateType, uint8_t *args ); + diff -r 06b8d295518e -r 2d286e185cff Scan/CK3/setup.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Scan/CK3/setup.cmake Sat Feb 20 12:13:02 2016 -0800 @@ -0,0 +1,32 @@ +###| CMake Kiibohd Controller Scan Module |### +# +# Written by Jacob Alexander in 2014 for the Kiibohd Controller +# +# Released into the Public Domain +# +### + + +### +# Required Submodules +# + +AddModule ( Scan MatrixARM ) + + +### +# Module C files +# + +set ( Module_SRCS + scan_loop.c +) + + +### +# Compiler Family Compatibility +# +set ( ModuleCompatibility + arm +) + diff -r 06b8d295518e -r 2d286e185cff Scan/MatrixARM/matrix_scan.c --- a/Scan/MatrixARM/matrix_scan.c Thu Feb 11 22:56:25 2016 -0800 +++ b/Scan/MatrixARM/matrix_scan.c Sat Feb 20 12:13:02 2016 -0800 @@ -70,6 +70,15 @@ // Debounce Array KeyState Matrix_scanArray[ Matrix_colsNum * Matrix_rowsNum ]; +// Ghost Arrays +#ifdef GHOSTING_MATRIX +KeyGhost Matrix_ghostArray[ Matrix_colsNum * Matrix_rowsNum ]; + +uint8_t col_use[Matrix_colsNum], row_use[Matrix_rowsNum]; // used count +uint8_t col_ghost[Matrix_colsNum], row_ghost[Matrix_rowsNum]; // marked as having ghost if 1 +#endif + + // Matrix debug flag - If set to 1, for each keypress the scan code is displayed in hex // If set to 2, for each key state change, the scan code is displayed along with the state uint8_t matrixDebugMode = 0; @@ -111,10 +120,17 @@ { case Type_StrobeOn: *GPIO_PSOR |= (1 << gpio.pin); + #ifdef GHOSTING_MATRIX + *GPIO_PDDR |= (1 << gpio.pin); // output + #endif break; case Type_StrobeOff: *GPIO_PCOR |= (1 << gpio.pin); + #ifdef GHOSTING_MATRIX + // Ghosting martix needs to put not used (off) strobes in high impedance state + *GPIO_PDDR &= ~(1 << gpio.pin); // input, high Z state + #endif break; case Type_StrobeSetup: @@ -206,6 +222,11 @@ Matrix_scanArray[ item ].activeCount = 0; Matrix_scanArray[ item ].inactiveCount = DebounceDivThreshold_define; // Start at 'off' steady state Matrix_scanArray[ item ].prevDecisionTime = 0; + #ifdef GHOSTING_MATRIX + Matrix_ghostArray[ item ].prev = KeyState_Off; + Matrix_ghostArray[ item ].cur = KeyState_Off; + Matrix_ghostArray[ item ].saved = KeyState_Off; + #endif } // Clear scan stats counters @@ -377,7 +398,9 @@ state->prevDecisionTime = currentTime; // Send keystate to macro module + #ifndef GHOSTING_MATRIX Macro_keyState( key, state->curState ); + #endif // Matrix Debug, only if there is a state change if ( matrixDebugMode && state->curState != state->prevState ) @@ -403,6 +426,101 @@ Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOff ); } + + // Matrix ghosting check and elimination + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +#ifdef GHOSTING_MATRIX + // strobe = column, sense = row + + // Count (rows) use for columns + //print("C "); + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + uint8_t used = 0; + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) ) + used++; + } + //printInt8(used); + col_use[col] = used; + col_ghost[col] = 0; // clear + } + + // Count (columns) use for rows + //print(" R "); + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t used = 0; + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) ) + used++; + } + //printInt8(used); + row_use[row] = used; + row_ghost[row] = 0; // clear + } + + // Check if matrix has ghost + // Happens when key is pressed and some other key is pressed in same row and another in same column + //print(" G "); + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + if ( keyOn(state->curState) && col_use[col] >= 2 && row_use[row] >= 2 ) + { + // mark col and row as having ghost + col_ghost[col] = 1; + row_ghost[row] = 1; + //print(" "); printInt8(col); print(","); printInt8(row); + } + } + } + //print( NL ); + + // Send keys + for ( uint8_t col = 0; col < Matrix_colsNum; col++ ) + { + for ( uint8_t row = 0; row < Matrix_rowsNum; row++ ) + { + uint8_t key = Matrix_colsNum * row + col; + KeyState *state = &Matrix_scanArray[ key ]; + KeyGhost *st = &Matrix_ghostArray[ key ]; + + // col or row is ghosting (crossed) + uint8_t ghost = (col_ghost[col] > 0 || row_ghost[row] > 0) ? 1 : 0; + + st->prev = st->cur; // previous + // save state if no ghost or outside ghosted area + if ( ghost == 0 ) + st->saved = state->curState; // save state if no ghost + // final + // use saved state if ghosting, or current if not + st->cur = ghost > 0 ? st->saved : state->curState; + + // Send keystate to macro module + KeyPosition k = !st->cur + ? (!st->prev ? KeyState_Off : KeyState_Release) + : ( st->prev ? KeyState_Hold : KeyState_Press); + //if (!st->cur && !st->prev) k = KeyState_Off; else + //if ( st->cur && st->prev) k = KeyState_Hold; else + //if ( st->cur && !st->prev) k = KeyState_Press; else + //if (!st->cur && st->prev) k = KeyState_Release; + Macro_keyState( key, k ); + } + } +#endif + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + // State Table Output Debug if ( matrixDebugStateCounter > 0 ) { diff -r 06b8d295518e -r 2d286e185cff Scan/MatrixARM/matrix_scan.h --- a/Scan/MatrixARM/matrix_scan.h Thu Feb 11 22:56:25 2016 -0800 +++ b/Scan/MatrixARM/matrix_scan.h Sat Feb 20 12:13:02 2016 -0800 @@ -139,6 +139,18 @@ uint8_t prevDecisionTime; } __attribute__((packed)) KeyState; +// Ghost Element, after ghost detection/cancelation +typedef struct KeyGhost { + KeyPosition prev; + KeyPosition cur; + KeyPosition saved; // state before ghosting +} __attribute__((packed)) KeyGhost; + +// utility +inline uint8_t keyOn(/*KeyPosition*/uint8_t st) +{ + return (st == KeyState_Press || st == KeyState_Hold) ? 1 : 0; +} // ----- Functions -----