示例#1
0
// Port State processing loop
inline uint8_t Port_scan()
{
	// Latency measurement start
	Latency_start_time( portLatencyResource );

	// TODO Add in interconnect line cross

	#define USBPortSwapDelay_ms 1000
	// Wait 1000 ms before checking
	// Only check for swapping after delay
	uint32_t wait_ms = systick_millis_count - Port_lastcheck_ms;
	if ( wait_ms > USBPortSwapDelay_ms )
	{
		// Update timeout
		Port_lastcheck_ms = systick_millis_count;

		// USB not initialized, attempt to swap
		if ( !usb_configured() )
		{
			Port_usb_swap();
		}
	}

	// Latency measurement end
	Latency_end_time( portLatencyResource );

	return 0;
}
示例#2
0
// Scan for updates in the master/slave
// - Interrupts will deal with most input functions
// - Used to send queries
// - SyncEvent is sent immediately once the current command is sent
// - SyncEvent is also blocking until sent
void Connect_scan()
{
	// Latency measurement start
	Latency_start_time( connectLatencyResource );

	// Check if initially configured as a slave and usb comes up
	// Then reconfigure as a master
	if ( !Connect_master && Output_Available && !Connect_override )
	{
		Connect_setup( Output_Available, 0 );
	}

	// Limit how often we do cable checks
	//uint32_t time_compare = 0x007; // XXX Used for debugging cables -HaaTa
	uint32_t time_compare = 0x7FF; // Must be all 1's, 0x3FF is valid, 0x4FF is not
	uint32_t current_time = systick_millis_count;
	if ( Connect_lastCheck != current_time
		&& ( current_time & time_compare ) == time_compare
	)
	{
		// Make sure we don't double check if the clock speed is too high
		Connect_lastCheck = current_time;

		// Send a cable check command of 2 bytes
		Connect_send_CableCheck( UARTConnectCableCheckLength_define );

		// If this is a slave, and we don't have an id yeth
		// Don't bother sending if there are cable issues
		if ( !Connect_master && Connect_id == DEFAULT_SLAVE_ID && Connect_cableOkMaster )
		{
			Connect_send_IdRequest();
		}
	}

	// Only process commands if uarts have been configured
	if ( uarts_configured )
	{
		// Check if Tx Buffers are empty and the Tx Ring buffers have data to send
		// This happens if there was previously nothing to send
#if defined(_kinetis_)
		if ( uart_tx_buf[ 0 ].items > 0 && UART0_TCFIFO == 0 )
			uart_fillTxFifo( 0 );
		if ( uart_tx_buf[ 1 ].items > 0 && UART1_TCFIFO == 0 )
			uart_fillTxFifo( 1 );
#elif defined(_sam_)
		//SAM TODO
#endif

		// Process Rx Buffers
		Connect_rx_process( 0 );
		Connect_rx_process( 1 );
	}

	// Latency measurement end
	Latency_end_time( connectLatencyResource );
}
示例#3
0
// USB Data Poll
inline void Output_poll()
{
	// Start latency measurement
	Latency_start_time( outputPollLatencyResource );

#if enableRawIO_define == 1
	// HID-IO Process
	HIDIO_process();
#endif

	// End latency measurement
	Latency_end_time( outputPollLatencyResource );
}
示例#4
0
// USB Data Periodic
inline void Output_periodic()
{
	// Start latency measurement
	Latency_start_time( outputPeriodicLatencyResource );

#if enableMouse_define == 1
	// Process mouse actions
	while ( USBMouse_Changed )
		Output_callback( "mouse_send", "" );
#endif

#if enableKeyboard_define == 1
	// Boot Mode Only, unset stale keys
	if ( USBKeys_Protocol == 0 )
	{
		for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ )
		{
			USBKeys_primary.keys[c] = 0;
		}
	}

	// Send keypresses while there are pending changes
	while ( USBKeys_primary.changed )
		Output_callback( "keyboard_send", "" );

	// Clear keys sent
	USBKeys_Sent = 0;

	// Signal Scan Module we are finished
	switch ( USBKeys_Protocol )
	{
	case 0: // Boot Mode
		// Clear modifiers only in boot mode
		USBKeys_primary.modifiers = 0;
		Scan_finishedWithOutput( USBKeys_Sent <= USB_BOOT_MAX_KEYS ? USBKeys_Sent : USB_BOOT_MAX_KEYS );
		break;
	case 1: // NKRO Mode
		Scan_finishedWithOutput( USBKeys_Sent );
		break;
	}
