Example #1
0
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;
}
Example #2
0
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;
}
Example #3
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;
}
Example #4
0
// 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;
}
Example #5
0
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;
	}
}
Example #6
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;
}
Example #7
0
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;
}
Example #8
0
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
}
Example #9
0
// 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;
}
Example #10
0
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 );
	}
Example #13
0
// 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;
}
Example #14
0
// 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;
}