// Setup GPIO pins for matrix scanning void Matrix_setup() { // Register Matrix CLI dictionary CLI_registerDictionary( matrixCLIDict, matrixCLIDictName ); info_msg("Columns: "); printHex( Matrix_colsNum ); // Setup Strobe Pins for ( uint8_t pin = 0; pin < Matrix_colsNum; pin++ ) { Matrix_pin( Matrix_cols[ pin ], Type_StrobeSetup ); } print( NL ); info_msg("Rows: "); printHex( Matrix_rowsNum ); // Setup Sense Pins for ( uint8_t pin = 0; pin < Matrix_rowsNum; pin++ ) { Matrix_pin( Matrix_rows[ pin ], Type_SenseSetup ); } print( NL ); info_msg("Max Keys: "); printHex( Matrix_maxKeys ); print( NL ); // Clear out Debounce Array for ( uint8_t item = 0; item < Matrix_maxKeys; item++ ) { Matrix_scanArray[ item ].prevState = KeyState_Off; Matrix_scanArray[ item ].curState = KeyState_Off; 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 matrixMaxScans = 0; matrixPrevScans = 0; }
void CustomAction_gameLayer_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { // Only use capability on press // TODO Analog // XXX Could also be on release, but that's sorta dumb -HaaTa if ( stateType == 0x00 && state != 0x01 ) // All normal key conditions except press return; gameLed ^= 1; Matrix_pin(ledFn, gameLed ? Type_StrobeOff : Type_StrobeOn); Macro_layerState( state, stateType, 2, 0x04 ); }
// Setup inline void Scan_setup() { // Register Scan CLI dictionary CLI_registerDictionary( scanCLIDict, scanCLIDictName ); // Setup GPIO pins for matrix scanning Matrix_setup(); Matrix_pin(ledCaps, Type_StrobeSetup); Matrix_pin(ledCaps, Type_StrobeOn); Matrix_pin(ledFn, Type_StrobeSetup); Matrix_pin(ledFn, Type_StrobeOn); Matrix_pin(ledNum, Type_StrobeSetup); Matrix_pin(ledNum, Type_StrobeOn); // Reset scan count Scan_scanCount = 0; }
// Scan the matrix for keypresses // NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters) void Matrix_scan( uint16_t scanNum ) { #if ( DebounceThrottleDiv_define > 0 ) // Scan-rate throttling // By scanning using a divider, the scan rate slowed down // DebounceThrottleDiv_define == 1 means -> /2 or half scan rate // This helps with bouncy switches on fast uCs if ( !( Matrix_divCounter++ & (1 << ( DebounceThrottleDiv_define - 1 )) ) ) return; #endif // Increment stats counters if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum; if ( scanNum == 0 ) { matrixPrevScans = matrixCurScans; matrixCurScans = 0; } else { matrixCurScans++; } // Read systick for event scheduling uint8_t currentTime = (uint8_t)systick_millis_count; // For each strobe, scan each of the sense pins for ( uint8_t strobe = 0; strobe < Matrix_colsNum; strobe++ ) { #ifdef STROBE_DELAY uint32_t start = micros(); while ((micros() - start) < STROBE_DELAY); #endif // Strobe Pin Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOn ); #ifdef STROBE_DELAY start = micros(); while ((micros() - start) < STROBE_DELAY); #endif // Scan each of the sense pins for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { // Key position uint8_t key = Matrix_colsNum * sense + strobe; KeyState *state = &Matrix_scanArray[ key ]; // If first scan, reset state if ( scanNum == 0 ) { // Set previous state, and reset current state state->prevState = state->curState; state->curState = KeyState_Invalid; } // Handle USB LEDs int ledOn = 0; if ( sense == 11 ) { switch ( strobe ) { case 0: ledOn = USBKeys_LEDs & 0x1; break; case 1: ledOn = USBKeys_LEDs & 0x2; break; case 2: ledOn = USBKeys_LEDs & 0x4; break; default: break; } } // Signal Detected // Increment count and right shift opposing count // This means there is a maximum of scan 13 cycles on a perfect off to on transition // (coming from a steady state 0xFFFF off scans) // Somewhat longer with switch bounciness // The advantage of this is that the count is ongoing and never needs to be reset // State still needs to be kept track of to deal with what to send to the Macro module if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) || ledOn) { // Only update if not going to wrap around if ( state->activeCount < DebounceDivThreshold_define ) state->activeCount += 1; state->inactiveCount >>= 1; } // Signal Not Detected else { // Only update if not going to wrap around if ( state->inactiveCount < DebounceDivThreshold_define ) state->inactiveCount += 1; state->activeCount >>= 1; } // Check for state change if it hasn't been set // But only if enough time has passed since last state change // Only check if the minimum number of scans has been met // the current state is invalid // and either active or inactive count is over the debounce threshold if ( state->curState == KeyState_Invalid ) { // Determine time since last decision uint8_t lastTransition = currentTime - state->prevDecisionTime; // Attempt state transition switch ( state->prevState ) { case KeyState_Press: case KeyState_Hold: if ( state->activeCount > state->inactiveCount ) { state->curState = KeyState_Hold; } else { // If not enough time has passed since Hold // Keep previous state if ( lastTransition < MinDebounceTime_define ) { //warn_print("FAST Release stopped"); state->curState = state->prevState; continue; } state->curState = KeyState_Release; } break; case KeyState_Release: case KeyState_Off: if ( state->activeCount > state->inactiveCount ) { // If not enough time has passed since Hold // Keep previous state if ( lastTransition < MinDebounceTime_define ) { //warn_print("FAST Press stopped"); state->curState = state->prevState; continue; } state->curState = KeyState_Press; } else { state->curState = KeyState_Off; } break; case KeyState_Invalid: default: erro_print("Matrix scan bug!! Report me!"); break; } // Update decision time 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 ) { // Basic debug output if ( matrixDebugMode == 1 && state->curState == KeyState_Press ) { printHex( key ); print(" "); } // State transition debug output else if ( matrixDebugMode == 2 ) { printHex( key ); Matrix_keyPositionDebug( state->curState ); print(" "); } } } } // Unstrobe Pin Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOff ); }