#endif

	// End latency measurement
	Latency_end_time( outputPeriodicLatencyResource );
}
示例#5
0
inline void LED_scan()
{
	// Latency measurement start
	Latency_start_time( ledLatencyResource );

	// Check for current change event
	if ( LED_currentEvent )
	{
		// Turn LEDs off in low power mode
		if ( LED_currentEvent < 150 )
		{
			LED_enable_current = 0;

			// Pause animations and clear display
			Pixel_setAnimationControl( AnimationControl_WipePause );
		}
		else
		{
			LED_enable_current = 1;

			// Start animations
			Pixel_setAnimationControl( AnimationControl_Forward );
		}

		LED_currentEvent = 0;
	}

	// Check if an LED_pause is set
	// Some ISSI operations need a clear buffer, but still have the chip running
	if ( LED_pause )
		goto led_finish_scan;

	// Check enable state
	if ( LED_enable && LED_enable_current )
	{
		// Disable Hardware shutdown of ISSI chips (pull high)
		GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup );
	}
	// Only write pages to I2C if chip is enabled (i.e. Hardware shutdown is disabled)
	else
	{
		// Enable hardware shutdown
		GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup );
		goto led_finish_scan;
	}

	// Check if any I2C buses have errored
	// Reset the buses and restart the Frame State
	if ( i2c_error() )
	{
		i2c_reset();
		Pixel_FrameState = FrameState_Update;
	}

	// Only start if we haven't already
	// And if we've finished updating the buffers
	if ( Pixel_FrameState == FrameState_Sending )
		goto led_finish_scan;

	// Only send frame to ISSI chip if buffers are ready
	if ( Pixel_FrameState != FrameState_Ready )
		goto led_finish_scan;

	// Adjust frame rate (i.e. delay and do something else for a bit)
	Time duration = Time_duration( LED_timePrev );
	if ( duration.ms < LED_framerate )
		goto led_finish_scan;

	// FPS Display
	if ( LED_displayFPS )
	{
		// Show frame calculation
		dbug_msg("1frame/");
		printInt32( Time_ms( duration ) );
		print("ms + ");
		printInt32( duration.ticks );
		print(" ticks");

		// Check if we're not meeting frame rate
		if ( duration.ms > LED_framerate )
		{
			print(" - Could not meet framerate: ");
			printInt32( LED_framerate );
		}

		print( NL );
	}

	// Emulated brightness control
	// Lower brightness by LED_brightness
#if ISSI_Chip_31FL3731_define == 1
	for ( uint8_t chip = 0; chip < ISSI_Chips_define; chip++ )
	{
		for ( uint8_t ch = 0; ch < LED_EnableBufferLength; ch++ )
		{
			LED_pageBuffer_brightness[ chip ].ledctrl[ ch ] = LED_pageBuffer[ chip ].ledctrl[ ch ];
		}

		for ( uint8_t ch = 0; ch < LED_BufferLength; ch++ )
		{
			// Don't modify is 0
			if ( LED_pageBuffer[ chip ].buffer[ ch ] == 0 || LED_brightness == 0 )
			{
				LED_pageBuffer_brightness[ chip ].buffer[ ch ] = 0;
				continue;
			}

			// XXX (HaaTa) Yes, this is a bit slow, but it's pretty accurate
			LED_pageBuffer_brightness[ chip ].buffer[ ch ] =
				(LED_pageBuffer[ chip ].buffer[ ch ] * LED_brightness) / 0xFF;
		}
	}
#endif

	// Update frame start time
	LED_timePrev = Time_now();

	// Set the page of all the ISSI chips
	// This way we can easily link the buffers to send the brightnesses in the background
	for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
	{
		uint8_t bus = LED_ChannelMapping[ ch ].bus;
		// Page Setup
		LED_setupPage(
			bus,
			LED_ChannelMapping[ ch ].addr,
			ISSI_LEDPwmPage
		);
	}

	// Send current set of buffers
	// Uses interrupts to send to all the ISSI chips
	// Pixel_FrameState will be updated when complete
	LED_chipSend = 0; // Start with chip 0
	LED_linkedSend();

