]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Macro/PartialMap/macro.c
All basic macros tested and working!
[kiibohd-controller.git] / Macro / PartialMap / macro.c
1 /* Copyright (C) 2014 by Jacob Alexander
2  *
3  * This file is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This file is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 // ----- Includes -----
18
19 // Compiler Includes
20 #include <Lib/MacroLib.h>
21
22 // Project Includes
23 #include <cli.h>
24 #include <led.h>
25 #include <print.h>
26 #include <scan_loop.h>
27
28 // Keymaps
29 #include "usb_hid.h"
30 #include <defaultMap.h>
31 #include "generatedKeymap.h" // TODO Use actual generated version
32
33 // Local Includes
34 #include "macro.h"
35
36
37
38 // ----- Function Declarations -----
39
40 void cliFunc_capList   ( char* args );
41 void cliFunc_capSelect ( char* args );
42 void cliFunc_keyHold   ( char* args );
43 void cliFunc_keyPress  ( char* args );
44 void cliFunc_keyRelease( char* args );
45 void cliFunc_layerList ( char* args );
46 void cliFunc_layerState( char* args );
47 void cliFunc_macroDebug( char* args );
48 void cliFunc_macroList ( char* args );
49 void cliFunc_macroProc ( char* args );
50 void cliFunc_macroShow ( char* args );
51 void cliFunc_macroStep ( char* args );
52
53
54
55 // ----- Enums -----
56
57 // Bit positions are important, passes (correct key) always trump incorrect key votes
58 typedef enum TriggerMacroVote {
59         TriggerMacroVote_Release          = 0x10, // Correct key
60         TriggerMacroVote_PassRelease      = 0x18, // Correct key (both pass and release)
61         TriggerMacroVote_Pass             = 0x8,  // Correct key
62         TriggerMacroVote_DoNothingRelease = 0x4,  // Incorrect key
63         TriggerMacroVote_DoNothing        = 0x2,  // Incorrect key
64         TriggerMacroVote_Fail             = 0x1,  // Incorrect key
65         TriggerMacroVote_Invalid          = 0x0,  // Invalid state
66 } TriggerMacroVote;
67
68 typedef enum TriggerMacroEval {
69         TriggerMacroEval_DoNothing,
70         TriggerMacroEval_DoResult,
71         TriggerMacroEval_DoResultAndRemove,
72         TriggerMacroEval_Remove,
73 } TriggerMacroEval;
74
75 typedef enum ResultMacroEval {
76         ResultMacroEval_DoNothing,
77         ResultMacroEval_Remove,
78 } ResultMacroEval;
79
80
81
82 // ----- Variables -----
83
84 // Macro Module command dictionary
85 const char macroCLIDictName[] = "Macro Module Commands";
86 const CLIDictItem macroCLIDict[] = {
87         { "capList",     "Prints an indexed list of all non USB keycode capabilities.", cliFunc_capList },
88         { "capSelect",   "Triggers the specified capabilities. First two args are state and stateType." NL "\t\t\033[35mK11\033[0m Keyboard Capability 0x0B", cliFunc_capSelect },
89         { "keyHold",     "Send key-hold events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A", cliFunc_keyHold },
90         { "keyPress",    "Send key-press events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A", cliFunc_keyPress },
91         { "keyRelease",  "Send key-release event to macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A", cliFunc_keyRelease },
92         { "layerList",   "List available layers.", cliFunc_layerList },
93         { "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", cliFunc_layerState },
94         { "macroDebug",  "Disables/Enables sending USB keycodes to the Output Module and prints U/K codes.", cliFunc_macroDebug },
95         { "macroList",   "List the defined trigger and result macros.", cliFunc_macroList },
96         { "macroProc",   "Pause/Resume macro processing.", cliFunc_macroProc },
97         { "macroShow",   "Show the macro corresponding to the given index." NL "\t\t\033[35mT16\033[0m Indexed Trigger Macro 0x10, \033[35mR12\033[0m Indexed Result Macro 0x0C", cliFunc_macroShow },
98         { "macroStep",   "Do N macro processing steps. Defaults to 1.", cliFunc_macroStep },
99         { 0, 0, 0 } // Null entry for dictionary end
100 };
101
102
103 // Macro debug flag - If set, clears the USB Buffers after signalling processing completion
104 uint8_t macroDebugMode = 0;
105
106 // Macro pause flag - If set, the macro module pauses processing, unless unset, or the step counter is non-zero
107 uint8_t macroPauseMode = 0;
108
109 // Macro step counter - If non-zero, the step counter counts down every time the macro module does one processing loop
110 unsigned int macroStepCounter = 0;
111
112
113 // Key Trigger List Buffer
114 TriggerGuide macroTriggerListBuffer[ MaxScanCode ];
115 uint8_t macroTriggerListBufferSize = 0;
116
117 // Pending Trigger Macro Index List
118 //  * Any trigger macros that need processing from a previous macro processing loop
119 // TODO, figure out a good way to scale this array size without wasting too much memory, but not rejecting macros
120 //       Possibly could be calculated by the KLL compiler
121 // XXX It may be possible to calculate the worst case using the KLL compiler
122 unsigned int macroTriggerMacroPendingList[ TriggerMacroNum ] = { 0 };
123 unsigned int macroTriggerMacroPendingListSize = 0;
124
125 // Layer Index Stack
126 //  * When modifying layer state and the state is non-0x0, the stack must be adjusted
127 unsigned int macroLayerIndexStack[ LayerNum ] = { 0 };
128 unsigned int macroLayerIndexStackSize = 0;
129
130 // Pending Result Macro Index List
131 //  * Any result macro that needs processing from a previous macro processing loop
132 unsigned int macroResultMacroPendingList[ ResultMacroNum ] = { 0 };
133 unsigned int macroResultMacroPendingListSize = 0;
134
135
136
137 // ----- Capabilities -----
138
139 // Modifies the specified Layer control byte
140 // Argument #1: Layer Index -> unsigned int
141 // Argument #2: Toggle byte -> uint8_t
142 void Macro_layerStateToggle_capability( uint8_t state, uint8_t stateType, uint8_t *args )
143 {
144         // Display capability name
145         if ( stateType == 0xFF && state == 0xFF )
146         {
147                 print("Macro_layerState(layerIndex,toggleByte)");
148                 return;
149         }
150
151         // Get layer index from arguments
152         // Cast pointer to uint8_t to unsigned int then access that memory location
153         unsigned int layer = *(unsigned int*)(&args[0]);
154
155         // Get layer toggle byte
156         uint8_t toggleByte = args[ sizeof(unsigned int) ];
157
158         // Is layer in the LayerIndexStack?
159         uint8_t inLayerIndexStack = 0;
160         unsigned int stackItem = 0;
161         while ( stackItem < macroLayerIndexStackSize )
162         {
163                 // Flag if layer is already in the LayerIndexStack
164                 if ( macroLayerIndexStack[ stackItem ] == layer )
165                 {
166                         inLayerIndexStack = 1;
167                         break;
168                 }
169
170                 // Increment to next item
171                 stackItem++;
172         }
173
174         // Toggle Layer State Byte
175         if ( LayerIndex[ layer ].state & toggleByte )
176         {
177                 // Unset
178                 LayerIndex[ layer ].state &= ~toggleByte;
179         }
180         else
181         {
182                 // Set
183                 LayerIndex[ layer ].state |= toggleByte;
184         }
185
186         // If the layer was not in the LayerIndexStack add it
187         if ( !inLayerIndexStack )
188         {
189                 macroLayerIndexStack[ macroLayerIndexStackSize++ ] = layer;
190         }
191
192         // If the layer is in the LayerIndexStack and the state is 0x00, remove
193         if ( LayerIndex[ layer ].state == 0x00 && inLayerIndexStack )
194         {
195                 // Remove the layer from the LayerIndexStack
196                 // Using the already positioned stackItem variable from the loop above
197                 while ( stackItem < macroLayerIndexStackSize )
198                 {
199                         macroLayerIndexStack[ stackItem ] = macroLayerIndexStack[ stackItem + 1 ];
200                         stackItem++;
201                 }
202
203                 // Reduce LayerIndexStack size
204                 macroLayerIndexStackSize--;
205         }
206 }
207
208
209
210 // ----- Functions -----
211
212 // Looks up the trigger list for the given scan code (from the active layer)
213 // NOTE: Calling function must handle the NULL pointer case
214 unsigned int *Macro_layerLookup( uint8_t scanCode )
215 {
216         // If no trigger macro is defined at the given layer, fallthrough to the next layer
217         for ( unsigned int layerIndex = 0; layerIndex < macroLayerIndexStackSize; layerIndex++ )
218         {
219                 // Lookup Layer
220                 Layer *layer = &LayerIndex[ macroLayerIndexStack[ layerIndex ] ];
221
222                 // Check if latch has been pressed for this layer
223                 // XXX Regardless of whether a key is found, the latch is removed on first lookup
224                 uint8_t latch = layer->state & 0x02;
225                 if ( latch )
226                 {
227                         layer->state &= ~0x02;
228                 }
229
230                 // Only use layer, if state is valid
231                 // XOR each of the state bits
232                 // If only two are enabled, do not use this state
233                 if ( (layer->state & 0x01) ^ (latch>>1) ^ ((layer->state & 0x04)>>2) )
234                 {
235                         // Lookup layer
236                         unsigned int **map = (unsigned int**)layer->triggerMap;
237
238                         // Determine if layer has key defined
239                         if ( map != 0 && *map[ scanCode ] != 0 )
240                                 return map[ scanCode ];
241                 }
242         }
243
244         // Do lookup on default layer
245         unsigned int **map = (unsigned int**)LayerIndex[0].triggerMap;
246
247         // Determine if layer has key defined
248         if ( map == 0 && *map[ scanCode ] == 0 )
249         {
250                 erro_msg("Scan Code has no defined Trigger Macro: ");
251                 printHex( scanCode );
252                 return 0;
253         }
254
255         // Return lookup result
256         return map[ scanCode ];
257 }
258
259
260 // Update the scancode key state
261 // States:
262 //   * 0x00 - Off
263 //   * 0x01 - Pressed
264 //   * 0x02 - Held
265 //   * 0x03 - Released
266 //   * 0x04 - Unpressed (this is currently ignored)
267 inline void Macro_keyState( uint8_t scanCode, uint8_t state )
268 {
269         // Only add to macro trigger list if one of three states
270         switch ( state )
271         {
272         case 0x01: // Pressed
273         case 0x02: // Held
274         case 0x03: // Released
275                 macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
276                 macroTriggerListBuffer[ macroTriggerListBufferSize ].state    = state;
277                 macroTriggerListBuffer[ macroTriggerListBufferSize ].type     = 0x00; // Normal key
278                 macroTriggerListBufferSize++;
279                 break;
280         }
281 }
282
283
284 // Update the scancode analog state
285 // States:
286 //   * 0x00      - Off
287 //   * 0x01      - Released
288 //   * 0x02-0xFF - Analog value (low to high)
289 inline void Macro_analogState( uint8_t scanCode, uint8_t state )
290 {
291         // Only add to macro trigger list if non-off
292         if ( state != 0x00 )
293         {
294                 macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
295                 macroTriggerListBuffer[ macroTriggerListBufferSize ].state    = state;
296                 macroTriggerListBuffer[ macroTriggerListBufferSize ].type     = 0x02; // Analog key
297                 macroTriggerListBufferSize++;
298         }
299 }
300
301
302 // Update led state
303 // States:
304 //   * 0x00 - Off
305 //   * 0x01 - On
306 inline void Macro_ledState( uint8_t ledCode, uint8_t state )
307 {
308         // Only add to macro trigger list if non-off
309         if ( state != 0x00 )
310         {
311                 macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = ledCode;
312                 macroTriggerListBuffer[ macroTriggerListBufferSize ].state    = state;
313                 macroTriggerListBuffer[ macroTriggerListBufferSize ].type     = 0x01; // LED key
314                 macroTriggerListBufferSize++;
315         }
316 }
317
318
319 // Append result macro to pending list, checking for duplicates
320 // Do nothing if duplicate
321 inline void Macro_appendResultMacroToPendingList( TriggerMacro *triggerMacro )
322 {
323         // Lookup result macro index
324         unsigned int resultMacroIndex = triggerMacro->result;
325
326         // Iterate through result macro pending list, making sure this macro hasn't been added yet
327         for ( unsigned int macro = 0; macro < macroResultMacroPendingListSize; macro++ )
328         {
329                 // If duplicate found, do nothing
330                 if ( macroResultMacroPendingList[ macro ] == resultMacroIndex )
331                         return;
332         }
333
334         // No duplicates found, add to pending list
335         macroResultMacroPendingList[ macroResultMacroPendingListSize++ ] = resultMacroIndex;
336
337         // Lookup scanCode of the last key in the last combo
338         unsigned int pos = 0;
339         for ( uint8_t comboLength = triggerMacro->guide[0]; comboLength > 0; )
340         {
341                 pos += TriggerGuideSize * comboLength + 1;
342                 comboLength = triggerMacro->guide[ pos ];
343         }
344
345         uint8_t scanCode = ((TriggerGuide*)&triggerMacro->guide[ pos - TriggerGuideSize ])->scanCode;
346
347         // Lookup scanCode in buffer list for the current state and stateType
348         for ( uint8_t keyIndex = 0; keyIndex < macroTriggerListBufferSize; keyIndex++ )
349         {
350                 if ( macroTriggerListBuffer[ keyIndex ].scanCode == scanCode )
351                 {
352                         ResultMacroList[ resultMacroIndex ].state     = macroTriggerListBuffer[ keyIndex ].state;
353                         ResultMacroList[ resultMacroIndex ].stateType = macroTriggerListBuffer[ keyIndex ].type;
354                 }
355         }
356
357         // Reset the macro position
358         ResultMacroList[ resultMacroIndex ].pos = 0;
359 }
360
361
362 // Determine if long ResultMacro (more than 1 seqence element)
363 inline uint8_t Macro_isLongResultMacro( ResultMacro *macro )
364 {
365         // Check the second sequence combo length
366         // If non-zero return non-zero (long sequence)
367         // 0 otherwise (short sequence)
368         unsigned int position = 1;
369         for ( unsigned int result = 0; result < macro->guide[0]; result++ )
370                 position += ResultGuideSize( (ResultGuide*)&macro->guide[ position ] );
371         return macro->guide[ position ];
372 }
373
374
375 // Determine if long TriggerMacro (more than 1 sequence element)
376 inline uint8_t Macro_isLongTriggerMacro( TriggerMacro *macro )
377 {
378         // Check the second sequence combo length
379         // If non-zero return non-zero (long sequence)
380         // 0 otherwise (short sequence)
381         return macro->guide[ macro->guide[0] * TriggerGuideSize + 1 ];
382 }
383
384
385 // Votes on the given key vs. guide, short macros
386 inline TriggerMacroVote Macro_evalShortTriggerMacroVote( TriggerGuide *key, TriggerGuide *guide )
387 {
388         // Depending on key type
389         switch ( guide->type )
390         {
391         // Normal State Type
392         case 0x00:
393                 // For short TriggerMacros completely ignore incorrect keys
394                 if ( guide->scanCode == key->scanCode )
395                 {
396                         switch ( key->state )
397                         {
398                         // Correct key, pressed, possible passing
399                         case 0x01:
400                                 return TriggerMacroVote_Pass;
401
402                         // Correct key, held, possible passing or release
403                         case 0x02:
404                                 return TriggerMacroVote_PassRelease;
405
406                         // Correct key, released, possible release
407                         case 0x03:
408                                 return TriggerMacroVote_Release;
409                         }
410                 }
411
412                 return TriggerMacroVote_DoNothing;
413
414         // LED State Type
415         case 0x01:
416                 erro_print("LED State Type - Not implemented...");
417                 break;
418
419         // Analog State Type
420         case 0x02:
421                 erro_print("Analog State Type - Not implemented...");
422                 break;
423
424         // Invalid State Type
425         default:
426                 erro_print("Invalid State Type. This is a bug.");
427                 break;
428         }
429
430         // XXX Shouldn't reach here
431         return TriggerMacroVote_Invalid;
432 }
433
434
435 // Votes on the given key vs. guide, long macros
436 // A long macro is defined as a guide with more than 1 combo
437 inline TriggerMacroVote Macro_evalLongTriggerMacroVote( TriggerGuide *key, TriggerGuide *guide )
438 {
439         // Depending on key type
440         switch ( guide->type )
441         {
442         // Normal State Type
443         case 0x00:
444                 // Depending on the state of the buffered key, make voting decision
445                 // Incorrect key
446                 if ( guide->scanCode != key->scanCode )
447                 {
448                         switch ( key->state )
449                         {
450                         // Wrong key, pressed, fail
451                         case 0x01:
452                                 return TriggerMacroVote_Fail;
453
454                         // Wrong key, held, do not pass (no effect)
455                         case 0x02:
456                                 return TriggerMacroVote_DoNothing;
457
458                         // Wrong key released, fail out if pos == 0
459                         case 0x03:
460                                 return TriggerMacroVote_DoNothing | TriggerMacroVote_DoNothingRelease;
461                         }
462                 }
463
464                 // Correct key
465                 else
466                 {
467                         switch ( key->state )
468                         {
469                         // Correct key, pressed, possible passing
470                         case 0x01:
471                                 return TriggerMacroVote_Pass;
472
473                         // Correct key, held, possible passing or release
474                         case 0x02:
475                                 return TriggerMacroVote_PassRelease;
476
477                         // Correct key, released, possible release
478                         case 0x03:
479                                 return TriggerMacroVote_Release;
480                         }
481                 }
482
483                 break;
484
485         // LED State Type
486         case 0x01:
487                 erro_print("LED State Type - Not implemented...");
488                 break;
489
490         // Analog State Type
491         case 0x02:
492                 erro_print("Analog State Type - Not implemented...");
493                 break;
494
495         // Invalid State Type
496         default:
497                 erro_print("Invalid State Type. This is a bug.");
498                 break;
499         }
500
501         // XXX Shouldn't reach here
502         return TriggerMacroVote_Invalid;
503 }
504
505
506 // Evaluate/Update TriggerMacro
507 inline TriggerMacroEval Macro_evalTriggerMacro( unsigned int triggerMacroIndex )
508 {
509         // Lookup TriggerMacro
510         TriggerMacro *macro = &TriggerMacroList[ triggerMacroIndex ];
511
512         // Check if macro has finished and should be incremented sequence elements
513         if ( macro->state == TriggerMacro_Release )
514         {
515                 macro->state = TriggerMacro_Waiting;
516                 macro->pos = macro->pos + macro->guide[ macro->pos ] * TriggerGuideSize + 1;
517         }
518
519         // Current Macro position
520         unsigned int pos = macro->pos;
521
522         // Length of the combo being processed
523         uint8_t comboLength = macro->guide[ pos ] * TriggerGuideSize;
524
525         // If no combo items are left, remove the TriggerMacro from the pending list
526         if ( comboLength == 0 )
527         {
528                 return TriggerMacroEval_Remove;
529         }
530
531         // Check if this is a long Trigger Macro
532         uint8_t longMacro = Macro_isLongTriggerMacro( macro );
533
534         // Iterate through the items in the combo, voting the on the key state
535         // If any of the pressed keys do not match, fail the macro
536         //
537         // The macro is waiting for input when in the TriggerMacro_Waiting state
538         // Once all keys have been pressed/held (only those keys), entered TriggerMacro_Press state (passing)
539         // Transition to the next combo (if it exists) when a single key is released (TriggerMacro_Release state)
540         // On scan after position increment, change to TriggerMacro_Waiting state
541         // TODO Add support for system LED states (NumLock, CapsLock, etc.)
542         // TODO Add support for analog key states
543         // TODO Add support for 0x00 Key state (not pressing a key, not all that useful in general)
544         // TODO Add support for Press/Hold/Release differentiation when evaluating (not sure if useful)
545         TriggerMacroVote overallVote = TriggerMacroVote_Invalid;
546         for ( uint8_t comboItem = pos + 1; comboItem < pos + comboLength + 1; comboItem += TriggerGuideSize )
547         {
548                 // Assign TriggerGuide element (key type, state and scancode)
549                 TriggerGuide *guide = (TriggerGuide*)(&macro->guide[ comboItem ]);
550
551                 TriggerMacroVote vote = TriggerMacroVote_Invalid;
552                 // Iterate through the key buffer, comparing to each key in the combo
553                 for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
554                 {
555                         // Lookup key information
556                         TriggerGuide *keyInfo = &macroTriggerListBuffer[ key ];
557
558                         // If vote is a pass (>= 0x08, no more keys in the combo need to be looked at)
559                         // Also mask all of the non-passing votes
560                         vote |= longMacro
561                                 ? Macro_evalLongTriggerMacroVote( keyInfo, guide )
562                                 : Macro_evalShortTriggerMacroVote( keyInfo, guide );
563                         if ( vote >= TriggerMacroVote_Pass )
564                         {
565                                 vote &= TriggerMacroVote_Release | TriggerMacroVote_PassRelease | TriggerMacroVote_Pass;
566                                 break;
567                         }
568                 }
569
570                 // If no pass vote was found after scanning all of the keys
571                 // Fail the combo, if this is a short macro (long macros already will have a fail vote)
572                 if ( !longMacro && vote < TriggerMacroVote_Pass )
573                         vote |= TriggerMacroVote_Fail;
574
575                 // After voting, append to overall vote
576                 overallVote |= vote;
577         }
578
579         // If no pass vote was found after scanning the entire combo
580         // And this is the first position in the combo, just remove it (nothing important happened)
581         if ( longMacro && overallVote & TriggerMacroVote_DoNothingRelease && pos == 0 )
582                 overallVote |= TriggerMacroVote_Fail;
583
584         // Decide new state of macro after voting
585         // Fail macro, remove from pending list
586         if ( overallVote & TriggerMacroVote_Fail )
587         {
588                 return TriggerMacroEval_Remove;
589         }
590         // Do nothing, incorrect key is being held or released
591         else if ( overallVote & TriggerMacroVote_DoNothing && longMacro )
592         {
593                 // Just doing nothing :)
594         }
595         // If passing and in Waiting state, set macro state to Press
596         else if ( overallVote & TriggerMacroVote_Pass
597              && ( macro->state == TriggerMacro_Waiting || macro->state == TriggerMacro_Press ) )
598         {
599                 macro->state = TriggerMacro_Press;
600
601                 // If in press state, and this is the final combo, send request for ResultMacro
602                 // Check to see if the result macro only has a single element
603                 // If this result macro has more than 1 key, only send once
604                 // TODO Add option to have long macro repeat rate
605                 if ( macro->guide[ pos + comboLength + 1 ] == 0 )
606                 {
607                         // Long result macro (more than 1 combo)
608                         if ( Macro_isLongResultMacro( &ResultMacroList[ macro->result ] ) )
609                         {
610                                 // Only ever trigger result once, on press
611                                 if ( overallVote == TriggerMacroVote_Pass )
612                                 {
613                                         return TriggerMacroEval_DoResultAndRemove;
614                                 }
615                         }
616                         // Short result macro
617                         else
618                         {
619                                 // Only trigger result once, on press, if long trigger (more than 1 combo)
620                                 if ( Macro_isLongTriggerMacro( macro ) )
621                                 {
622                                         return TriggerMacroEval_DoResultAndRemove;
623                                 }
624                                 // Otherwise, trigger result continuously
625                                 else
626                                 {
627                                         return TriggerMacroEval_DoResult;
628                                 }
629                         }
630                 }
631         }
632         // If ready for transition and in Press state, set to Waiting and increment combo position
633         // Position is incremented (and possibly remove the macro from the pending list) on the next iteration
634         else if ( overallVote & TriggerMacroVote_Release && macro->state == TriggerMacro_Press )
635         {
636                 macro->state = TriggerMacro_Release;
637
638                 // If this is the last combo in the sequence, remove from the pending list
639                 if ( macro->guide[ macro->pos + macro->guide[ macro->pos ] * TriggerGuideSize + 1 ] == 0 )
640                         return TriggerMacroEval_Remove;
641         }
642         // Otherwise, just remove the macro on key release
643         // XXX Might cause some issues
644         else if ( overallVote & TriggerMacroVote_Release )
645         {
646                 return TriggerMacroEval_Remove;
647         }
648
649         // If this is a short macro, just remove it
650         // The state can be rebuilt on the next iteration
651         if ( !longMacro )
652                 return TriggerMacroEval_Remove;
653
654         return TriggerMacroEval_DoNothing;
655 }
656
657
658 // Evaluate/Update ResultMacro
659 inline ResultMacroEval Macro_evalResultMacro( unsigned int resultMacroIndex )
660 {
661         // Lookup ResultMacro
662         ResultMacro *macro = &ResultMacroList[ resultMacroIndex ];
663
664         // Current Macro position
665         unsigned int pos = macro->pos;
666
667         // Length of combo being processed
668         uint8_t comboLength = macro->guide[ pos ];
669
670         // Function Counter, used to keep track of the combo items processed
671         unsigned int funcCount = 0;
672
673         // Combo Item Position within the guide
674         unsigned int comboItem = pos + 1;
675
676         // Iterate through the Result Combo
677         while ( funcCount < comboLength )
678         {
679                 // Assign TriggerGuide element (key type, state and scancode)
680                 ResultGuide *guide = (ResultGuide*)(&macro->guide[ comboItem ]);
681
682                 // Do lookup on capability function
683                 void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ guide->index ].func);
684
685                 // Call capability
686                 capability( macro->state, macro->stateType, &guide->args );
687
688                 // Increment counters
689                 funcCount++;
690                 comboItem += ResultGuideSize( (ResultGuide*)(&macro->guide[ comboItem ]) );
691         }
692
693         // Move to next item in the sequence
694         macro->pos = comboItem;
695
696         // If the ResultMacro is finished, remove
697         if ( macro->guide[ comboItem ] == 0 )
698         {
699                 return ResultMacroEval_Remove;
700         }
701
702         // Otherwise leave the macro in the list
703         return ResultMacroEval_DoNothing;
704 }
705
706
707 // Update pending trigger list
708 inline void Macro_updateTriggerMacroPendingList()
709 {
710         // Iterate over the macroTriggerListBuffer to add any new Trigger Macros to the pending list
711         for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
712         {
713                 // TODO LED States
714                 // TODO Analog Switches
715                 // Only add TriggerMacro to pending list if key was pressed (not held, released or off)
716                 if ( macroTriggerListBuffer[ key ].state == 0x00 && macroTriggerListBuffer[ key ].state != 0x01 )
717                         continue;
718
719                 // Lookup Trigger List
720                 unsigned int *triggerList = Macro_layerLookup( macroTriggerListBuffer[ key ].scanCode );
721
722                 // Number of Triggers in list
723                 unsigned int triggerListSize = triggerList[0];
724
725                 // Iterate over triggerList to see if any TriggerMacros need to be added
726                 // First item is the number of items in the TriggerList
727                 for ( unsigned int macro = 1; macro < triggerListSize + 1; macro++ )
728                 {
729                         // Lookup trigger macro index
730                         unsigned int triggerMacroIndex = triggerList[ macro ];
731
732                         // Iterate over macroTriggerMacroPendingList to see if any macro in the scancode's
733                         //  triggerList needs to be added
734                         unsigned int pending = 0;
735                         for ( ; pending < macroTriggerMacroPendingListSize; pending++ )
736                         {
737                                 // Stop scanning if the trigger macro index is found in the pending list
738                                 if ( macroTriggerMacroPendingList[ pending ] == triggerMacroIndex )
739                                         break;
740                         }
741
742                         // If the triggerMacroIndex (macro) was not found in the macroTriggerMacroPendingList
743                         // Add it to the list
744                         if ( pending == macroTriggerMacroPendingListSize )
745                         {
746                                 macroTriggerMacroPendingList[ macroTriggerMacroPendingListSize++ ] = triggerMacroIndex;
747
748                                 // Reset macro position
749                                 TriggerMacroList[ triggerMacroIndex ].pos   = 0;
750                                 TriggerMacroList[ triggerMacroIndex ].state = TriggerMacro_Waiting;
751                         }
752                 }
753         }
754 }
755
756
757 // Macro Procesing Loop
758 // Called once per USB buffer send
759 inline void Macro_process()
760 {
761         // Only do one round of macro processing between Output Module timer sends
762         if ( USBKeys_Sent != 0 )
763                 return;
764
765         // If the pause flag is set, only process if the step counter is non-zero
766         if ( macroPauseMode )
767         {
768                 if ( macroStepCounter == 0 )
769                         return;
770
771                 // Proceed, decrementing the step counter
772                 macroStepCounter--;
773                 dbug_print("Macro Step");
774         }
775
776         // Update pending trigger list, before processing TriggerMacros
777         Macro_updateTriggerMacroPendingList();
778
779         // Tail pointer for macroTriggerMacroPendingList
780         // Macros must be explicitly re-added
781         unsigned int macroTriggerMacroPendingListTail = 0;
782
783         // Iterate through the pending TriggerMacros, processing each of them
784         for ( unsigned int macro = 0; macro < macroTriggerMacroPendingListSize; macro++ )
785         {
786                 switch ( Macro_evalTriggerMacro( macroTriggerMacroPendingList[ macro ] ) )
787                 {
788                 // Trigger Result Macro (purposely falling through)
789                 case TriggerMacroEval_DoResult:
790                         // Append ResultMacro to PendingList
791                         Macro_appendResultMacroToPendingList( &TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ] );
792
793                 default:
794                         macroTriggerMacroPendingList[ macroTriggerMacroPendingListTail++ ] = macroTriggerMacroPendingList[ macro ];
795                         break;
796
797                 // Trigger Result Macro and Remove (purposely falling through)
798                 case TriggerMacroEval_DoResultAndRemove:
799                         // Append ResultMacro to PendingList
800                         Macro_appendResultMacroToPendingList( &TriggerMacroList[ macroTriggerMacroPendingList[ macro ] ] );
801
802                 // Remove Macro from Pending List, nothing to do, removing by default
803                 case TriggerMacroEval_Remove:
804                         break;
805                 }
806         }
807
808         // Update the macroTriggerMacroPendingListSize with the tail pointer
809         macroTriggerMacroPendingListSize = macroTriggerMacroPendingListTail;
810
811
812         // Tail pointer for macroResultMacroPendingList
813         // Macros must be explicitly re-added
814         unsigned int macroResultMacroPendingListTail = 0;
815
816         // Iterate through the pending ResultMacros, processing each of them
817         for ( unsigned int macro = 0; macro < macroResultMacroPendingListSize; macro++ )
818         {
819                 switch ( Macro_evalResultMacro( macroResultMacroPendingList[ macro ] ) )
820                 {
821                 // Re-add macros to pending list
822                 case ResultMacroEval_DoNothing:
823                 default:
824                         macroResultMacroPendingList[ macroResultMacroPendingListTail++ ] = macroResultMacroPendingList[ macro ];
825                         break;
826
827                 // Remove Macro from Pending List, nothing to do, removing by default
828                 case ResultMacroEval_Remove:
829                         break;
830                 }
831         }
832
833         // Update the macroResultMacroPendingListSize with the tail pointer
834         macroResultMacroPendingListSize = macroResultMacroPendingListTail;
835
836         // Signal buffer that we've used it
837         Scan_finishedWithMacro( macroTriggerListBufferSize );
838
839         // Reset TriggerList buffer
840         macroTriggerListBufferSize = 0;
841
842         // If Macro debug mode is set, clear the USB Buffer
843         if ( macroDebugMode )
844         {
845                 USBKeys_Modifiers = 0;
846                 USBKeys_Sent = 0;
847         }
848 }
849
850
851 inline void Macro_setup()
852 {
853         // Register Macro CLI dictionary
854         CLI_registerDictionary( macroCLIDict, macroCLIDictName );
855
856         // Disable Macro debug mode
857         macroDebugMode = 0;
858
859         // Disable Macro pause flag
860         macroPauseMode = 0;
861
862         // Set Macro step counter to zero
863         macroStepCounter = 0;
864
865         // Make sure macro trigger buffer is empty
866         macroTriggerListBufferSize = 0;
867
868         // Initialize TriggerMacro states
869         for ( unsigned int macro = 0; macro < TriggerMacroNum; macro++ )
870         {
871                 TriggerMacroList[ macro ].pos   = 0;
872                 TriggerMacroList[ macro ].state = TriggerMacro_Waiting;
873         }
874
875         // Initialize ResultMacro states
876         for ( unsigned int macro = 0; macro < ResultMacroNum; macro++ )
877         {
878                 ResultMacroList[ macro ].pos       = 0;
879                 ResultMacroList[ macro ].state     = 0;
880                 ResultMacroList[ macro ].stateType = 0;
881         }
882 }
883
884
885 // ----- CLI Command Functions -----
886
887 void cliFunc_capList( char* args )
888 {
889         print( NL );
890         info_msg("Capabilities List");
891         printHex( CapabilitiesNum );
892
893         // Iterate through all of the capabilities and display them
894         for ( unsigned int cap = 0; cap < CapabilitiesNum; cap++ )
895         {
896                 print( NL "\t" );
897                 printHex( cap );
898                 print(" - ");
899
900                 // Display/Lookup Capability Name (utilize debug mode of capability)
901                 void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ cap ].func);
902                 capability( 0xFF, 0xFF, 0 );
903         }
904 }
905
906 void cliFunc_capSelect( char* args )
907 {
908         // Parse code from argument
909         char* curArgs;
910         char* arg1Ptr;
911         char* arg2Ptr = args;
912
913         // Total number of args to scan (must do a lookup if a keyboard capability is selected)
914         unsigned int totalArgs = 2; // Always at least two args
915         unsigned int cap = 0;
916
917         // Arguments used for keyboard capability function
918         unsigned int argSetCount = 0;
919         uint8_t *argSet = (uint8_t*)args;
920
921         // Process all args
922         for ( unsigned int c = 0; argSetCount < totalArgs; c++ )
923         {
924                 curArgs = arg2Ptr;
925                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
926
927                 // Stop processing args if no more are found
928                 // Extra arguments are ignored
929                 if ( *arg1Ptr == '\0' )
930                         break;
931
932                 // For the first argument, choose the capability
933                 if ( c == 0 ) switch ( arg1Ptr[0] )
934                 {
935                 // Keyboard Capability
936                 case 'K':
937                         // Determine capability index
938                         cap = numToInt( &arg1Ptr[1] );
939
940                         // Lookup the number of args
941                         totalArgs += CapabilitiesList[ cap ].argCount;
942                         continue;
943                 }
944
945                 // Because allocating memory isn't doable, and the argument count is arbitrary
946                 // The argument pointer is repurposed as the argument list (much smaller anyways)
947                 argSet[ argSetCount++ ] = (uint8_t)numToInt( arg1Ptr );
948
949                 // Once all the arguments are prepared, call the keyboard capability function
950                 if ( argSetCount == totalArgs )
951                 {
952                         // Indicate that the capability was called
953                         print( NL );
954                         info_msg("K");
955                         printInt8( cap );
956                         print(" - ");
957                         printHex( argSet[0] );
958                         print(" - ");
959                         printHex( argSet[1] );
960                         print(" - ");
961                         printHex( argSet[2] );
962                         print( "..." NL );
963
964                         void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ cap ].func);
965                         capability( argSet[0], argSet[1], &argSet[2] );
966                 }
967         }
968 }
969
970 void cliFunc_keyHold( char* args )
971 {
972         // Parse codes from arguments
973         char* curArgs;
974         char* arg1Ptr;
975         char* arg2Ptr = args;
976
977         // Process all args
978         for ( ;; )
979         {
980                 curArgs = arg2Ptr;
981                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
982
983                 // Stop processing args if no more are found
984                 if ( *arg1Ptr == '\0' )
985                         break;
986
987                 // Ignore non-Scancode numbers
988                 switch ( arg1Ptr[0] )
989                 {
990                 // Scancode
991                 case 'S':
992                         Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x02 ); // Hold scancode
993                         break;
994                 }
995         }
996 }
997
998 void cliFunc_keyPress( char* args )
999 {
1000         // Parse codes from arguments
1001         char* curArgs;
1002         char* arg1Ptr;
1003         char* arg2Ptr = args;
1004
1005         // Process all args
1006         for ( ;; )
1007         {
1008                 curArgs = arg2Ptr;
1009                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
1010
1011                 // Stop processing args if no more are found
1012                 if ( *arg1Ptr == '\0' )
1013                         break;
1014
1015                 // Ignore non-Scancode numbers
1016                 switch ( arg1Ptr[0] )
1017                 {
1018                 // Scancode
1019                 case 'S':
1020                         Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x01 ); // Press scancode
1021                         break;
1022                 }
1023         }
1024 }
1025
1026 void cliFunc_keyRelease( char* args )
1027 {
1028         // Parse codes from arguments
1029         char* curArgs;
1030         char* arg1Ptr;
1031         char* arg2Ptr = args;
1032
1033         // Process all args
1034         for ( ;; )
1035         {
1036                 curArgs = arg2Ptr;
1037                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
1038
1039                 // Stop processing args if no more are found
1040                 if ( *arg1Ptr == '\0' )
1041                         break;
1042
1043                 // Ignore non-Scancode numbers
1044                 switch ( arg1Ptr[0] )
1045                 {
1046                 // Scancode
1047                 case 'S':
1048                         Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x03 ); // Release scancode
1049                         break;
1050                 }
1051         }
1052 }
1053
1054 void cliFunc_layerList( char* args )
1055 {
1056         print( NL );
1057         info_msg("Layer List");
1058
1059         // Iterate through all of the layers and display them
1060         for ( unsigned int layer = 0; layer < LayerNum; layer++ )
1061         {
1062                 print( NL "\t" );
1063                 printHex( layer );
1064                 print(" - ");
1065
1066                 // Display layer name
1067                 dPrint( (char*)LayerIndex[ layer ].name );
1068
1069                 // Default map
1070                 if ( layer == 0 )
1071                         print(" \033[1m(default)\033[0m");
1072
1073                 // Layer State
1074                 print( NL "\t\t Layer State: " );
1075                 printHex( LayerIndex[ layer ].state );
1076
1077                 // Max Index
1078                 print(" Max Index: ");
1079                 printHex( LayerIndex[ layer ].max );
1080         }
1081 }
1082
1083 void cliFunc_layerState( char* args )
1084 {
1085         // Parse codes from arguments
1086         char* curArgs;
1087         char* arg1Ptr;
1088         char* arg2Ptr = args;
1089
1090         uint8_t arg1 = 0;
1091         uint8_t arg2 = 0;
1092
1093         // Process first two args
1094         for ( uint8_t c = 0; c < 2; c++ )
1095         {
1096                 curArgs = arg2Ptr;
1097                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
1098
1099                 // Stop processing args if no more are found
1100                 if ( *arg1Ptr == '\0' )
1101                         break;
1102
1103                 switch ( c )
1104                 {
1105                 // First argument (e.g. L1)
1106                 case 0:
1107                         if ( arg1Ptr[0] != 'L' )
1108                                 return;
1109
1110                         arg1 = (uint8_t)numToInt( &arg1Ptr[1] );
1111                         break;
1112                 // Second argument (e.g. 4)
1113                 case 1:
1114                         arg2 = (uint8_t)numToInt( arg1Ptr );
1115
1116                         // Display operation (to indicate that it worked)
1117                         print( NL );
1118                         info_msg("Setting Layer L");
1119                         printInt8( arg1 );
1120                         print(" to - ");
1121                         printHex( arg2 );
1122
1123                         // Set the layer state
1124                         LayerIndex[ arg1 ].state = arg2;
1125                         break;
1126                 }
1127         }
1128 }
1129
1130 void cliFunc_macroDebug( char* args )
1131 {
1132         // Toggle macro debug mode
1133         macroDebugMode = macroDebugMode ? 0 : 1;
1134
1135         print( NL );
1136         info_msg("Macro Debug Mode: ");
1137         printInt8( macroDebugMode );
1138 }
1139
1140 void cliFunc_macroList( char* args )
1141 {
1142         // Show pending key events
1143         print( NL );
1144         info_msg("Pending Key Events: ");
1145         printInt16( (uint16_t)macroTriggerListBufferSize );
1146         print(" : ");
1147         for ( uint8_t key = 0; key < macroTriggerListBufferSize; key++ )
1148         {
1149                 printHex( macroTriggerListBuffer[ key ].scanCode );
1150                 print(" ");
1151         }
1152
1153         // Show pending trigger macros
1154         print( NL );
1155         info_msg("Pending Trigger Macros: ");
1156         printInt16( (uint16_t)macroTriggerMacroPendingListSize );
1157         print(" : ");
1158         for ( unsigned int macro = 0; macro < macroTriggerMacroPendingListSize; macro++ )
1159         {
1160                 printHex( macroTriggerMacroPendingList[ macro ] );
1161                 print(" ");
1162         }
1163
1164         // Show pending result macros
1165         print( NL );
1166         info_msg("Pending Result Macros: ");
1167         printInt16( (uint16_t)macroResultMacroPendingListSize );
1168         print(" : ");
1169         for ( unsigned int macro = 0; macro < macroResultMacroPendingListSize; macro++ )
1170         {
1171                 printHex( macroResultMacroPendingList[ macro ] );
1172                 print(" ");
1173         }
1174
1175         // Show available trigger macro indices
1176         print( NL );
1177         info_msg("Trigger Macros Range: T0 -> T");
1178         printInt16( (uint16_t)TriggerMacroNum - 1 ); // Hopefully large enough :P (can't assume 32-bit)
1179
1180         // Show available result macro indices
1181         print( NL );
1182         info_msg("Result  Macros Range: R0 -> R");
1183         printInt16( (uint16_t)ResultMacroNum - 1 ); // Hopefully large enough :P (can't assume 32-bit)
1184
1185         // Show Trigger to Result Macro Links
1186         print( NL );
1187         info_msg("Trigger : Result Macro Pairs");
1188         for ( unsigned int macro = 0; macro < TriggerMacroNum; macro++ )
1189         {
1190                 print( NL );
1191                 print("\tT");
1192                 printInt16( (uint16_t)macro ); // Hopefully large enough :P (can't assume 32-bit)
1193                 print(" : R");
1194                 printInt16( (uint16_t)TriggerMacroList[ macro ].result ); // Hopefully large enough :P (can't assume 32-bit)
1195         }
1196 }
1197
1198 void cliFunc_macroProc( char* args )
1199 {
1200         // Toggle macro pause mode
1201         macroPauseMode = macroPauseMode ? 0 : 1;
1202
1203         print( NL );
1204         info_msg("Macro Processing Mode: ");
1205         printInt8( macroPauseMode );
1206 }
1207
1208 void macroDebugShowTrigger( unsigned int index )
1209 {
1210         // Only proceed if the macro exists
1211         if ( index >= TriggerMacroNum )
1212                 return;
1213
1214         // Trigger Macro Show
1215         TriggerMacro *macro = &TriggerMacroList[ index ];
1216
1217         print( NL );
1218         info_msg("Trigger Macro Index: ");
1219         printInt16( (uint16_t)index ); // Hopefully large enough :P (can't assume 32-bit)
1220         print( NL );
1221
1222         // Read the comboLength for combo in the sequence (sequence of combos)
1223         unsigned int pos = 0;
1224         uint8_t comboLength = macro->guide[ pos ];
1225
1226         // Iterate through and interpret the guide
1227         while ( comboLength != 0 )
1228         {
1229                 // Initial position of the combo
1230                 unsigned int comboPos = ++pos;
1231
1232                 // Iterate through the combo
1233                 while ( pos < comboLength * TriggerGuideSize + comboPos )
1234                 {
1235                         // Assign TriggerGuide element (key type, state and scancode)
1236                         TriggerGuide *guide = (TriggerGuide*)(&macro->guide[ pos ]);
1237
1238                         // Display guide information about trigger key
1239                         printHex( guide->scanCode );
1240                         print("|");
1241                         printHex( guide->type );
1242                         print("|");
1243                         printHex( guide->state );
1244
1245                         // Increment position
1246                         pos += TriggerGuideSize;
1247
1248                         // Only show combo separator if there are combos left in the sequence element
1249                         if ( pos < comboLength * TriggerGuideSize + comboPos )
1250                                 print("+");
1251                 }
1252
1253                 // Read the next comboLength
1254                 comboLength = macro->guide[ pos ];
1255
1256                 // Only show sequence separator if there is another combo to process
1257                 if ( comboLength != 0 )
1258                         print(";");
1259         }
1260
1261         // Display current position
1262         print( NL "Position: " );
1263         printInt16( (uint16_t)macro->pos ); // Hopefully large enough :P (can't assume 32-bit)
1264
1265         // Display result macro index
1266         print( NL "Result Macro Index: " );
1267         printInt16( (uint16_t)macro->result ); // Hopefully large enough :P (can't assume 32-bit)
1268
1269         // Display trigger macro state
1270         print( NL "Trigger Macro State: " );
1271         switch ( macro->state )
1272         {
1273         case TriggerMacro_Press:   print("Press");   break;
1274         case TriggerMacro_Release: print("Release"); break;
1275         case TriggerMacro_Waiting: print("Waiting"); break;
1276         }
1277 }
1278
1279 void macroDebugShowResult( unsigned int index )
1280 {
1281         // Only proceed if the macro exists
1282         if ( index >= ResultMacroNum )
1283                 return;
1284
1285         // Trigger Macro Show
1286         ResultMacro *macro = &ResultMacroList[ index ];
1287
1288         print( NL );
1289         info_msg("Result Macro Index: ");
1290         printInt16( (uint16_t)index ); // Hopefully large enough :P (can't assume 32-bit)
1291         print( NL );
1292
1293         // Read the comboLength for combo in the sequence (sequence of combos)
1294         unsigned int pos = 0;
1295         uint8_t comboLength = macro->guide[ pos++ ];
1296
1297         // Iterate through and interpret the guide
1298         while ( comboLength != 0 )
1299         {
1300                 // Function Counter, used to keep track of the combos processed
1301                 unsigned int funcCount = 0;
1302
1303                 // Iterate through the combo
1304                 while ( funcCount < comboLength )
1305                 {
1306                         // Assign TriggerGuide element (key type, state and scancode)
1307                         ResultGuide *guide = (ResultGuide*)(&macro->guide[ pos ]);
1308
1309                         // Display Function Index
1310                         printHex( guide->index );
1311                         print("|");
1312
1313                         // Display Function Ptr Address
1314                         printHex( (unsigned int)CapabilitiesList[ guide->index ].func );
1315                         print("|");
1316
1317                         // Display/Lookup Capability Name (utilize debug mode of capability)
1318                         void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ guide->index ].func);
1319                         capability( 0xFF, 0xFF, 0 );
1320
1321                         // Display Argument(s)
1322                         print("(");
1323                         for ( unsigned int arg = 0; arg < CapabilitiesList[ guide->index ].argCount; arg++ )
1324                         {
1325                                 // Arguments are only 8 bit values
1326                                 printHex( (&guide->args)[ arg ] );
1327
1328                                 // Only show arg separator if there are args left
1329                                 if ( arg + 1 < CapabilitiesList[ guide->index ].argCount )
1330                                         print(",");
1331                         }
1332                         print(")");
1333
1334                         // Increment position
1335                         pos += ResultGuideSize( guide );
1336
1337                         // Increment function count
1338                         funcCount++;
1339
1340                         // Only show combo separator if there are combos left in the sequence element
1341                         if ( funcCount < comboLength )
1342                                 print("+");
1343                 }
1344
1345                 // Read the next comboLength
1346                 comboLength = macro->guide[ pos++ ];
1347
1348                 // Only show sequence separator if there is another combo to process
1349                 if ( comboLength != 0 )
1350                         print(";");
1351         }
1352
1353         // Display current position
1354         print( NL "Position: " );
1355         printInt16( (uint16_t)macro->pos ); // Hopefully large enough :P (can't assume 32-bit)
1356
1357         // Display final trigger state/type
1358         print( NL "Final Trigger State (State/Type): " );
1359         printHex( macro->state );
1360         print("/");
1361         printHex( macro->stateType );
1362 }
1363
1364 void cliFunc_macroShow( char* args )
1365 {
1366         // Parse codes from arguments
1367         char* curArgs;
1368         char* arg1Ptr;
1369         char* arg2Ptr = args;
1370
1371         // Process all args
1372         for ( ;; )
1373         {
1374                 curArgs = arg2Ptr;
1375                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
1376
1377                 // Stop processing args if no more are found
1378                 if ( *arg1Ptr == '\0' )
1379                         break;
1380
1381                 // Ignore invalid codes
1382                 switch ( arg1Ptr[0] )
1383                 {
1384                 // Indexed Trigger Macro
1385                 case 'T':
1386                         macroDebugShowTrigger( numToInt( &arg1Ptr[1] ) );
1387                         break;
1388                 // Indexed Result Macro
1389                 case 'R':
1390                         macroDebugShowResult( numToInt( &arg1Ptr[1] ) );
1391                         break;
1392                 }
1393         }
1394 }
1395
1396 void cliFunc_macroStep( char* args )
1397 {
1398         // Parse number from argument
1399         //  NOTE: Only first argument is used
1400         char* arg1Ptr;
1401         char* arg2Ptr;
1402         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1403
1404         // Default to 1, if no argument given
1405         unsigned int count = (unsigned int)numToInt( arg1Ptr );
1406
1407         if ( count == 0 )
1408                 count = 1;
1409
1410         // Set the macro step counter, negative int's are cast to uint
1411         macroStepCounter = count;
1412 }
1413