changeset 196:8ecfdaa27234

Basic Trigger and Result Macros are now working. - More complex macro not yet tested (long Trigger to long Result) - Long Trigger Macros not tested yet
author Jacob Alexander <haata@kiibohd.com>
date Wed, 20 Aug 2014 10:53:22 -0700
parents 58cfcb7bac88
children 1ebb6fb5f74f
files Macro/PartialMap/generatedKeymap.h Macro/PartialMap/macro.c
diffstat 2 files changed, 215 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/Macro/PartialMap/generatedKeymap.h	Sat Aug 16 12:07:25 2014 -0700
+++ b/Macro/PartialMap/generatedKeymap.h	Wed Aug 20 10:53:22 2014 -0700
@@ -188,6 +188,7 @@
 Guide_RM( 1 ) = { 1, 0, 0xBE, 1, 0, 0xEF, 0 };
 Guide_RM( 2 ) = { 2, 0, 0xFA, 0, 0xAD, 0 };
 Guide_RM( 3 ) = { 1, 1, 0xCA, 0xFE, 0 };
+Guide_RM( 4 ) = { 1, 0, 0xDA, 0 };
 
 
 // -- Result Macro List
@@ -202,6 +203,7 @@
 	Define_RM( 1 ),
 	Define_RM( 2 ),
 	Define_RM( 3 ),
+	Define_RM( 4 ),
 };
 
 
@@ -222,6 +224,12 @@
 Guide_TM( 2 ) = { 2, 0x00, 0x01, 0x73, 0x00, 0x01, 0x74, 0 };
 Guide_TM( 3 ) = { 1, 0x00, 0x01, 0x76, 0 };
 Guide_TM( 4 ) = { 1, 0x00, 0x01, 0x77, 0 };
+Guide_TM( 5 ) = { 1, 0x00, 0x01, 0x2E, 0 };
+Guide_TM( 6 ) = { 1, 0x00, 0x01, 0x2D, 0 };
+Guide_TM( 7 ) = { 1, 0x00, 0x01, 0x2C, 0 };
+Guide_TM( 8 ) = { 2, 0x00, 0x01, 0x20, 0x00, 0x01, 0x21, 0 };
+Guide_TM( 9 ) = { 1, 0x00, 0x01, 0x20, 1, 0x00, 0x01, 0x22, 0 };
+Guide_TM( 10 ) = { 1, 0x00, 0x01, 0x2B, 0 };
 
 
 // -- Trigger Macro List
@@ -237,6 +245,12 @@
 	Define_TM( 2, 2 ),
 	Define_TM( 3, 3 ),
 	Define_TM( 4, 0 ),
+	Define_TM( 5, 0 ),
+	Define_TM( 6, 1 ),
+	Define_TM( 7, 2 ),
+	Define_TM( 8, 0 ),
+	Define_TM( 9, 0 ), // TODO
+	Define_TM( 10, 4 ),
 };
 
 
@@ -294,8 +308,8 @@
 Define_TL( default, 0x1D ) = { 0 };
 Define_TL( default, 0x1E ) = { 0 };
 Define_TL( default, 0x1F ) = { 0 };
-Define_TL( default, 0x20 ) = { 0 };
-Define_TL( default, 0x21 ) = { 0 };
+Define_TL( default, 0x20 ) = { 1, 8 };
+Define_TL( default, 0x21 ) = { 1, 8 };
 Define_TL( default, 0x22 ) = { 0 };
 Define_TL( default, 0x23 ) = { 0 };
 Define_TL( default, 0x24 ) = { 0 };
@@ -305,10 +319,10 @@
 Define_TL( default, 0x28 ) = { 0 };
 Define_TL( default, 0x29 ) = { 0 };
 Define_TL( default, 0x2A ) = { 0 };
