diff options
| -rw-r--r-- | backends/maweb.c | 189 | ||||
| -rw-r--r-- | backends/maweb.h | 18 | ||||
| -rw-r--r-- | backends/maweb.md | 76 | ||||
| -rw-r--r-- | backends/winmidi.c | 3 | 
4 files changed, 181 insertions, 105 deletions
diff --git a/backends/maweb.c b/backends/maweb.c index c88ca8c..be356d0 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -19,72 +19,57 @@ static uint64_t update_interval = 50;  static uint64_t last_update = 0;  static uint64_t updates_inflight = 0; -static char* cmdline_keys[] = { -	"SET", -	"PREV", -	"NEXT", -	"CLEAR", -	"FIXTURE_CHANNEL", -	"FIXTURE_GROUP_PRESET", -	"EXEC_CUE", -	"STORE_UPDATE", -	"OOPS", -	"ESC", -	"0", -	"1", -	"2", -	"3", -	"4", -	"5", -	"6", -	"7", -	"8", -	"9", -	"PUNKT", -	"PLUS", -	"MINUS", -	"THRU", -	"IF", -	"AT", -	"FULL", -	"HIGH", -	"ENTER", -	"OFF", -	"ON", -	"ASSIGN", -	"LABEL", -	"COPY", -	"TIME", -	"PAGE", -	"MACRO", -	"DELETE", -	"GOTO", -	"GO_PLUS", -	"GO_MINUS", -	"PAUSE", -	"SELECT", -	"FIXTURE", -	"SEQU", -	"CUE", -	"PRESET", -	"EDIT", -	"UPDATE", -	"EXEC", -	"STORE", -	"GROUP", -	"PROG_ONLY", -	"SPECIAL_DIALOGUE", -	"SOLO", -	"ODD", -	"EVEN", -	"WINGS", -	"RESET", -	"MA", -	"layerMode", -	"featureSort", -	"fixtureSort", -	"channelSort", -	"hideName" +static maweb_command_key cmdline_keys[] = { +	{"PREV", 109, 0, 1}, {"SET", 108, 1, 0, 1}, {"NEXT", 110, 0, 1}, +	{"TIME", 58, 1, 1}, {"EDIT", 55, 1, 1}, {"UPDATE", 57, 1, 1}, +	{"OOPS", 53, 1, 1}, {"ESC", 54, 1, 1}, {"CLEAR", 105, 1, 1}, +	{"0", 86, 1, 1}, {"1", 87, 1, 1}, {"2", 88, 1, 1}, +	{"3", 89, 1, 1}, {"4", 90, 1, 1}, {"5", 91, 1, 1}, +	{"6", 92, 1, 1}, {"7", 93, 1, 1}, {"8", 94, 1, 1}, +	{"9", 95, 1, 1}, {"PUNKT", 98, 1, 1}, {"ENTER", 106, 1, 1}, +	{"PLUS", 96, 1, 1}, {"MINUS", 97, 1, 1}, {"THRU", 102, 1, 1}, +	{"IF", 103, 1, 1}, {"AT", 104, 1, 1}, {"FULL", 99, 1, 1}, +	{"MA", 68, 0, 1}, {"HIGH", 100, 1, 1, 1}, {"SOLO", 101, 1, 1, 1}, +	{"SELECT", 42, 1, 1}, {"OFF", 43, 1, 1}, {"ON", 46, 1, 1}, +	{"ASSIGN", 63, 1, 1}, {"LABEL", 0, 1, 1}, +	{"COPY", 73, 1, 1}, {"DELETE", 69, 1, 1}, {"STORE", 59, 1, 1}, +	{"GOTO", 56, 1, 1}, {"PAGE", 70, 1, 1}, {"MACRO", 71, 1, 1}, +	{"PRESET", 72, 1, 1}, {"SEQU", 74, 1, 1}, {"CUE", 75, 1, 1}, +	{"EXEC", 76, 1, 1}, {"FIXTURE", 83, 1, 1}, {"GROUP", 84, 1, 1}, +	{"GO_MINUS", 10, 1, 1}, {"PAUSE", 9, 1, 1}, {"GO_PLUS", 11, 1, 1}, + +	{"FIXTURE_CHANNEL", 0, 1, 1}, {"FIXTURE_GROUP_PRESET", 0, 1, 1}, +	{"EXEC_CUE", 0, 1, 1}, {"STORE_UPDATE", 0, 1, 1}, {"PROG_ONLY", 0, 1, 1, 1}, +	{"SPECIAL_DIALOGUE", 0, 1, 1}, +	{"ODD", 0, 1, 1}, {"EVEN", 0, 1, 1}, +	{"WINGS", 0, 1, 1}, {"RESET", 0, 1, 1}, +	//gma2 internal only +	{"CHPGPLUS", 3}, {"CHPGMINUS", 4}, +	{"FDPGPLUS", 5}, {"FDPGMINUS", 6}, +	{"BTPGPLUS", 7}, {"BTPGMINUS", 8}, +	{"X1", 12}, {"X2", 13}, {"X3", 14}, +	{"X4", 15}, {"X5", 16}, {"X6", 17}, +	{"X7", 18}, {"X8", 19}, {"X9", 20}, +	{"X10", 21}, {"X11", 22}, {"X12", 23}, +	{"X13", 24}, {"X14", 25}, {"X15", 26}, +	{"X16", 27}, {"X17", 28}, {"X18", 29}, +	{"X19", 30}, {"X20", 31}, +	{"V1", 120}, {"V2", 121}, {"V3", 122}, +	{"V4", 123}, {"V5", 124}, {"V6", 125}, +	{"V7", 126}, {"V8", 127}, {"V9", 128}, +	{"V10", 129}, +	{"NIPPLE", 40}, +	{"TOOLS", 119}, {"SETUP", 117}, {"BACKUP", 117}, +	{"BLIND", 60}, {"FREEZE", 61}, {"PREVIEW", 62}, +	{"FIX", 41}, {"TEMP", 44}, {"TOP", 45}, +	{"VIEW", 66}, {"EFFECT", 67}, {"CHANNEL", 82}, +	{"MOVE", 85}, {"BLACKOUT", 65}, +	{"PLEASE", 106}, +	{"LIST", 32}, {"USER1", 33}, {"USER2", 34}, +	{"ALIGN", 64}, {"HELP", 116}, +	{"UP", 107}, {"DOWN", 111}, +	{"FASTREVERSE", 47}, {"LEARN", 48}, {"FASTFORWARD", 49}, +	{"GO_MINUS_SMALL", 50}, {"PAUSE_SMALL", 51}, {"GO_PLUS_SMALL", 52}  };  int init(){ @@ -199,6 +184,22 @@ static int maweb_configure_instance(instance* inst, char* option, char* value){  		return 1;  		#endif  	} +	else if(!strcmp(option, "cmdline")){ +		if(!strcmp(value, "console")){ +			data->cmdline = cmd_console; +		} +		else if(!strcmp(value, "remote")){ +			data->cmdline = cmd_remote; +		} +		else if(!strcmp(value, "downgrade")){ +			data->cmdline = cmd_downgrade; +		} +		else{ +			fprintf(stderr, "Unknown maweb commandline mode %s for instance %s\n", value, inst->name); +			return 1; +		} +		return 0; +	}  	fprintf(stderr, "Unknown configuration parameter %s for maweb instance %s\n", option, inst->name);  	return 1; @@ -268,10 +269,15 @@ static channel* maweb_channel(instance* inst, char* spec){  		chan.index = strtoul(next_token, NULL, 10);  	}  	else{ -		for(n = 0; n < sizeof(cmdline_keys) / sizeof(char*); n++){ -			//FIXME this is broken for layerMode -			if(!strcmp(spec, cmdline_keys[n]) || (*spec == 'l' && !strcmp(spec + 1, cmdline_keys[n]))){ -				chan.type = (*spec == 'l') ? cmdline_local : cmdline; +		for(n = 0; n < sizeof(cmdline_keys) / sizeof(maweb_command_key); n++){ +			if(!strcmp(spec, cmdline_keys[n].name)){ +				if((data->cmdline == cmd_remote && !cmdline_keys[n].press && !cmdline_keys[n].release) +							|| (data->cmdline == cmd_console && !cmdline_keys[n].lua)){ +					fprintf(stderr, "maweb cmdline key %s does not work with the current commandline mode for instance %s\n", spec, inst->name); +					return NULL; +				} + +				chan.type = cmdline;  				chan.index = n + 1;  				chan.page = 1;  				break; @@ -599,6 +605,8 @@ static int maweb_handle_message(instance* inst, char* payload, size_t payload_le  		field = json_obj_str(payload, "appType", NULL);  		if(!strncmp(field, "dot2", 4)){  			data->peer_type = peer_dot2; +			//the dot2 can't handle lua commands +			data->cmdline = cmd_remote;  		}  		else if(!strncmp(field, "gma2", 4)){  			data->peer_type = peer_ma2; @@ -860,14 +868,41 @@ static int maweb_set(instance* inst, size_t num, channel** c, channel_value* v){  						data->session);  				break;  			case cmdline: -				snprintf(xmit_buffer, sizeof(xmit_buffer), -						"{\"keyname\":\"%s\"," -						//"\"autoSubmit\":false," -						"\"value\":%d" -						"}", cmdline_keys[chan->index], -						(v[n].normalised > 0.9) ? 1 : 0); +				if(cmdline_keys[chan->index].lua +						&& (data->cmdline == cmd_console || data->cmdline == cmd_downgrade) +						&& data->peer_type != peer_dot2){ +					//push canbus events +					snprintf(xmit_buffer, sizeof(xmit_buffer), +							"{\"command\":\"LUA 'gma.canbus.hardkey(%d, %s, false)'\"," +							"\"requestType\":\"command\"," +							"\"session\":%" PRIu64 +							"}", cmdline_keys[chan->index].lua, +							(v[n].normalised > 0.9) ? "true" : "false", +							data->session); +				} +				else if((cmdline_keys[chan->index].press || cmdline_keys[chan->index].release) +						&& (data->cmdline != cmd_console)){ +					//send press/release events if required +					if((cmdline_keys[chan->index].press && v[n].normalised > 0.9) +							|| (cmdline_keys[chan->index].release && v[n].normalised < 0.9)){ +						snprintf(xmit_buffer, sizeof(xmit_buffer), +								"{\"keyname\":\"%s\"," +								"\"autoSubmit\":%s," +								"\"value\":%d" +								"}", cmdline_keys[chan->index].name, +								cmdline_keys[chan->index].auto_submit ? "true" : "null", +								(v[n].normalised > 0.9) ? 1 : 0); +					} +					else{ +						continue; +					} +				} +				else{ +					fprintf(stderr, "maweb commandline key %s not executed on %s due to mode mismatch\n", +							cmdline_keys[chan->index].name, inst->name); +					continue; +				}  				break; -			//TODO cmdline_local  			default:  				fprintf(stderr, "maweb control not yet implemented\n");  				return 1; diff --git a/backends/maweb.h b/backends/maweb.h index 3738367..b9de68f 100644 --- a/backends/maweb.h +++ b/backends/maweb.h @@ -25,8 +25,7 @@ typedef enum /*_maweb_channel_type*/ {  	exec_button = 2, //gma: 0 dot: 0  	exec_lower = 3, //gma: 1 dot: 1  	exec_upper = 4, //gma: 2 dot: 0 -	cmdline, -	cmdline_local +	cmdline  } maweb_channel_type;  typedef enum /*_maweb_peer_type*/ { @@ -43,6 +42,12 @@ typedef enum /*_ws_conn_state*/ {  	ws_closed  } maweb_state; +typedef enum /*_maweb_cmdline_mode*/ { +	cmd_remote = 0, +	cmd_console, +	cmd_downgrade +} maweb_cmdline_mode; +  typedef enum /*_ws_frame_op*/ {  	ws_text = 1,  	ws_binary = 2, @@ -50,6 +55,14 @@ typedef enum /*_ws_frame_op*/ {  	ws_pong = 10  } maweb_operation; +typedef struct { +	char* name; +	unsigned lua; +	uint8_t press; +	uint8_t release; +	uint8_t auto_submit; +} maweb_command_key; +  typedef struct /*_maweb_channel*/ {  	maweb_channel_type type;  	uint16_t page; @@ -73,6 +86,7 @@ typedef struct /*_maweb_instance_data*/ {  	size_t channels;  	maweb_channel_data* channel; +	maweb_cmdline_mode cmdline;  	int fd;  	maweb_state state; diff --git a/backends/maweb.md b/backends/maweb.md index 93cd776..a18cde4 100644 --- a/backends/maweb.md +++ b/backends/maweb.md @@ -26,6 +26,14 @@ Web Remote. Set a web remote password using the option below the activation sett  | `host`	| `10.23.42.21 80`	| none			| Host address (and optional port) of the MA Web Remote		|  | `user`	| `midimonster`		| none			| User for the remote session (GrandMA2)			|  | `password`	| `midimonster`		| `midimonster`		| Password for the remote session				| +| `cmdline`	| `console`		| `remote`		| Commandline key handling mode (see below)			| + +The per-instance command line mode may be one of `remote`, `console` or `downgrade`. The first option handles +command keys with a "virtual" commandline belonging to the Web Remote connection. Any commands entered are +not visible on the main console. The `console` mode is only available with GrandMA2 remotes and injects the +key events into the main console's command line. When connected to a dot2 console, the use of commandline keys +will not be possible. With the `downgrade` mode, keys are handled on the console if possible, falling back to +remote handling if not.  #### Channel specification @@ -33,7 +41,7 @@ Currently, three types of MA controls can be assigned, with each having some sub  * Fader executor  * Button executor -* Command line buttons +* Command keys  ##### Executors @@ -70,33 +78,52 @@ mw1.page2.button103 > mw1.page3.fader101  mw1.page2.button803 > mw1.page3.button516  ``` -##### Command line buttons +##### Command keys -Command line buttons will be pressed when the incoming event value is greater than `0.9` and released when it is less than that. +Command keys will be pressed when the incoming event value is greater than `0.9` and released when it is less than that.  They can be mapped using the syntax  ``` -mw1.<button-name> +mw1.<key-name>  ``` -The following button names are recognized by the backend: - -| Supported	| Command	| Line		| Keys		|			|				|		| -|---------------|---------------|---------------|---------------|-----------------------|-------------------------------|---------------| -| `SET`		| `PREV`	| `NEXT`	| `CLEAR`	| `FIXTURE_CHANNEL`	| `FIXTURE_GROUP_PRESET`	| `EXEC_CUE`	| -| `STORE_UPDATE`| `OOPS`	| `ESC`		| `OFF`		| `ON`			| `MA`				| `STORE`	| -| `0`		| `1`		| `2`		| `3`		| `4`			| `5`				| `6`		| -| `7`		| `8`		| `9`		| `PUNKT`	| `PLUS`		| `MINUS`			| `THRU`	| -| `IF`		| `AT`		| `FULL`	| `HIGH`	| `ENTER`		| `ASSIGN`			| `LABEL`	| -| `COPY`	| `TIME`	| `PAGE`	| `MACRO`	| `DELETE`		| `GOTO`			| `GO_PLUS`	| -| `GO_MINUS`	| `PAUSE`	| `SELECT`	| `FIXTURE`	| `SEQU`		| `CUE`				| `PRESET`	| -| `EDIT`	| `UPDATE`	| `EXEC`	| `GROUP`	| `PROG_ONLY`		| `SPECIAL_DIALOGUE` 		| `SOLO`	| -| `ODD`		| `EVEN`	| `WINGS`	| `RESET` 	| `layerMode`		| `featureSort`			| `fixtureSort`	| -| `channelSort`	| `hideName`	|		|		|			|				|		| - -Note that each Web Remote connection has it's own command line, as such commands entered using this backend will not affect -the command line on the main console. To do that, you will need to use another backend to feed input to the MA, such as -the ArtNet or MIDI backends. +The following keys are mappable in all commandline modes and work on all consoles + +| Supported	| Command	| Line		| Keys		|		|		| +|---------------|---------------|---------------|---------------|---------------|---------------| +| `PREV`	| `SET`		| `NEXT`	| `TIME`	| `EDIT`	| `UPDATE`	| +| `OOPS`	| `ESC`		| `CLEAR`	| `0`		| `1`		| `2`		| +| `3`		| `4`		| `5`		| `6`		| `7`		| `8`		| +| `9`		| `PUNKT`	| `ENTER`	| `PLUS`	| `MINUS`	| `THRU`	| +| `IF`		| `AT`		| `FULL`	| `MA`		| `HIGH`	| `SOLO`	| +| `SELECT`	| `OFF`		| `ON`		| `ASSIGN`	| `COPY`	| `DELETE`	| +| `STORE`	| `GOTO`	| `PAGE`	| `MACRO`	| `PRESET`	| `SEQU`	| +| `CUE`		| `EXEC`	| `FIXTURE`	| `GROUP`	| `GO_MINUS`	| `PAUSE`	| +| `GO_PLUS`	|		|		|		|		|		| + +The following keys only work in the `remote` or `downgrade` commandline mode, but on all consoles + +| Web		| Remote		| specific			|		|			| +|---------------|-----------------------|-------------------------------|---------------|-----------------------| +| `LABEL`	|`FIXTURE_CHANNEL`	| `FIXTURE_GROUP_PRESET`	| `EXEC_CUE`	| `STORE_UPDATE`	| +| `PROG_ONLY`	| `SPECIAL_DIALOGUE`	| `ODD`				| `EVEN`	| `WINGS`		| +| `RESET`	|			|				|		|			| + +The following keys only work in the `console` or `downgrade` command line modes on a GrandMA2 + +| GrandMA2	| console	| only		|		|		|		| +|---------------|---------------|---------------|---------------|---------------|---------------| +| `CHPGPLUS`	| `CHPGMINUS`	| `FDPGPLUS`	| `FDPGMINUS`	| `BTPGPLUS`	| `BTPGMINUS`	| +| `X1`		| `X2`		| `X3`		| `X4`		| `X5`		| `X6`		| +| `X7`		| `X8`		| `X9`		| `X10`		| `X11`		| `X12`		| +| `X13`		| `X14`		| `X15`		| `X16`		| `X17`		| `X18`		| +| `X19`		| `X20`		| `V1`		| `V2`		| `V3`		| `V4`		| +| `V5`		| `V6`		| `V7`		| `V8`		| `V9`		| `V10`		| +| `NIPPLE`	| `TOOLS`	| `SETUP`	| `BACKUP`	| `BLIND`	| `FREEZE`	| +| `PREVIEW`	| `FIX`		| `TEMP`	| `TOP`		| `VIEW`	| `EFFECT`	| +| `CHANNEL`	| `MOVE`	| `BLACKOUT`	| `PLEASE`	| `LIST`	| `USER1`	| +| `USER2`	| `ALIGN`	| `HELP`	| `UP`		| `DOWN`	| `FASTREVERSE`	| +| `LEARN`	| `FASTFORWARD`	| `GO_MINUS_SMALL` | `PAUSE_SMALL` | `GO_PLUS_SMALL` |		|  #### Known bugs / problems @@ -109,6 +136,5 @@ Data input from the console is done by actively querying the state of all mapped  at low latency. A lower input interval value will produce data with lower latency, at the cost of network & CPU usage.  Higher values will make the input "step" more, but will not consume as many CPU cycles and network bandwidth. -When requesting button executor events on the fader pages (execs 101 to 222) of a dot2 console, map at least one fader control from the 0 - 22 range or input will not work due to strange limitations in the MA Web API. - -Command line events are sent, but I'm not sure they're being handled yet. +When requesting button executor events on the fader pages (execs 101 to 222) of a dot2 console, map at least one fader control from the 0 - 22 range +or input will not work due to strange limitations in the MA Web API. diff --git a/backends/winmidi.c b/backends/winmidi.c index 67187ac..13c4b4a 100644 --- a/backends/winmidi.c +++ b/backends/winmidi.c @@ -21,6 +21,7 @@ static struct {  };  //TODO detect option +//TODO receive feedback socket until EAGAIN  int init(){  	backend winmidi = { @@ -465,7 +466,7 @@ static int winmidi_start(){  	}  	//open the feedback sockets -	//for some reason this while construct fails to work on 'real' windows with ipv6 +	//for some reason the feedback connection fails to work on 'real' windows with ipv6  	backend_config.socket_pair[0] = mmbackend_socket("127.0.0.1", "0", SOCK_DGRAM, 1, 0);  	if(backend_config.socket_pair[0] < 0){  		fprintf(stderr, "winmidi failed to open feedback socket\n");  | 
