uint8_t Connect_receive_IdReport( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num ) { dbug_print("IdReport"); // Check the directionality if ( uart_num == UART_Master ) { erro_print("Invalid IdRequest direction..."); } // Track Id response if master if ( Connect_master ) { info_msg("Id Reported: "); printHex( id ); print( NL ); // Check if this is the highest ID if ( id > Connect_maxId ) Connect_maxId = id; return 1; } // Propagate id if yet another slave else { Connect_send_IdReport( id ); } return 1; }
uint8_t Connect_receive_CurrentEvent( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num ) { // Check the directionality if ( uart_num == UART_Slave ) { erro_print("Invalid CurrentEvent direction..."); } switch ( (*pending_bytes)-- ) { // Byte count always starts at 0xFFFF case 0xFFFF: // Current (LSB) Connect_receive_CurrentEvent_current = byte; break; case 0xFFFE: // Current (MSB) Connect_receive_CurrentEvent_current |= (byte << 8); // We now have all the necessary arguments (this will update all current monitors) Output_update_external_current( Connect_receive_CurrentEvent_current ); // All done *pending_bytes = 0; break; } // Check whether the scan codes have finished sending return *pending_bytes == 0 ? 1 : 0; }
uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num ) { dbug_print("IdEnumeration"); // Check the directionality if ( uart_num == UART_Slave ) { erro_print("Invalid IdEnumeration direction..."); } // Set the device id Connect_id = id; // Send reponse back to master Connect_send_IdReport( id ); // Node now enumerated, set current to last received current setting // Only set if this is not the master node if ( Connect_id != 0 ) { Output_update_external_current( Connect_LastCurrentValue ); } // Propogate next Id if the connection is ok if ( Connect_cableOkSlave ) { Connect_send_IdEnumeration( id + 1 ); } return 1; }
// Votes on the given key vs. guide, short macros inline TriggerMacroVote Macro_evalShortTriggerMacroVote( TriggerGuide *key, TriggerGuide *guide ) { // Depending on key type switch ( guide->type ) { // Normal State Type case 0x00: // For short TriggerMacros completely ignore incorrect keys if ( guide->scanCode == key->scanCode ) { switch ( key->state ) { // Correct key, pressed, possible passing case 0x01: return TriggerMacroVote_Pass; // Correct key, held, possible passing or release case 0x02: return TriggerMacroVote_PassRelease; // Correct key, released, possible release case 0x03: return TriggerMacroVote_Release; } } return TriggerMacroVote_DoNothing; // LED State Type case 0x01: erro_print("LED State Type - Not implemented..."); break; // Analog State Type case 0x02: erro_print("Analog State Type - Not implemented..."); break; // Invalid State Type default: erro_print("Invalid State Type. This is a bug."); break; } // XXX Shouldn't reach here return TriggerMacroVote_Invalid; }
void Connect_addBytes( uint8_t *buffer, uint8_t count, uint8_t uart ) { // Too big to fit into buffer if ( count > UART_Buffer_Size ) { erro_msg("Too big of a command to fit into the buffer..."); return; } // Invalid UART if ( uart >= UART_Num_Interfaces ) { erro_print("Invalid UART to send from..."); return; } // Delay UART copy until there's some space left while ( uart_tx_buf[ uart ].items + count > UART_Buffer_Size ) { warn_msg("Too much data to send on UART"); printInt8( uart ); print( ", waiting..." NL ); delay_ms( 1 ); // FIXME Buffer will not drain here.... } // Append data to ring buffer for ( uint8_t c = 0; c < count; c++ ) { if ( Connect_debug ) { printHex( buffer[ c ] ); print(" +"); printInt8( uart ); print( NL ); } uart_tx_buf[ uart ].buffer[ uart_tx_buf[ uart ].tail++ ] = buffer[ c ]; uart_tx_buf[ uart ].items++; if ( uart_tx_buf[ uart ].tail >= UART_Buffer_Size ) uart_tx_buf[ uart ].tail = 0; if ( uart_tx_buf[ uart ].head == uart_tx_buf[ uart ].tail ) uart_tx_buf[ uart ].head++; if ( uart_tx_buf[ uart ].head >= UART_Buffer_Size ) uart_tx_buf[ uart ].head = 0; } }
uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num ) { dbug_print("IdEnumeration"); // Check the directionality if ( uart_num == UART_Slave ) { erro_print("Invalid IdEnumeration direction..."); } // Set the device id Connect_id = id; // Send reponse back to master Connect_send_IdReport( id ); // Propogate next Id if the connection is ok if ( Connect_cableOkSlave ) { Connect_send_IdEnumeration( id + 1 ); } return 1; }
uint8_t Connect_receive_IdRequest( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num ) { dbug_print("IdRequest"); // Check the directionality if ( uart_num == UART_Master ) { erro_print("Invalid IdRequest direction..."); } // Check if master, begin IdEnumeration if ( Connect_master ) { // The first device is always id 1 // Id 0 is reserved for the master Connect_send_IdEnumeration( 1 ); } // Propagate IdRequest else { Connect_send_IdRequest(); } return 1; }
void i2c0_isr() { cli(); // Disable Interrupts uint8_t status = I2C0_S; // Read I2C Bus status // Master Mode Transmit if ( I2C0_C1 & I2C_C1_TX ) { // Check current use of the I2C bus // Currently sending data if ( I2C_TxBuffer.sequencePos > 0 ) { // Make sure slave sent an ACK if ( status & I2C_S_RXAK ) { // NACK Detected, disable interrupt erro_print("I2C NAK detected..."); I2C0_C1 = I2C_C1_IICEN; // Abort Tx Buffer I2C_TxBuffer.head = 0; I2C_TxBuffer.tail = 0; I2C_TxBuffer.sequencePos = 0; } else { // Transmit byte I2C0_D = I2C_TxBufferPop(); } } // Receiving data else if ( I2C_RxBuffer.sequencePos > 0 ) { // Master Receive, addr sent if ( status & I2C_S_ARBL ) { // Arbitration Lost erro_print("Arbitration lost..."); // TODO Abort Rx I2C0_C1 = I2C_C1_IICEN; I2C0_S = I2C_S_ARBL | I2C_S_IICIF; // Clear ARBL flag and interrupt } if ( status & I2C_S_RXAK ) { // Slave Address NACK Detected, disable interrupt erro_print("Slave Address I2C NAK detected..."); // TODO Abort Rx I2C0_C1 = I2C_C1_IICEN; } else { dbug_print("Attempting to read byte"); I2C0_C1 = I2C_RxBuffer.sequencePos == 1 ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read } } else { /* dbug_msg("STOP - "); printHex( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) ); print(NL); */ // Delay around STOP to make sure it actually happens... delayMicroseconds( 1 ); I2C0_C1 = I2C_C1_IICEN; // Send STOP delayMicroseconds( 7 ); // If there is another sequence, start sending if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) < I2C_TxBuffer.size ) { // Clear status flags I2C0_S = I2C_S_IICIF | I2C_S_ARBL; // Wait...till the master dies while ( I2C0_S & I2C_S_BUSY ); // Enable I2C interrupt I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX; // Transmit byte I2C0_D = I2C_TxBufferPop(); } } } // Master Mode Receive else { // XXX Do we need to handle 2nd last byte? //I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // No STOP, Rx, NAK on recv // Last byte if ( I2C_TxBuffer.sequencePos <= 1 ) { // Change to Tx mode I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; // Grab last byte I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer ); delayMicroseconds( 1 ); // Should be enough time before issuing the stop I2C0_C1 = I2C_C1_IICEN; // Send STOP } else { // Retrieve data I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer ); } } I2C0_S = I2C_S_IICIF; // Clear interrupt sei(); // Re-enable Interrupts }
// Votes on the given key vs. guide, long macros // A long macro is defined as a guide with more than 1 combo inline TriggerMacroVote Macro_evalLongTriggerMacroVote( TriggerGuide *key, TriggerGuide *guide ) { // Depending on key type switch ( guide->type ) { // Normal State Type case 0x00: // Depending on the state of the buffered key, make voting decision // Incorrect key if ( guide->scanCode != key->scanCode ) { switch ( key->state ) { // Wrong key, pressed, fail case 0x01: return TriggerMacroVote_Fail; // Wrong key, held, do not pass (no effect) case 0x02: return TriggerMacroVote_DoNothing; // Wrong key released, fail out if pos == 0 case 0x03: return TriggerMacroVote_DoNothing | TriggerMacroVote_DoNothingRelease; } } // Correct key else { switch ( key->state ) { // Correct key, pressed, possible passing case 0x01: return TriggerMacroVote_Pass; // Correct key, held, possible passing or release case 0x02: return TriggerMacroVote_PassRelease; // Correct key, released, possible release case 0x03: return TriggerMacroVote_Release; } } break; // LED State Type case 0x01: erro_print("LED State Type - Not implemented..."); break; // Analog State Type case 0x02: erro_print("Analog State Type - Not implemented..."); break; // Invalid State Type default: erro_print("Invalid State Type. This is a bug."); break; } // XXX Shouldn't reach here return TriggerMacroVote_Invalid; }
uint8_t Connect_receive_ScanCode( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num ) { // Check the directionality if ( uart_num == UART_Master ) { erro_print("Invalid ScanCode direction..."); } // Master node, trigger scan codes if ( Connect_master ) switch ( (*pending_bytes)-- ) { // Byte count always starts at 0xFFFF case 0xFFFF: // Device Id Connect_receive_ScanCodeDeviceId = byte; break; case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3) *pending_bytes = byte * sizeof( TriggerGuide ); Connect_receive_ScanCodeBufferPos = 0; break; default: // Set the specific TriggerGuide entry ((uint8_t*)&Connect_receive_ScanCodeBuffer)[ Connect_receive_ScanCodeBufferPos++ ] = byte; // Reset the BufferPos if higher than sizeof TriggerGuide // And send the TriggerGuide to the Macro Module if ( Connect_receive_ScanCodeBufferPos >= sizeof( TriggerGuide ) ) { Connect_receive_ScanCodeBufferPos = 0; // Adjust ScanCode offset if ( Connect_receive_ScanCodeDeviceId > 0 ) { // Check if this node is too large if ( Connect_receive_ScanCodeDeviceId >= InterconnectNodeMax ) { warn_msg("Not enough interconnect layout nodes configured: "); printHex( Connect_receive_ScanCodeDeviceId ); print( NL ); break; } // This variable is in generatedKeymaps.h extern uint8_t InterconnectOffsetList[]; Connect_receive_ScanCodeBuffer.scanCode = Connect_receive_ScanCodeBuffer.scanCode + InterconnectOffsetList[ Connect_receive_ScanCodeDeviceId - 1 ]; } // ScanCode receive debug if ( Connect_debug ) { dbug_msg(""); printHex( Connect_receive_ScanCodeBuffer.type ); print(" "); printHex( Connect_receive_ScanCodeBuffer.state ); print(" "); printHex( Connect_receive_ScanCodeBuffer.scanCode ); print( NL ); } // Send ScanCode to macro module Macro_interconnectAdd( &Connect_receive_ScanCodeBuffer ); } break; } // Propagate ScanCode packet // XXX It would be safer to buffer the scancodes first, before transmitting the packet -Jacob // The current method is the more efficient/aggressive, but could cause issues if there were errors during transmission else switch ( (*pending_bytes)-- ) { // Byte count always starts at 0xFFFF case 0xFFFF: // Device Id { Connect_receive_ScanCodeDeviceId = byte; // Lock the master Tx buffer uart_lockTx( UART_Master ); // Send header + Id byte uint8_t header[] = { 0x16, 0x01, ScanCode, byte }; Connect_addBytes( header, sizeof( header ), UART_Master ); break; } case 0xFFFE: // Number of TriggerGuides in bytes *pending_bytes = byte * sizeof( TriggerGuide ); Connect_receive_ScanCodeBufferPos = 0; // Pass through byte Connect_addBytes( &byte, 1, UART_Master ); break; default: // Pass through byte Connect_addBytes( &byte, 1, UART_Master ); // Unlock Tx Buffer after sending last byte if ( *pending_bytes == 0 ) uart_unlockTx( UART_Master ); break; } // Check whether the scan codes have finished sending return *pending_bytes == 0 ? 1 : 0; }
// send the contents of keyboard_keys and keyboard_modifier_keys void usb_keyboard_send() { uint32_t wait_count = 0; usb_packet_t *tx_packet; // Wait till ready while ( 1 ) { if ( !usb_configuration ) { erro_print("USB not configured..."); return; } if ( USBKeys_Protocol == 0 ) // Boot Mode { if ( usb_tx_packet_count( NKRO_KEYBOARD_ENDPOINT ) < TX_PACKET_LIMIT ) { tx_packet = usb_malloc(); if ( tx_packet ) break; } } else if ( USBKeys_Protocol == 1 ) // NKRO Mode { if ( usb_tx_packet_count( KEYBOARD_ENDPOINT ) < TX_PACKET_LIMIT ) { tx_packet = usb_malloc(); if ( tx_packet ) break; } } if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) { transmit_previous_timeout = 1; warn_print("USB Transmit Timeout..."); return; } yield(); } // Pointer to USB tx packet buffer uint8_t *tx_buf = tx_packet->buf; switch ( USBKeys_Protocol ) { // Send boot keyboard interrupt packet(s) case 0: // USB Boot Mode debug output if ( Output_DebugMode ) { dbug_msg("Boot USB: "); printHex_op( USBKeys_Modifiers, 2 ); print(" "); printHex( 0 ); print(" "); printHex_op( USBKeys_Keys[0], 2 ); printHex_op( USBKeys_Keys[1], 2 ); printHex_op( USBKeys_Keys[2], 2 ); printHex_op( USBKeys_Keys[3], 2 ); printHex_op( USBKeys_Keys[4], 2 ); printHex_op( USBKeys_Keys[5], 2 ); print( NL ); } // Boot Mode *tx_buf++ = USBKeys_Modifiers; *tx_buf++ = 0; memcpy( tx_buf, USBKeys_Keys, USB_BOOT_MAX_KEYS ); tx_packet->len = 8; // Send USB Packet usb_tx( KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed = USBKeyChangeState_None; break; // Send NKRO keyboard interrupts packet(s) case 1: if ( Output_DebugMode ) { dbug_msg("NKRO USB: "); } // Check system control keys if ( USBKeys_Changed & USBKeyChangeState_System ) { if ( Output_DebugMode ) { print("SysCtrl["); printHex_op( USBKeys_SysCtrl, 2 ); print( "] " NL ); } *tx_buf++ = 0x02; // ID *tx_buf = USBKeys_SysCtrl; tx_packet->len = 2; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed &= ~USBKeyChangeState_System; // Mark sent } // Check consumer control keys if ( USBKeys_Changed & USBKeyChangeState_Consumer ) { if ( Output_DebugMode ) { print("ConsCtrl["); printHex_op( USBKeys_ConsCtrl, 2 ); print( "] " NL ); } *tx_buf++ = 0x03; // ID *tx_buf++ = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); *tx_buf = (uint8_t)(USBKeys_ConsCtrl >> 8); tx_packet->len = 3; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed &= ~USBKeyChangeState_Consumer; // Mark sent } // Standard HID Keyboard if ( USBKeys_Changed ) { // USB NKRO Debug output if ( Output_DebugMode ) { printHex_op( USBKeys_Modifiers, 2 ); print(" "); for ( uint8_t c = 0; c < 6; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print(" "); for ( uint8_t c = 6; c < 20; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print(" "); printHex_op( USBKeys_Keys[20], 2 ); print(" "); for ( uint8_t c = 21; c < 27; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print( NL ); } tx_packet->len = 0; // Modifiers *tx_buf++ = 0x01; // ID *tx_buf++ = USBKeys_Modifiers; tx_packet->len += 2; // 4-49 (first 6 bytes) memcpy( tx_buf, USBKeys_Keys, 6 ); tx_buf += 6; tx_packet->len += 6; // 51-155 (Middle 14 bytes) memcpy( tx_buf, USBKeys_Keys + 6, 14 ); tx_buf += 14; tx_packet->len += 14; // 157-164 (Next byte) memcpy( tx_buf, USBKeys_Keys + 20, 1 ); tx_buf += 1; tx_packet->len += 1; // 176-221 (last 6 bytes) memcpy( tx_buf, USBKeys_Keys + 21, 6 ); tx_packet->len += 6; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed = USBKeyChangeState_None; // Mark sent } break; } return; }
// 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 ); }
// Votes on the given key vs. guide, long macros // A long macro is defined as a guide with more than 1 combo TriggerMacroVote Trigger_evalLongTriggerMacroVote( TriggerEvent *event, TriggerGuide *guide, TriggerMacroVote *cur_vote ) { // Lookup full index var_uint_t guide_index = KLL_TriggerIndex_loopkup( guide->type, guide->scanCode ); var_uint_t event_index = KLL_TriggerIndex_loopkup( event->type, event->index ); // Depending on key type switch ( guide->type ) { // Normal State Type case TriggerType_Switch1: case TriggerType_Switch2: case TriggerType_Switch3: case TriggerType_Switch4: // LED State Type case TriggerType_LED1: // Layer State Type case TriggerType_Layer1: case TriggerType_Layer2: case TriggerType_Layer3: case TriggerType_Layer4: // Activity State Types case TriggerType_Sleep1: case TriggerType_Resume1: case TriggerType_Inactive1: case TriggerType_Active1: // Depending on the state of the buffered key, make voting decision // Only monitor 0x70 bits if set in the guide, otherwise ensure they are 0x00 // Used for Layer state information // Correct key if ( guide_index == event_index && guide->type == event->type && ( (guide->state & 0x70) == (event->state & 0x70) || (guide->state & 0x70) == 0x00 ) ) { return Trigger_evalLongTriggerMacroVote_PHRO( event->state, 1 ); } // Incorrect key else { return Trigger_evalLongTriggerMacroVote_PHRO( event->state, 0 ); } break; // Analog State Type case TriggerType_Analog1: case TriggerType_Analog2: case TriggerType_Analog3: case TriggerType_Analog4: erro_print("Analog State Type - Not implemented..."); break; // Animation State Type case TriggerType_Animation1: case TriggerType_Animation2: case TriggerType_Animation3: case TriggerType_Animation4: // Depending on the state of the buffered key, make voting decision // Correct trigger if ( guide_index == event_index && guide->type == event->type && guide->state == event->state ) { return Trigger_evalLongTriggerMacroVote_DRO( event->state, 1 ); } // Incorrect trigger else { return Trigger_evalLongTriggerMacroVote_DRO( event->state, 0 ); } break; // Rotation State Type case TriggerType_Rotation1: // Rotation triggers use state as the index, rather than encoding a type of action // There is only "activated" state for rotations, which is only sent once // This makes rotations not so useful for long macros // (though it may be possible to implement it if there is demand) // TODO erro_print("Rotation State Type (Long Macros) - Not implemented..."); break; // Invalid State Type default: erro_print("Invalid State Type. This is a bug."); break; } // XXX Shouldn't reach here return TriggerMacroVote_Invalid; }
// Votes on the given key vs. guide, short macros TriggerMacroVote Trigger_evalShortTriggerMacroVote( TriggerEvent *event, TriggerGuide *guide, TriggerMacroVote *cur_vote ) { // Lookup full index var_uint_t guide_index = KLL_TriggerIndex_loopkup( guide->type, guide->scanCode ); var_uint_t event_index = KLL_TriggerIndex_loopkup( event->type, event->index ); // Return value TriggerMacroVote vote = TriggerMacroVote_Invalid; // Depending on key type switch ( guide->type ) { // Normal State Type case TriggerType_Switch1: case TriggerType_Switch2: case TriggerType_Switch3: case TriggerType_Switch4: // LED State Type case TriggerType_LED1: // Layer State Type case TriggerType_Layer1: case TriggerType_Layer2: case TriggerType_Layer3: case TriggerType_Layer4: // Activity State Types case TriggerType_Sleep1: case TriggerType_Resume1: case TriggerType_Inactive1: case TriggerType_Active1: // For short TriggerMacros completely ignore incorrect keys // Only monitor 0x70 bits if set in the guide, otherwise ensure they are 0x00 // Used for Layer state information if ( guide_index == event_index && guide->type == event->type && ( (guide->state & 0x70) == (event->state & 0x70) || (guide->state & 0x70) == 0x00 ) ) { // If this trigger is generic, we can just vote based on the incoming state if ( guide->state & ScheduleType_Gen ) { vote = Trigger_evalShortTriggerMacroVote_PHRO( event->state ); break; } // TODO (HaaTa) Implement state scheduling erro_print("State Scheduling not implemented yet..."); } vote = TriggerMacroVote_DoNothing; break; /* // LED State Type case TriggerType_LED1: // XXX (HaaTa) This is an initial version of State Scheduling // For any state match that is not ScheduleType_A, set to ScheduleType_A // as this will indicate a pulse to the capability. if ( guide_index == event_index && guide->type == event->type ) { // When state scheduling is specified // TODO (HaaTa); We should probably move to another state type for "auto" schedule types if ( guide->state == event->state && guide->state != ScheduleType_A ) { return Trigger_evalShortTriggerMacroVote_PHRO( ScheduleType_A ); } //return Trigger_evalShortTriggerMacroVote_PHRO( event->state ); } return TriggerMacroVote_DoNothing; */ // Analog State Type case TriggerType_Analog1: case TriggerType_Analog2: case TriggerType_Analog3: case TriggerType_Analog4: erro_print("Analog State Type - Not implemented..."); break; // Animation State Type case TriggerType_Animation1: case TriggerType_Animation2: case TriggerType_Animation3: case TriggerType_Animation4: // For short TriggerMacros completely ignore incorrect triggers if ( guide_index == event_index && guide->type == event->type && guide->state == event->state ) { vote = Trigger_evalShortTriggerMacroVote_DRO( event->state ); break; } vote = TriggerMacroVote_DoNothing; break; // Rotation State Type case TriggerType_Rotation1: // Rotation triggers use state as the index, rather than encoding a type of action // There is only "activated" state for rotations, which is only sent once // This makes rotations not so useful for long macros // (though it may be possible to implement it if there is demand) if ( guide_index == event_index && guide->type == event->type && guide->state == event->state // <== This is the rotation position ) { // Only ever "Pressed", other states are not used with rotations vote = Trigger_evalShortTriggerMacroVote_PHRO( ScheduleType_P ); break; } vote = TriggerMacroVote_DoNothing; break; // Invalid State Type default: erro_print("Invalid State Type. This is a bug."); break; } // If this is a combo macro, make a preference for TriggerMacroVote_Pass instead of TriggerMacroVote_PassRelease if ( *cur_vote != TriggerMacroVote_Invalid && event_index == guide_index ) { // Make sure the votes are different and one of them are Pass if ( *cur_vote != vote && ( *cur_vote == TriggerMacroVote_Pass || vote == TriggerMacroVote_Pass ) && ( *cur_vote == TriggerMacroVote_PassRelease || vote == TriggerMacroVote_PassRelease ) ) { *cur_vote = TriggerMacroVote_Pass; vote = TriggerMacroVote_Pass; } } return vote; }