-Define_TL( default, 0x2B ) = { 0 };
-Define_TL( default, 0x2C ) = { 0 };
-Define_TL( default, 0x2D ) = { 0 };
-Define_TL( default, 0x2E ) = { 0 };
+Define_TL( default, 0x2B ) = { 1, 10 };
+Define_TL( default, 0x2C ) = { 1, 7 };
+Define_TL( default, 0x2D ) = { 1, 6 };
+Define_TL( default, 0x2E ) = { 1, 5 };
 Define_TL( default, 0x2F ) = { 0 };
 Define_TL( default, 0x30 ) = { 0 };
 Define_TL( default, 0x31 ) = { 0 };
--- a/Macro/PartialMap/macro.c	Sat Aug 16 12:07:25 2014 -0700
+++ b/Macro/PartialMap/macro.c	Wed Aug 20 10:53:22 2014 -0700
@@ -317,8 +317,11 @@
 
 // Append result macro to pending list, checking for duplicates
 // Do nothing if duplicate
-inline void Macro_appendResultMacroToPendingList( unsigned int resultMacroIndex )
+inline void Macro_appendResultMacroToPendingList( TriggerMacro *triggerMacro )
 {
+	// Lookup result macro index
+	unsigned int resultMacroIndex = triggerMacro->result;
+
 	// Iterate through result macro pending list, making sure this macro hasn't been added yet
 	for ( unsigned int macro = 0; macro < macroResultMacroPendingListSize; macro++ )
 	{
@@ -329,6 +332,29 @@
 
 	// No duplicates found, add to pending list
 	macroResultMacroPendingList[ macroResultMacroPendingListSize++ ] = resultMacroIndex;
+
+	// Lookup scanCode of the last key in the last combo
+	unsigned int pos = 0;
+	for ( uint8_t comboLength = triggerMacro->guide[0]; comboLength > 0; )
+	{
+		pos += TriggerGuideSize * comboLength + 1;
+		comboLength = triggerMacro->guide[ pos ];
+	}
+
+	uint8_t scanCode = ((TriggerGuide*)&triggerMacro->guide[ pos - TriggerGuideSize ])->scanCode;
+
+	// Lookup scanCode in buffer list for the current state and stateType
+	for ( uint8_t keyIndex = 0; keyIndex < macroTriggerListBufferSize; keyIndex++ )
+	{
+		if ( macroTriggerListBuffer[ keyIndex ].scanCode == scanCode )
+		{
+			ResultMacroList[ resultMacroIndex ].state     = macroTriggerListBuffer[ keyIndex ].state;
+			ResultMacroList[ resultMacroIndex ].stateType = macroTriggerListBuffer[ keyIndex ].type;
+		}
+	}
+
+	// Reset the macro position
+	ResultMacroList[ resultMacroIndex ].pos = 0;
 }
 
 
@@ -336,14 +362,78 @@
 inline uint8_t Macro_isLongResultMacro( ResultMacro *macro )
 {
 	// Check the second sequence combo length
-	// If non-zero return 1 (long sequence)
+	// If non-zero return non-zero (long sequence)
 	// 0 otherwise (short sequence)
-	return macro->guide[ macro->guide[0] * ResultGuideSize( (ResultGuide*)macro->guide ) ] > 0 ? 1 : 0;
+	unsigned int position = 1;
+	for ( unsigned int result = 0; result < macro->guide[0]; result++ )
+		position += ResultGuideSize( (ResultGuide*)&macro->guide[ position ] );
+	return macro->guide[ position ];
+}
+
+
+// Determine if long TriggerMacro (more than 1 sequence element)
+inline uint8_t Macro_isLongTriggerMacro( TriggerMacro *macro )
+{
+	// Check the second sequence combo length
+	// If non-zero return non-zero (long sequence)
+	// 0 otherwise (short sequence)
+	return macro->guide[ macro->guide[0] * TriggerGuideSize + 1 ];
 }
 
 
-// Votes on the given key vs. guide
-inline TriggerMacroVote Macro_evalTriggerMacroVote( TriggerGuide *key, TriggerGuide *guide )
+// 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;
+}
+
+
+// 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 )
@@ -419,14 +509,14 @@
 	if ( macro->state == TriggerMacro_Release )
 	{
 		macro->state = TriggerMacro_Waiting;
-		macro->pos = macro->pos + macro->guide[ macro->pos ] * TriggerGuideSize;
+		macro->pos = macro->pos + macro->guide[ macro->pos ] * TriggerGuideSize + 1;
 	}
 
 	// Current Macro position
 	unsigned int pos = macro->pos;
 
 	// Length of the combo being processed