led_finish_scan:
	// Latency measurement end
	Latency_end_time( ledLatencyResource );
}
示例#6
0
// Macro Processing Loop, called from the periodic execution thread
// Called once per USB buffer send
void Macro_periodic()
{
	// Latency measurement
	Latency_start_time( macroLatencyResource );

#if defined(ConnectEnabled_define)
	// Only compile in if a Connect node module is available
	// If this is a interconnect slave node, send all scancodes to master node
	if ( !Connect_master )
	{
		if ( macroTriggerEventBufferSize > 0 )
		{
			Connect_send_ScanCode( Connect_id, macroTriggerEventBuffer, macroTriggerEventBufferSize );
			macroTriggerEventBufferSize = 0;
		}
		return;
	}
#endif

#if defined(ConnectEnabled_define) || defined(PressReleaseCache_define)
#if defined(ConnectEnabled_define)
	// Check if there are any ScanCodes in the interconnect cache to process
	if ( Connect_master && macroInterconnectCacheSize > 0 )
#endif
	{
		// Iterate over all the cache ScanCodes
		uint8_t currentInterconnectCacheSize = macroInterconnectCacheSize;
		macroInterconnectCacheSize = 0;
		for ( uint8_t c = 0; c < currentInterconnectCacheSize; c++ )
		{
			// Add to the trigger list
			macroTriggerEventBuffer[ macroTriggerEventBufferSize++ ] = macroInterconnectCache[ c ];

			// TODO Handle other TriggerGuide types (e.g. analog)
			switch ( macroInterconnectCache[ c ].type )
			{
			// Normal (Press/Hold/Release)
			case TriggerType_Switch1:
			case TriggerType_Switch2:
			case TriggerType_Switch3:
			case TriggerType_Switch4:
			case TriggerType_LED1:
				// Decide what to do based on the current state
				switch ( macroInterconnectCache[ c ].state )
				{
				// Re-add to interconnect cache in hold state
				case ScheduleType_P: // Press
				//case ScheduleType_H: // Hold // XXX Why does this not work? -HaaTa
					macroInterconnectCache[ c ].state = ScheduleType_H;
					macroInterconnectCache[ macroInterconnectCacheSize++ ] = macroInterconnectCache[ c ];
					break;

				case ScheduleType_R: // Release
					break;

				// Otherwise, do not re-add
				default:
					break;
				}
				break;

			// Not implemented
			default:
				erro_msg("Interconnect Trigger Event Type - Not Implemented ");
				printInt8( macroInterconnectCache[ c ].type );
				print( NL );
				break;
			}
		}
	}
#endif
	// Macro incoming state debug
	switch ( macroDebugMode )
	{
	case 1:
	case 2:
		// Iterate over incoming triggers
		for ( uint16_t trigger = 0; trigger < macroTriggerEventBufferSize; trigger++ )
		{
			// Show debug info about incoming trigger
			Macro_showTriggerEvent( &macroTriggerEventBuffer[trigger] );
			print( NL );
		}

	case 3:
	default:
		break;
	}

	// Check macroTriggerEventBufferSize to make sure no overflow
	if ( macroTriggerEventBufferSize >= MaxScanCode_KLL )
	{
		// No scancodes defined
		if ( MaxScanCode_KLL == 0 )
		{
			warn_print("No scancodes defined! Check your BaseMap!");
		}
		// Bug!
		else
		{
			erro_msg("Macro Trigger Event Overflow! Serious Bug! ");
			printInt16( macroTriggerEventBufferSize );
			print( NL );
			macroTriggerEventBufferSize = 0;
		}
	}

	// If the pause flag is set, only process if the step counter is non-zero
	if ( macroPauseMode )
	{
		if ( macroStepCounter == 0 )
			return;

		// Proceed, decrementing the step counter
		macroStepCounter--;
		dbug_print("Macro Step");
	}

	// Process Trigger Macros
	Trigger_process();


	// Store events processed
	var_uint_t macroTriggerEventBufferSize_processed = macroTriggerEventBufferSize;

	// Reset TriggerList buffer
	macroTriggerEventBufferSize = 0;


	// Process result macros
	Result_process();

	// Signal buffer that we've used it
	Scan_finishedWithMacro( macroTriggerEventBufferSize_processed );

#if defined(_host_)
	// Signal host to read layer state
	Output_callback( "layerState", "" );
#endif

	// Latency measurement
	Latency_end_time( macroLatencyResource );

	// If Macro debug mode is set, clear the USB Buffer
#if defined(Output_USBEnabled_define)
	if ( macroDebugMode == 1 || macroDebugMode == 3 )
	{
		USBKeys_primary.changed = 0;
	}
#endif
}
示例#7
0
// 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 );
			}

		}
	}
