void cliFunc_keyRelease( char* args ) { // Parse codes from arguments char* curArgs; char* arg1Ptr; char* arg2Ptr = args; // Process all args for ( ;; ) { curArgs = arg2Ptr; CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr ); // Stop processing args if no more are found if ( *arg1Ptr == '\0' ) break; // Ignore non-Scancode numbers switch ( arg1Ptr[0] ) { // Scancode case 'S': Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x03 ); // Release scancode break; } } }
// 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 ); }
// Single strobe matrix scan // Only goes through a single strobe // This module keeps track of the next strobe to scan uint8_t Matrix_single_scan() { // Start latency measurement Latency_start_time( matrixLatencyResource ); // Read systick for event scheduling uint32_t currentTime = systick_millis_count; // Current strobe uint8_t strobe = matrixCurrentStrobe; // XXX (HaaTa) // Before strobing drain each sense line // This helps with faulty pull-up resistors (particularily with SAM4S) for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveSetup, Matrix_type ); #if ScanCodeMatrixInvert_define == 2 // GPIO_Config_Pulldown GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveLow, Matrix_type ); #elif ScanCodeMatrixInvert_define == 1 // GPIO_Config_Pullup GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveHigh, Matrix_type ); #endif GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_ReadSetup, Matrix_type ); } // Strobe Pin GPIO_Ctrl( Matrix_cols[ strobe ], GPIO_Type_DriveHigh, Matrix_type ); // Used to allow the strobe signal to propagate, generally not required if ( strobeDelayTime > 0 ) { delay_us( strobeDelayTime ); } // Scan each of the sense pins for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { // Key position uint16_t key = Matrix_colsNum * sense + strobe; #if ScanCodeRemapping_define == 1 uint16_t key_disp = matrixScanCodeRemappingMatrix[key]; #else uint16_t key_disp = key + 1; // 1-indexed for reporting purposes #endif // Check bounds, before attempting to scan // 1-indexed as ScanCode 0 is not used if ( key_disp > MaxScanCode_KLL || key_disp == 0 ) { continue; } volatile KeyState *state = &Matrix_scanArray[ key ]; // 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 // Compared against the default state value (ScanCodeMatrixInvert_define), usually 0 if ( GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_Read, Matrix_type ) != ScanCodeMatrixInvert_define ) { // Only update if not going to wrap around if ( state->activeCount < DebounceDivThreshold ) state->activeCount += 1; state->inactiveCount >>= 1; } // Signal Not Detected else { // Only update if not going to wrap around if ( state->inactiveCount < DebounceDivThreshold ) state->inactiveCount += 1; state->activeCount >>= 1; } // Check for state change // But only if: // 1) Enough time has passed since last state change // 2) Either active or inactive count is over the debounce threshold // Update previous state state->prevState = state->curState; // Determine time since last decision uint32_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 < debounceExpiryTime ) { state->curState = state->prevState; Macro_keyState( key_disp, state->curState ); 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 < debounceExpiryTime ) { state->curState = state->prevState; Macro_keyState( key_disp, state->curState ); continue; } state->curState = KeyState_Press; } else { state->curState = KeyState_Off; } break; case KeyState_Invalid: default: erro_msg("Matrix scan bug!! Report me! - "); printHex( state->prevState ); print(" Col: "); printHex( strobe ); print(" Row: "); printHex( sense ); print(" Key: "); printHex( key_disp ); print( NL ); break; } // Update decision time state->prevDecisionTime = currentTime; // Send keystate to macro module Macro_keyState( key_disp, state->curState ); // Check for activity and inactivity if ( state->curState != KeyState_Off ) { matrixStateActiveCount++; } switch ( state->curState ) { case KeyState_Press: matrixStatePressCount++; break; case KeyState_Release: matrixStateReleaseCount++; break; default: break; } // 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 ) { printInt16( key_disp ); print(":"); printHex( key_disp ); print(" "); } // State transition debug output else if ( matrixDebugMode == 2 ) { printInt16( key_disp ); Matrix_keyPositionDebug( state->curState ); print(" "); } else if ( matrixDebugMode == 3 ) { print("\033[1m"); printInt16( key_disp ); print("\033[0m"); print(":"); Matrix_keyPositionDebug( Matrix_scanArray[ key ].prevState ); Matrix_keyPositionDebug( Matrix_scanArray[ key ].curState ); print(" 0x"); printHex_op( state->activeCount, 2 ); print(" 0x"); printHex_op( state->inactiveCount, 2 ); print(" "); printInt32( lastTransition ); print( NL ); } } }