-	uint8_t comboLength = macro->guide[ pos ];
+	uint8_t comboLength = macro->guide[ pos ] * TriggerGuideSize;
 
 	// If no combo items are left, remove the TriggerMacro from the pending list
 	if ( comboLength == 0 )
@@ -434,7 +524,10 @@
 		return TriggerMacroEval_Remove;
 	}
 
-	// Iterate through the key buffer, comparing to each key in the combo
+	// Check if this is a long Trigger Macro
+	uint8_t longMacro = Macro_isLongTriggerMacro( macro );
+
+	// Iterate through the items in the combo, voting the on the key state
 	// If any of the pressed keys do not match, fail the macro
 	//
 	// The macro is waiting for input when in the TriggerMacro_Waiting state
@@ -446,21 +539,23 @@
 	// TODO Add support for 0x00 Key state (not pressing a key, not all that useful in general)
 	// TODO Add support for Press/Hold/Release differentiation when evaluating (not sure if useful)
 	TriggerMacroVote overallVote = TriggerMacroVote_Invalid;
-	for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
+	for ( uint8_t comboItem = pos + 1; comboItem < pos + comboLength + 1; comboItem += TriggerGuideSize )
 	{
-		// Lookup key information
-		TriggerGuide *keyInfo = &macroTriggerListBuffer[ key ];
+		// Assign TriggerGuide element (key type, state and scancode)
+		TriggerGuide *guide = (TriggerGuide*)(&macro->guide[ comboItem ]);
 
-		// Iterate through the items in the combo, voting the on the key state
 		TriggerMacroVote vote = TriggerMacroVote_Invalid;
-		for ( uint8_t comboItem = pos + 1; comboItem < pos + comboLength + 1; comboItem += TriggerGuideSize )
+		// Iterate through the key buffer, comparing to each key in the combo
+		for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
 		{
-			// Assign TriggerGuide element (key type, state and scancode)
-			TriggerGuide *guide = (TriggerGuide*)(&macro->guide[ comboItem ]);
+			// Lookup key information
+			TriggerGuide *keyInfo = &macroTriggerListBuffer[ key ];
 
 			// If vote is a pass (>= 0x08, no more keys in the combo need to be looked at)
 			// Also mask all of the non-passing votes
-			vote |= Macro_evalTriggerMacroVote( keyInfo, guide );
+			vote |= longMacro
+				? Macro_evalLongTriggerMacroVote( keyInfo, guide )
+				: Macro_evalShortTriggerMacroVote( keyInfo, guide );
 			if ( vote >= TriggerMacroVote_Pass )
 			{
 				vote &= TriggerMacroVote_Release | TriggerMacroVote_PassRelease | TriggerMacroVote_Pass;
@@ -468,6 +563,11 @@
 			}
 		}
 
+		// If no pass vote was found after scanning all of the keys
+		// Fail the combo, if this is a short macro (long macros already will have a fail vote)
+		if ( !longMacro && vote < TriggerMacroVote_Pass )
+			vote |= TriggerMacroVote_Fail;
+
 		// After voting, append to overall vote
 		overallVote |= vote;
 	}
@@ -479,35 +579,68 @@
 		return TriggerMacroEval_Remove;
 	}
 	// Do nothing, incorrect key is being held or released
