changeset 384:82ce1988fefe

Adding basic ISSI led brightness control capabilities - 6 modes * Single led: decrease, increase, set * All leds: decrease, increase, set - Currently update speed limited to once every 30 ms * Likely an I2C driver or ISSI limitation preventing even faster updates
author Jacob Alexander <haata@kiibohd.com>
date Fri, 09 Oct 2015 22:28:31 -0700
parents 801e7628d977
children d8f61e15aca1
files Scan/ISSILed/capabilities.kll Scan/ISSILed/led_scan.c
diffstat 2 files changed, 219 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/Scan/ISSILed/capabilities.kll	Fri Oct 09 18:18:07 2015 -0700
+++ b/Scan/ISSILed/capabilities.kll	Fri Oct 09 22:28:31 2015 -0700
@@ -1,10 +1,26 @@
 Name = ISSILedCapabilities;
-Version = 0.1;
+Version = 0.2;
 Author = "HaaTa (Jacob Alexander) 2015";
 KLL = 0.3c;
 
 # Modified Date
-Date = 2015-08-02;
+Date = 2015-10-09;
+
+# Basic ISSI Capabilities
+# Modes
+#  0: Decrease single led brightness
+#  1: Increase single led brightness
+#  2: Set single led brightness
+#  3: Decrease brightness of all leds
+#  4: Increase brightness of all leds
+#  5: Set brightness of all leds
+# Amount -> 0 -> 255
+# Index:
+#  Depends on keyboard. At least from from 0 -> 143 (single chip).
+#  Remember, it may be possible that all leds on a single chip are connected.
+#  So it may be possible that you may have index gaps.
+#  i.e. 23 then 144
+ledControl => LED_control_capability( mode : 1, amount : 1, index : 2 );
 
 # Defines available to the ISSILed sub-module
 
--- a/Scan/ISSILed/led_scan.c	Fri Oct 09 18:18:07 2015 -0700
+++ b/Scan/ISSILed/led_scan.c	Fri Oct 09 22:28:31 2015 -0700
@@ -49,6 +49,8 @@
 } I2C_Buffer;
 
 typedef struct LED_Buffer {
+	uint8_t i2c_addr;
+	uint8_t reg_addr;
 	uint8_t buffer[LED_BufferLength];
 } LED_Buffer;
 
@@ -59,6 +61,7 @@
 // CLI Functions
 void cliFunc_i2cRecv ( char* args );
 void cliFunc_i2cSend ( char* args );
+void cliFunc_ledCtrl ( char* args );
 void cliFunc_ledRPage( char* args );
 void cliFunc_ledStart( char* args );
 void cliFunc_ledTest ( char* args );
