# HG changeset patch # User Jacob Alexander # Date 1408557202 25200 # Node ID 8ecfdaa27234a02eaafe5e429564a89b44825334 # Parent 58cfcb7bac8833d9db885908428e5573f02a63a0 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 diff -r 58cfcb7bac88 -r 8ecfdaa27234 Macro/PartialMap/generatedKeymap.h --- 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 }; diff -r 58cfcb7bac88 -r 8ecfdaa27234 Macro/PartialMap/macro.c --- 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*)¯o->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 = ¯oTriggerListBuffer[ key ]; + // Assign TriggerGuide element (key type, state and scancode) + TriggerGuide *guide = (TriggerGuide*)(¯o->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*)(¯o->guide[ comboItem ]); + // Lookup key information + TriggerGuide *keyInfo = ¯oTriggerListBuffer[ 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*)(¯o->guide[ pos ]); + ResultGuide *guide = (ResultGuide*)(¯o->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 )