-	else if ( overallVote & TriggerMacroVote_DoNothing )
+	else if ( overallVote & TriggerMacroVote_DoNothing && longMacro )
 	{
 		// Just doing nothing :)
 	}
 	// If passing and in Waiting state, set macro state to Press
-	else if ( overallVote & TriggerMacroVote_Pass && macro->state == TriggerMacro_Waiting )
+	else if ( overallVote & TriggerMacroVote_Pass
+	     && ( macro->state == TriggerMacro_Waiting || macro->state == TriggerMacro_Press ) )
 	{
 		macro->state = TriggerMacro_Press;
 
 		// If in press state, and this is the final combo, send request for ResultMacro
 		// Check to see if the result macro only has a single element
 		// If this result macro has more than 1 key, only send once
-		// TODO Add option to have macro repeat rate
-		if ( macro->guide[ pos + comboLength ] == 0 )
+		// TODO Add option to have long macro repeat rate
+		if ( macro->guide[ pos + comboLength + 1 ] == 0 )
 		{
-			// Long Macro, only send once (more than 1 sequence item)
-			// Short Macro (only 1 sequence item)
-			return Macro_isLongResultMacro( &ResultMacroList[ macro->result ] )
-				? TriggerMacroEval_DoResult
-				: TriggerMacroEval_DoResultAndRemove;
+			// Long result macro (more than 1 combo)
+			if ( Macro_isLongResultMacro( &ResultMacroList[ macro->result ] ) )
+			{
+				// Only ever trigger result once, on press
+				if ( overallVote == TriggerMacroVote_Pass )
+				{
+					return TriggerMacroEval_DoResultAndRemove;
+				}
+			}
+			// Short result macro
+			else
+			{
+				// Only trigger result once, on press, if long trigger (more than 1 combo)
+				if ( Macro_isLongTriggerMacro( macro ) )
+				{
+					return TriggerMacroEval_DoResultAndRemove;
+				}
+				// Otherwise, trigger result continuously
+				else
+				{
+					return TriggerMacroEval_DoResult;
+				}
+			}
 		}
-
 	}
 	// If ready for transition and in Press state, set to Waiting and increment combo position
 	// Position is incremented (and possibly remove the macro from the pending list) on the next iteration
 	else if ( overallVote & TriggerMacroVote_Release && macro->state == TriggerMacro_Press )
 	{
 		macro->state = TriggerMacro_Release;
+
+		// If this is the last combo in the sequence, remove from the pending list
+		if ( macro->guide[ macro->pos + macro->guide[ macro->pos ] * TriggerGuideSize + 1 ] == 0 )
+			return TriggerMacroEval_Remove;
 	}
+	// Otherwise, just remove the macro on key release
+	// XXX Might cause some issues
+	else if ( overallVote & TriggerMacroVote_Release )
+	{
+		return TriggerMacroEval_Remove;
+	}
+
+	// If this is a short macro, just remove it
+	// The state can be rebuilt on the next iteration
+	if ( !longMacro )
+		return TriggerMacroEval_Remove;
 
 	return TriggerMacroEval_DoNothing;
 }
@@ -525,12 +658,6 @@
 	// Length of combo being processed
 	uint8_t comboLength = macro->guide[ pos ];
 
-	// If no combo items are left, remove the ResultMacro from the pending list
-	if ( comboLength == 0 )
-	{
-		return ResultMacroEval_Remove;
-	}
-
 	// Function Counter, used to keep track of the combo items processed
 	unsigned int funcCount = 0;
 
@@ -541,7 +668,7 @@
 	while ( funcCount < comboLength )
 	{
 		// Assign TriggerGuide element (key type, state and scancode)
-		ResultGuide *guide = (ResultGuide*)(&macro->guide[ pos ]);
+		ResultGuide *guide = (ResultGuide*)(&macro->guide[ comboItem ]);
 
 		// Do lookup on capability function
 		void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ guide->index ].func);
