#include "usb_hid.h"
#include <generatedKeymap.h> // Generated using kll at compile time, in build directory
+// Connect Includes
+#if defined(ConnectEnabled_define)
+#include <connect_scan.h>
+#endif
+
// Local Includes
#include "macro.h"
void cliFunc_keyHold ( char* args );
void cliFunc_keyPress ( char* args );
void cliFunc_keyRelease( char* args );
+void cliFunc_layerDebug( char* args );
void cliFunc_layerList ( char* args );
void cliFunc_layerState( char* args );
void cliFunc_macroDebug( char* args );
CLIDict_Entry( keyHold, "Send key-hold events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
CLIDict_Entry( keyPress, "Send key-press events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
CLIDict_Entry( keyRelease, "Send key-release event to macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
+CLIDict_Entry( layerDebug, "Layer debug mode. Shows layer stack and any changes." );
CLIDict_Entry( layerList, "List available layers." );
CLIDict_Entry( layerState, "Modify specified indexed layer state <layer> <state byte>." NL "\t\t\033[35mL2\033[0m Indexed Layer 0x02" NL "\t\t0 Off, 1 Shift, 2 Latch, 4 Lock States" );
CLIDict_Entry( macroDebug, "Disables/Enables sending USB keycodes to the Output Module and prints U/K codes." );
CLIDict_Item( keyHold ),
CLIDict_Item( keyPress ),
CLIDict_Item( keyRelease ),
+ CLIDict_Item( layerDebug ),
CLIDict_Item( layerList ),
CLIDict_Item( layerState ),
CLIDict_Item( macroDebug ),
};
+// Layer debug flag - If set, displays any changes to layers and the full layer stack on change
+uint8_t layerDebugMode = 0;
+
// Macro debug flag - If set, clears the USB Buffers after signalling processing completion
uint8_t macroDebugMode = 0;
// Key Trigger List Buffer and Layer Cache
// The layer cache is set on press only, hold and release events refer to the value set on press
TriggerGuide macroTriggerListBuffer[ MaxScanCode ];
-uint8_t macroTriggerListBufferSize = 0;
+var_uint_t macroTriggerListBufferSize = 0;
var_uint_t macroTriggerListLayerCache[ MaxScanCode ];
// Pending Trigger Macro Index List
uint16_t macroResultMacroPendingList[ ResultMacroNum ] = { 0 };
uint16_t macroResultMacroPendingListSize = 0;
+// Interconnect ScanCode Cache
+#if defined(ConnectEnabled_define)
+// TODO This can be shrunk by the size of the max node 0 ScanCode
+TriggerGuide macroInterconnectCache[ MaxScanCode ];
+uint8_t macroInterconnectCacheSize = 0;
+#endif
+
// ----- Capabilities -----
// Sets the given layer with the specified layerState
void Macro_layerState( uint8_t state, uint8_t stateType, uint16_t layer, uint8_t layerState )
{
- // Ignore if layer does not exist
- if ( layer >= LayerNum )
+ // Ignore if layer does not exist or trying to manipulate layer 0/Default layer
+ if ( layer >= LayerNum || layer == 0 )
return;
// Is layer in the LayerIndexStack?
// Reduce LayerIndexStack size
macroLayerIndexStackSize--;
}
+
+ // Layer Debug Mode
+ if ( layerDebugMode )
+ {
+ dbug_msg("Layer ");
+
+ // Iterate over each of the layers displaying the state as a hex value
+ for ( uint16_t index = 0; index < LayerNum; index++ )
+ {
+ printHex_op( LayerState[ index ], 0 );
+ }
+
+ // Always show the default layer (it's always 0)
+ print(" 0");
+
+ // Iterate over the layer stack starting from the bottom of the stack
+ for ( uint16_t index = macroLayerIndexStackSize; index > 0; index-- )
+ {
+ print(":");
+ printHex_op( macroLayerIndexStack[ index - 1 ], 0 );
+ }
+
+ print( NL );
+ }
}
// Modifies the specified Layer control byte
}
+// Rotate layer to next/previous
+// Uses state variable to keep track of the current layer position
+// Layers are still evaluated using the layer stack
+uint16_t Macro_rotationLayer;
+void Macro_layerRotate_capability( uint8_t state, uint8_t stateType, uint8_t *args )
+{
+ // Display capability name
+ if ( stateType == 0xFF && state == 0xFF )
+ {
+ print("Macro_layerRotate(previous)");
+ return;
+ }
+
+ // Only use capability on press
+ // TODO Analog
+ // XXX Could also be on release, but that's sorta dumb -HaaTa
+ if ( stateType == 0x00 && state != 0x01 ) // All normal key conditions except press
+ return;
+
+ // Unset previous rotation layer if not 0
+ if ( Macro_rotationLayer != 0 )
+ {
+ Macro_layerState( state, stateType, Macro_rotationLayer, 0x04 );
+ }
+
+ // Get direction of rotation, 0, next, non-zero previous
+ uint8_t direction = *args;
+
+ // Next
+ if ( !direction )
+ {
+ Macro_rotationLayer++;
+
+ // Invalid layer
+ if ( Macro_rotationLayer >= LayerNum )
+ Macro_rotationLayer = 0;
+ }
+ // Previous
+ else
+ {
+ Macro_rotationLayer--;
+
+ // Layer wrap
+ if ( Macro_rotationLayer >= LayerNum )
+ Macro_rotationLayer = LayerNum - 1;
+ }
+
+ // Toggle the computed layer rotation
+ Macro_layerState( state, stateType, Macro_rotationLayer, 0x04 );
+}
+
+
// ----- Functions -----
nat_ptr_t **map = (nat_ptr_t**)LayerIndex[ cachedLayer ].triggerMap;
const Layer *layer = &LayerIndex[ cachedLayer ];
- return map[ scanCode - layer->first ];
+ // Cache trigger list before attempting to expire latch
+ nat_ptr_t *trigger_list = map[ scanCode - layer->first ];
+
+ // Check if latch has been pressed for this layer
+ uint8_t latch = LayerState[ cachedLayer ] & 0x02;
+ if ( latch && latch_expire )
+ {
+ Macro_layerState( 0, 0, cachedLayer, 0x02 );
+#if defined(ConnectEnabled_define) && defined(LCDEnabled_define)
+ // Evaluate the layerStack capability if available (LCD + Interconnect)
+ extern void LCD_layerStack_capability( uint8_t state, uint8_t stateType, uint8_t *args );
+ LCD_layerStack_capability( 0, 0, 0 );
+#endif
+ }
+
+ return trigger_list;
}
// If no trigger macro is defined at the given layer, fallthrough to the next layer
- for ( uint16_t layerIndex = 0; layerIndex < macroLayerIndexStackSize; layerIndex++ )
+ for ( uint16_t layerIndex = macroLayerIndexStackSize; layerIndex != 0xFFFF; layerIndex-- )
{
// Lookup Layer
const Layer *layer = &LayerIndex[ macroLayerIndexStack[ layerIndex ] ];
// Determine if layer has key defined
// Make sure scanCode is between layer first and last scancodes
if ( map != 0
- && scanCode <= layer->last
- && scanCode >= layer->first
- && *map[ scanCode - layer->first ] != 0 )
+ && scanCode <= layer->last
+ && scanCode >= layer->first
+ && *map[ scanCode - layer->first ] != 0 )
{
// Set the layer cache
macroTriggerListLayerCache[ scanCode ] = macroLayerIndexStack[ layerIndex ];
// Make sure scanCode is between layer first and last scancodes
if ( map != 0
- && scanCode <= layer->last
- && scanCode >= layer->first
- && *map[ scanCode - layer->first ] != 0 )
+ && scanCode <= layer->last
+ && scanCode >= layer->first
+ && *map[ scanCode - layer->first ] != 0 )
{
// Set the layer cache to default map
macroTriggerListLayerCache[ scanCode ] = 0;
// Otherwise no defined Trigger Macro
erro_msg("Scan Code has no defined Trigger Macro: ");
printHex( scanCode );
+ print( NL );
return 0;
}
+// Add an interconnect ScanCode
+// These are handled differently (less information is sent, hold/off states must be assumed)
+#if defined(ConnectEnabled_define)
+inline void Macro_interconnectAdd( void *trigger_ptr )
+{
+ TriggerGuide *trigger = (TriggerGuide*)trigger_ptr;
+
+ // Error checking
+ uint8_t error = 0;
+ switch ( trigger->type )
+ {
+ case 0x00: // Normal key
+ switch ( trigger->state )
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ break;
+ default:
+ erro_msg("Invalid key state - ");
+ error = 1;
+ break;
+ }
+ break;
+
+ // Invalid TriggerGuide type
+ default:
+ erro_msg("Invalid type - ");
+ error = 1;
+ break;
+ }
+
+ // Check if ScanCode is out of range
+ if ( trigger->scanCode > MaxScanCode )
+ {
+ warn_msg("ScanCode is out of range/not defined - ");
+ error = 1;
+ }
+
+ // Display TriggerGuide
+ if ( error )
+ {
+ printHex( trigger->type );
+ print(" ");
+ printHex( trigger->state );
+ print(" ");
+ printHex( trigger->scanCode );
+ print( NL );
+ return;
+ }
+
+ // Add trigger to the Interconnect Cache
+ // During each processing loop, a scancode may be re-added depending on it's state
+ for ( var_uint_t c = 0; c < macroInterconnectCacheSize; c++ )
+ {
+ // Check if the same ScanCode
+ if ( macroInterconnectCache[ c ].scanCode == trigger->scanCode )
+ {
+ // Update the state
+ macroInterconnectCache[ c ].state = trigger->state;
+ return;
+ }
+ }
+
+ // If not in the list, add it
+ macroInterconnectCache[ macroInterconnectCacheSize++ ] = *trigger;
+}
+#endif
+
+
// Update the scancode key state
// States:
// * 0x00 - Off
// * 0x04 - Unpressed (this is currently ignored)
inline void Macro_keyState( uint8_t scanCode, uint8_t state )
{
+#if defined(ConnectEnabled_define)
+ // Only compile in if a Connect node module is available
+ if ( !Connect_master )
+ {
+ // ScanCodes are only added if there was a state change (on/off)
+ switch ( state )
+ {
+ case 0x00: // Off
+ case 0x02: // Held
+ return;
+ }
+ }
+#endif
+
// Only add to macro trigger list if one of three states
switch ( state )
{
case 0x01: // Pressed
case 0x02: // Held
case 0x03: // Released
+ // Check if ScanCode is out of range
+ if ( scanCode > MaxScanCode )
+ {
+ warn_msg("ScanCode is out of range/not defined: ");
+ printHex( scanCode );
+ print( NL );
+ return;
+ }
+
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x00; // Normal key
inline void Macro_analogState( uint8_t scanCode, uint8_t state )
{
// Only add to macro trigger list if non-off
+ // TODO Handle change for interconnect
if ( state != 0x00 )
{
+ // Check if ScanCode is out of range
+ if ( scanCode > MaxScanCode )
+ {
+ warn_msg("ScanCode is out of range/not defined: ");
+ printHex( scanCode );
+ print( NL );
+ return;
+ }
+
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x02; // Analog key
inline void Macro_ledState( uint8_t ledCode, uint8_t state )
{
// Only add to macro trigger list if non-off
+ // TODO Handle change for interconnect
if ( state != 0x00 )
{
+ // Check if LedCode is out of range
+ // TODO
+
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = ledCode;
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x01; // LED key
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++ )
+ for ( var_uint_t keyIndex = 0; keyIndex < macroTriggerListBufferSize; keyIndex++ )
{
if ( macroTriggerListBuffer[ keyIndex ].scanCode == scanCode )
{
TriggerMacroVote vote = TriggerMacroVote_Invalid;
// Iterate through the key buffer, comparing to each key in the combo
- for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
+ for ( var_uint_t key = 0; key < macroTriggerListBufferSize; key++ )
{
// Lookup key information
TriggerGuide *keyInfo = ¯oTriggerListBuffer[ key ];
}
// If passing and in Waiting state, set macro state to Press
else if ( overallVote & TriggerMacroVote_Pass
- && ( record->state == TriggerMacro_Waiting || record->state == TriggerMacro_Press ) )
+ && ( record->state == TriggerMacro_Waiting || record->state == TriggerMacro_Press ) )
{
record->state = TriggerMacro_Press;
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++ )
+ for ( var_uint_t key = 0; key < macroTriggerListBufferSize; key++ )
{
// TODO LED States
// TODO Analog Switches
// Lookup Trigger List
nat_ptr_t *triggerList = Macro_layerLookup( ¯oTriggerListBuffer[ key ], latch_expire );
+ // If there was an error during lookup, skip
+ if ( triggerList == 0 )
+ continue;
+
// Number of Triggers in list
nat_ptr_t triggerListSize = triggerList[0];
// Called once per USB buffer send
inline void Macro_process()
{
+#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 ( macroTriggerListBufferSize > 0 )
+ {
+ Connect_send_ScanCode( Connect_id, macroTriggerListBuffer, macroTriggerListBufferSize );
+ macroTriggerListBufferSize = 0;
+ }
+ return;
+ }
+#endif
+
// Only do one round of macro processing between Output Module timer sends
if ( USBKeys_Sent != 0 )
return;
+#if defined(ConnectEnabled_define)
+ // Check if there are any ScanCodes in the interconnect cache to process
+ if ( Connect_master && macroInterconnectCacheSize > 0 )
+ {
+ // 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
+ macroTriggerListBuffer[ macroTriggerListBufferSize++ ] = macroInterconnectCache[ c ];
+
+ // TODO Handle other TriggerGuide types (e.g. analog)
+ switch ( macroInterconnectCache[ c ].type )
+ {
+ // Normal (Press/Hold/Release)
+ case 0x00:
+ // Decide what to do based on the current state
+ switch ( macroInterconnectCache[ c ].state )
+ {
+ // Re-add to interconnect cache in hold state
+ case 0x01: // Press
+ //case 0x02: // Hold // XXX Why does this not work? -HaaTa
+ macroInterconnectCache[ c ].state = 0x02;
+ macroInterconnectCache[ macroInterconnectCacheSize++ ] = macroInterconnectCache[ c ];
+ break;
+ case 0x03: // Remove
+ break;
+ // Otherwise, do not re-add
+ }
+ }
+ }
+ }
+#endif
+
// If the pause flag is set, only process if the step counter is non-zero
if ( macroPauseMode )
{
// Make sure macro trigger buffer is empty
macroTriggerListBufferSize = 0;
+ // Set the current rotated layer to 0
+ Macro_rotationLayer = 0;
+
// Initialize TriggerMacro states
for ( var_uint_t macro = 0; macro < TriggerMacroNum; macro++ )
{
printHex( argSet[2] );
print( "..." NL );
+ // Make sure this isn't the reload capability
+ // If it is, and the remote reflash define is not set, ignore
+ if ( flashModeEnabled_define == 0 ) for ( uint32_t cap = 0; cap < CapabilitiesNum; cap++ )
+ {
+ if ( CapabilitiesList[ cap ].func == (const void*)Output_flashMode_capability )
+ {
+ print( NL );
+ warn_print("flashModeEnabled not set, cancelling firmware reload...");
+ info_msg("Set flashModeEnabled to 1 in your kll configuration.");
+ return;
+ }
+ }
+
void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ cap ].func);
capability( argSet[0], argSet[1], &argSet[2] );
}
}
}
+void cliFunc_layerDebug( char *args )
+{
+ // Toggle layer debug mode
+ layerDebugMode = layerDebugMode ? 0 : 1;
+
+ print( NL );
+ info_msg("Layer Debug Mode: ");
+ printInt8( layerDebugMode );
+}
+
void cliFunc_layerList( char* args )
{
print( NL );
info_msg("Pending Key Events: ");
printInt16( (uint16_t)macroTriggerListBufferSize );
print(" : ");
- for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
+ for ( var_uint_t key = 0; key < macroTriggerListBufferSize; key++ )
{
printHex( macroTriggerListBuffer[ key ].scanCode );
print(" ");