@@ -77,6 +80,7 @@
 // Scan Module command dictionary
 CLIDict_Entry( i2cRecv,     "Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence." NL "\t\tUse |'s to split sequences with a stop." );
 CLIDict_Entry( i2cSend,     "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
+CLIDict_Entry( ledCtrl,     "Basic LED control. Args: <mode> <amount> [<index>]" );
 CLIDict_Entry( ledRPage,    "Read the given register page." );
 CLIDict_Entry( ledStart,    "Disable software shutdown." );
 CLIDict_Entry( ledTest,     "Test out the led pages." );
@@ -86,6 +90,7 @@
 CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = {
 	CLIDict_Item( i2cRecv ),
 	CLIDict_Item( i2cSend ),
+	CLIDict_Item( ledCtrl ),
 	CLIDict_Item( ledRPage ),
 	CLIDict_Item( ledStart ),
 	CLIDict_Item( ledTest ),
@@ -178,7 +183,9 @@
 			}
 			else
 			{
-				dbug_print("Attempting to read byte");
+				dbug_msg("Attempting to read byte - ");
+				printHex( I2C_RxBuffer.sequencePos );
+				print( NL );
 				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
@@ -309,34 +316,6 @@
 
 }
 
-void LED_readPage( uint8_t len, uint8_t page )
-{
-	// Page Setup
-	uint8_t pageSetup[] = { 0xE8, 0xFD, page };
-
-	// Setup page
-	while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
-		delay(1);
-
-	// Register Setup
-	uint8_t regSetup[] = { 0xE8, 0x00 };
-
-	// Setup starting register
-	while ( I2C_Send( regSetup, sizeof( regSetup ), 0 ) == 0 )
-		delay(1);
-
-	// Register Read Command
-	uint8_t regReadCmd[] = { 0xE9 };
-
-	// Read each register in the page
-	for ( uint8_t reg = 0; reg < len; reg++ )
-	{
-		// Request register data
-		while ( I2C_Send( regReadCmd, sizeof( regReadCmd ), 0 ) == 0 )
-			delay(1);
-	}
-}
-
 void LED_writeReg( uint8_t reg, uint8_t val, uint8_t page )
 {
 	// Page Setup
@@ -353,6 +332,44 @@
 		delay(1);
 }
 
+void LED_readPage( uint8_t len, uint8_t page )
+{
+	// Software shutdown must be enabled to read registers
+	LED_writeReg( 0x0A, 0x00, 0x0B );
+
+	// Page Setup
+	uint8_t pageSetup[] = { 0xE8, 0xFD, page };
+
+	// Setup page
+	while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
+		delay(1);
+
+	// Register Setup
+	uint8_t regSetup[] = { 0xE8, 0x00 };
+
+	// Read each register in the page
+	for ( uint8_t reg = 0; reg < len; reg++ )
+	{
+		// Update register to read
+		regSetup[1] = reg;
+
+		// Configure register
+		while ( I2C_Send( regSetup, sizeof( regSetup ), 0 ) == 0 )
+			delay(1);
+
+		// Register Read Command
+		uint8_t regReadCmd[] = { 0xE9 };
+
+		// Request single register byte
+		while ( I2C_Send( regReadCmd, sizeof( regReadCmd ), 1 ) == 0 )
+			delay(1);
+		dbug_print("NEXT");
+	}
+
+	// Disable software shutdown
+	LED_writeReg( 0x0A, 0x01, 0x0B );
+}
+
 // Setup
 inline void LED_setup()
 {
@@ -619,8 +636,122 @@
 
 
 
+// ----- Capabilities -----
+
+// Basic LED Control Capability
+typedef enum LedControlMode {
+	// Single LED Modes
+	LedControlMode_brightness_decrease,
+	LedControlMode_brightness_increase,
+	LedControlMode_brightness_set,
+	// Set all LEDs (index argument not required)
+	LedControlMode_brightness_decrease_all,
+	LedControlMode_brightness_increase_all,
+	LedControlMode_brightness_set_all,
+} LedControlMode;
+
+typedef struct LedControl {
+	LedControlMode mode;   // XXX Make sure to adjust the .kll capability if this variable is larger than 8 bits
+	uint8_t        amount;
+	uint16_t       index;
+} LedControl;
+
+uint8_t LED_control_timer = 0;
+void LED_control( LedControl *control )
+{
+	// Only send if we've completed all other transactions
+	if ( I2C_TxBuffer.sequencePos > 0 )
+		return;
+
+	// XXX
+	// ISSI Chip locks up if we spam updates too quickly (might be an I2C bug on this side too -HaaTa)
+	// Make sure we only send an update every 30 milliseconds at most
+	// It may be possible to optimize speed even further, but will likely require serious time with a logic analyzer
+
+	uint8_t currentTime = (uint8_t)systick_millis_count;
+	int8_t compare = (int8_t)(currentTime - LED_control_timer) & 0x7F;
+	if ( compare < 30 )
+	{
+		return;
+	}
+	LED_control_timer = currentTime;
+
+	// Configure based upon the given mode
+	// TODO Handle multiple issi chips per node
+	// TODO Perhaps do gamma adjustment?
+	switch ( control->mode )
+	{
+	case LedControlMode_brightness_decrease:
+		// Don't worry about rolling over, the cycle is quick
+		LED_pageBuffer.buffer[ control->index ] -= control->amount;
+		break;
+
+	case LedControlMode_brightness_increase:
+		// Don't worry about rolling over, the cycle is quick
+		LED_pageBuffer.buffer[ control->index ] += control->amount;
+		break;
+
+	case LedControlMode_brightness_set:
+		LED_pageBuffer.buffer[ control->index ] = control->amount;
+		break;
+
+	case LedControlMode_brightness_decrease_all:
+		for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
+		{
+			// Don't worry about rolling over, the cycle is quick
+			LED_pageBuffer.buffer[ channel ] -= control->amount;
+		}
+		break;
+
+	case LedControlMode_brightness_increase_all:
+		for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
+		{
+			// Don't worry about rolling over, the cycle is quick
+			LED_pageBuffer.buffer[ channel ] += control->amount;
+		}
+		break;
+
+	case LedControlMode_brightness_set_all:
+		for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
+		{
+			LED_pageBuffer.buffer[ channel ] = control->amount;
+		}
+		break;
+	}
+
+	// Sync LED buffer with ISSI chip buffer
+	// TODO Support multiple frames
+	LED_pageBuffer.i2c_addr = 0xE8; // Chip 1
+	LED_pageBuffer.reg_addr = 0x24; // Brightness section
+	LED_sendPage( (uint8_t*)&LED_pageBuffer, sizeof( LED_Buffer ), 0 );
+}
+
+void LED_control_capability( uint8_t state, uint8_t stateType, uint8_t *args )
+{
+	// Display capability name
+	if ( stateType == 0xFF && state == 0xFF )
+	{
+		print("LED_control_capability(mode,amount,index)");
+		return;
+	}
+
+	// Only use capability on press
+	// TODO Analog
+	if ( stateType == 0x00 && state == 0x03 ) // Not on release
+		return;
+
+	// Set the input structure
+	LedControl *control = (LedControl*)args;
+
+	// TODO broadcast to rest of interconnect nodes if necessary
+	LED_control( control );
+}
+
+
+
 // ----- CLI Command Functions -----
 
+// TODO Currently not working correctly
 void cliFunc_i2cSend( char* args )
 {
 	char* curArgs;
@@ -717,6 +848,7 @@
 	I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip
 }
 
+// TODO Currently not working correctly
 void cliFunc_ledRPage( char* args )
 {
 	// Parse number from argument
@@ -730,13 +862,14 @@
 
 	if ( arg1Ptr[0] != '\0' )
 	{
-		 page = (uint8_t)numToInt( arg1Ptr );
+		page = (uint8_t)numToInt( arg1Ptr );
 	}
 
 	// No \r\n by default after the command is entered
 	print( NL );
 
-	LED_readPage( 0xB4, page );
+	LED_readPage( 0x1, page );
+	//LED_readPage( 0xB4, page );
 }
 
 void cliFunc_ledWPage( char* args )
@@ -809,3 +942,40 @@
 	LED_zeroPages( 0x00, 8, 0x24, 0xB4 ); // Only PWMs
 }
 
+void cliFunc_ledCtrl( char* args )
+{
+	char* curArgs;
+	char* arg1Ptr;
+	char* arg2Ptr = args;
+	LedControl control;
+
+	// First process mode
+	curArgs = arg2Ptr;
+	CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
+
+	// Stop processing args if no more are found
+	if ( *arg1Ptr == '\0' )
+		return;
+	control.mode = numToInt( arg1Ptr );
+
+
+	// Next process amount
+	curArgs = arg2Ptr;
+	CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
+
+	// Stop processing args if no more are found
+	if ( *arg1Ptr == '\0' )
+		return;
+	control.amount = numToInt( arg1Ptr );
+
+
+	// Finally process led index, if it exists
+	// Default to 0
+	curArgs = arg2Ptr;
+	CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
+	control.index = *arg1Ptr == '\0' ? 0 : numToInt( arg1Ptr );
+
+	// Process request
+	LED_control( &control );
+}
+