@@ -557,17 +684,29 @@
 	// Move to next item in the sequence
 	macro->pos = comboItem;
 
-	// If the ResultMacro is finished, it will be removed on the next iteration
+	// If the ResultMacro is finished, remove
+	if ( macro->guide[ comboItem ] == 0 )
+	{
+		return ResultMacroEval_Remove;
+	}
+
+	// Otherwise leave the macro in the list
 	return ResultMacroEval_DoNothing;
 }
 
 
 // Update pending trigger list
-void Macro_updateTriggerMacroPendingList()
+inline void Macro_updateTriggerMacroPendingList()
 {
 	// Iterate over the macroTriggerListBuffer to add any new Trigger Macros to the pending list
 	for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
 	{
+		// TODO LED States
+		// TODO Analog Switches
+		// Only add TriggerMacro to pending list if key was pressed (not held, released or off)
+		if ( macroTriggerListBuffer[ key ].state == 0x00 && macroTriggerListBuffer[ key ].state != 0x01 )
+			continue;
+
 		// Lookup Trigger List
 		unsigned int *triggerList = Macro_layerLookup( macroTriggerListBuffer[ key ].scanCode );
 
@@ -596,6 +735,10 @@
 			if ( pending == macroTriggerMacroPendingListSize )
 			{
 				macroTriggerMacroPendingList[ macroTriggerMacroPendingListSize++ ] = triggerMacroIndex;
+
+				// Reset macro position
+				TriggerMacroList[ triggerMacroIndex ].pos   = 0;
+				TriggerMacroList[ triggerMacroIndex ].state = TriggerMacro_Waiting;
 			}
 		}
 	}
@@ -636,20 +779,23 @@
 		// Trigger Result Macro (purposely falling through)
 		case TriggerMacroEval_DoResult:
 			// Append ResultMacro to PendingList
-			Macro_appendResultMacroToPendingList( TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ].result );
+			Macro_appendResultMacroToPendingList( &TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ] );
+			print("D");
 
-		// Otherwise, just re-add
 		default:
 			macroTriggerMacroPendingList[ macroTriggerMacroPendingListTail++ ] = macroTriggerMacroPendingList[ macro ];
+			print("A");
 			break;
 
 		// Trigger Result Macro and Remove (purposely falling through)
 		case TriggerMacroEval_DoResultAndRemove:
 			// Append ResultMacro to PendingList
-			Macro_appendResultMacroToPendingList( TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ].result );
+			Macro_appendResultMacroToPendingList( &TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ] );
+			print("&");
 
 		// Remove Macro from Pending List, nothing to do, removing by default
 		case TriggerMacroEval_Remove:
+			print("R");
 			break;
 		}
 	}
@@ -717,8 +863,8 @@
 	// Initialize TriggerMacro states
 	for ( unsigned int macro = 0; macro < TriggerMacroNum; macro++ )
 	{
-		TriggerMacroList[ macro ].pos    = 0;
-		TriggerMacroList[ macro ].state  = TriggerMacro_Waiting;
+		TriggerMacroList[ macro ].pos   = 0;
+		TriggerMacroList[ macro ].state = TriggerMacro_Waiting;
 	}
 
 	// Initialize ResultMacro states
@@ -1114,6 +1260,15 @@
 	// Display result macro index
 	print( NL "Result Macro Index: " );
 	printInt16( (uint16_t)macro->result ); // Hopefully large enough :P (can't assume 32-bit)
+
+	// Display trigger macro state
+	print( NL "Trigger Macro State: " );
+	switch ( macro->state )
+	{
+	case TriggerMacro_Press:   print("Press");   break;
+	case TriggerMacro_Release: print("Release"); break;
+	case TriggerMacro_Waiting: print("Waiting"); break;
+	}
 }
 
 void macroDebugShowResult( unsigned int index )