aboutsummaryrefslogtreecommitdiffstats
path: root/common/action_macro.h
blob: 621826308858c93b589013d25e4330a84683046d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
Copyright 2013 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTION_MACRO_H
#define ACTION_MACRO_H
#include <stdint.h>
#include <avr/pgmspace.h>


#define MACRO_NONE  0
#define MACRO(...) ({ static const macro_t __m[] PROGMEM = { __VA_ARGS__ }; &__m[0]; })


typedef uint8_t macro_t;


#ifndef NO_ACTION_MACRO
void action_macro_play(const macro_t *macro_p);
#else
#define action_macro_play(macro)
#endif



/* Macro commands
 *   code(0x04-73)                      // key down(1byte)
 *   code(0x04-73) | 0x80               // key up(1byte)
 *   { KEY_DOWN, code(0x04-0xff) }      // key down(2bytes)
 *   { KEY_UP,   code(0x04-0xff) }      // key up(2bytes)
 *   WAIT                               // wait milli-seconds
 *   INTERVAL                           // set interval between macro commands
 *   END                                // stop macro execution
 *
 * Ideas(Not implemented):
 *   modifiers
 *   system usage
 *   consumer usage
 *   unicode usage
 *   function call
 *   conditionals
 *   loop
 */
enum macro_command_id{
    /* 0x00 - 0x03 */
    END                 = 0x00,
    KEY_DOWN,
    KEY_UP,

    /* 0x04 - 0x73 (reserved for keycode down) */

    /* 0x74 - 0x83 */
    WAIT                = 0x74,
    INTERVAL,

    /* 0x84 - 0xf3 (reserved for keycode up) */

    /* 0xf4 - 0xff */
};


/* TODO: keycode:0x04-0x73 can be handled by 1byte command  else 2bytes are needed
 * if keycode between 0x04 and 0x73
 *      keycode / (keycode|0x80)
 * else
 *      {KEY_DOWN, keycode} / {KEY_UP, keycode}
*/
#define DOWN(key)       KEY_DOWN, (key)
#define UP(key)         KEY_UP, (key)
#define TYPE(key)       DOWN(key), UP(key)
#define WAIT(ms)        WAIT, (ms)
#define INTERVAL(ms)    INTERVAL, (ms)

/* key down */
#define D(key)          DOWN(KC_##key)
/* key up */
#define U(key)          UP(KC_##key)
/* key type */
#define T(key)          TYPE(KC_##key)
/* wait */
#define W(ms)           WAIT(ms)
/* interval */
#define I(ms)           INTERVAL(ms)

/* for backward comaptibility */
#define MD(key)         DOWN(KC_##key)
#define MU(key)         UP(KC_##key)


#endif /* ACTION_MACRO_H */
procedure for duplicating strings char * Abc_UtilStrsav( char * s ) { return s ? strcpy(malloc(strlen(s)+1), s) : NULL; } /**Function************************************************************* Synopsis [This procedures executes one call to system().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void * Abc_RunThread( void * Command ) { // perform the call if ( system( (char *)Command ) ) { assert(pthread_mutex_lock(&mutex) == 0); fprintf( stderr, "The following command has returned non-zero exit status:\n" ); fprintf( stderr, "\"%s\"\n", (char *)Command ); fprintf( stderr, "Sorry for the inconvenience.\n" ); fflush( stdout ); assert(pthread_mutex_unlock(&mutex) == 0); } // decrement the number of threads runining assert(pthread_mutex_lock(&mutex) == 0); nThreadsRunning--; assert(pthread_mutex_unlock(&mutex) == 0); // quit this thread //printf("...Finishing %s\n", (char *)Command); free( Command ); pthread_exit( NULL ); assert(0); return NULL; } /**Function************************************************************* Synopsis [Takes file with commands to be executed and the number of CPUs.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int main( int argc, char * argv[] ) { FILE * pFile, * pOutput = stdout; pthread_t ThreadIds[MAX_COMM_NUM]; char * pBufferCopy, Buffer[MAX_COMM_NUM]; int i, nCPUs = 0, nLines = 0, Counter; clock_t clk = clock(); // check command line arguments if ( argc != 3 ) { fprintf( stderr, "Wrong number of command line arguments.\n" ); goto usage; } // get the number of CPUs nCPUs = atoi( argv[1] ); if ( nCPUs <= 0 ) { fprintf( pOutput, "Cannot read an integer represting the number of CPUs.\n" ); goto usage; } // open the file and make sure it is available pFile = fopen( argv[2], "r" ); if ( pFile == NULL ) { fprintf( pOutput, "Input file \"%s\" cannot be opened.\n", argv[2] ); goto usage; } // read commands and execute at most <num> of them at a time // assert(mutex == PTHREAD_MUTEX_INITIALIZER); while ( fgets( Buffer, MAX_COMM_NUM, pFile ) != NULL ) { // get the command from the file if ( Buffer[0] == '\n' || Buffer[0] == '\r' || Buffer[0] == '\t' || Buffer[0] == ' ' || Buffer[0] == '#') { continue; } if ( Buffer[strlen(Buffer)-1] == '\n' ) Buffer[strlen(Buffer)-1] = 0; if ( Buffer[strlen(Buffer)-1] == '\r' ) Buffer[strlen(Buffer)-1] = 0; // wait till there is an empty thread while ( 1 ) { assert(pthread_mutex_lock(&mutex) == 0); Counter = nThreadsRunning; assert(pthread_mutex_unlock(&mutex) == 0); if ( Counter < nCPUs - 1 ) break; // Sleep( 100 ); } // increament the number of threads running assert(pthread_mutex_lock(&mutex) == 0); nThreadsRunning++; printf( "Calling: %s\n", (char *)Buffer ); fflush( stdout ); assert(pthread_mutex_unlock(&mutex) == 0); // create thread to execute this command pBufferCopy = Abc_UtilStrsav( Buffer ); assert(pthread_create( &ThreadIds[nLines], NULL, Abc_RunThread, (void *)pBufferCopy ) == 0); if ( ++nLines == MAX_COMM_NUM ) { fprintf( pOutput, "Cannot execute more than %d commands from file \"%s\".\n", nLines, argv[2] ); break; } } // wait for all the threads to finish while ( 1 ) { assert(pthread_mutex_lock(&mutex) == 0); Counter = nThreadsRunning; assert(pthread_mutex_unlock(&mutex) == 0); if ( Counter == 0 ) break; } // cleanup assert(pthread_mutex_destroy(&mutex) == 0); // assert(mutex == NULL); fclose( pFile ); printf( "Finished processing commands in file \"%s\". ", argv[2] ); ABC_PRT( "Total time", clock() - clk ); return 0; usage: // skip the path name till the binary name for ( i = strlen(argv[0]) - 1; i > 0; i-- ) if ( argv[0][i-1] == '\\' || argv[0][i-1] == '/' ) break; // print usage message fprintf( pOutput, "usage: %s <num> <file>\n", argv[0]+i ); fprintf( pOutput, " executes command listed in <file> in parallel on <num> CPUs\n" ); fprintf( pOutput, "\n" ); return 1; }