示例#8
0
文件: led_scan.c 项目: Olical/ergodox
inline void LED_scan()
{
	// Latency measurement start
	Latency_start_time( ledLatencyResource );

	// Check for current change event
	if ( LED_currentEvent )
	{
		// Turn LEDs off in low power mode
		if ( LED_currentEvent < 150 )
		{
			LED_enable = 0;

			// Pause animations and clear display
			Pixel_setAnimationControl( AnimationControl_WipePause );
		}
		else
		{
			LED_enable = 1;

			// Start animations
			Pixel_setAnimationControl( AnimationControl_Forward );
		}

		LED_currentEvent = 0;
	}

	// Check if an LED_pause is set
	// Some ISSI operations need a clear buffer, but still have the chip running
	if ( LED_pause )
		goto led_finish_scan;

	// Check enable state
	if ( LED_enable )
	{
		// Disable Hardware shutdown of ISSI chips (pull high)
		GPIOB_PSOR |= (1<<16);
	}
	// Only write pages to I2C if chip is enabled (i.e. Hardware shutdown is disabled)
	else
	{
		// Enable hardware shutdown
		GPIOB_PCOR |= (1<<16);
		goto led_finish_scan;
	}

	// Only start if we haven't already
	// And if we've finished updating the buffers
	if ( Pixel_FrameState == FrameState_Sending )
		goto led_finish_scan;

	// Only send frame to ISSI chip if buffers are ready
	if ( Pixel_FrameState != FrameState_Ready )
		goto led_finish_scan;

	// Adjust frame rate (i.e. delay and do something else for a bit)
	Time duration = Time_duration( LED_timePrev );
	if ( duration.ms < LED_framerate )
		goto led_finish_scan;

	// FPS Display
	if ( LED_displayFPS )
	{
		// Show frame calculation
		dbug_msg("1frame/");
		printInt32( Time_ms( duration ) );
		print("ms + ");
		printInt32( duration.ticks );
		print(" ticks");

		// Check if we're not meeting frame rate
		if ( duration.ms > LED_framerate )
		{
			print(" - Could not meet framerate: ");
			printInt32( LED_framerate );
		}

		print( NL );
	}

	// Emulated brightness control
	// Lower brightness by LED_brightness
#if ISSI_Chip_31FL3731_define == 1
	uint8_t inverse_brightness = 0xFF - LED_brightness;
	for ( uint8_t chip = 0; chip < ISSI_Chips_define; chip++ )
	{
		for ( uint8_t ch = 0; ch < LED_BufferLength; ch++ )
		{
			// Don't modify is 0
			if ( LED_pageBuffer[ chip ].buffer[ ch ] == 0 )
			{
				LED_pageBuffer_brightness[ chip ].buffer[ ch ] = 0;
				continue;
			}

			LED_pageBuffer_brightness[ chip ].buffer[ ch ] =
				LED_pageBuffer[ chip ].buffer[ ch ] - inverse_brightness < 0
				? 0x0
				: LED_pageBuffer[ chip ].buffer[ ch ] - inverse_brightness;
		}
	}
#endif

	// Update frame start time
	LED_timePrev = Time_now();

	// Set the page of all the ISSI chips
	// This way we can easily link the buffers to send the brightnesses in the background
	for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
	{
		uint8_t bus = LED_ChannelMapping[ ch ].bus;
		// Page Setup
		LED_setupPage(
			bus,
			LED_ChannelMapping[ ch ].addr,
			ISSI_LEDPwmPage
		);

#if ISSI_Chip_31FL3731_define == 1 || ISSI_Chip_31FL3732_define == 1
		// Reset LED enable mask
		// XXX At high speeds, the IS31FL3732 seems to have random bit flips
		//     To get around this, just re-set the enable mask before each send
		// XXX Might be sufficient to do this every N frames though
		while ( i2c_send( bus, (uint16_t*)&LED_ledEnableMask[ ch ], sizeof( LED_EnableBuffer ) / 2 ) == -1 )
			delay_us( ISSI_SendDelay );
#endif
	}

	// Send current set of buffers
	// Uses interrupts to send to all the ISSI chips
	// Pixel_FrameState will be updated when complete
	LED_chipSend = 0; // Start with chip 0
	LED_linkedSend();

led_finish_scan:
	// Latency measurement end
	Latency_end_time( ledLatencyResource );
}