diff options
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | artnet.c | 49 | ||||
| -rw-r--r-- | artnet.h | 17 | ||||
| -rw-r--r-- | backend.c | 10 | ||||
| -rw-r--r-- | backend.h | 3 | ||||
| -rw-r--r-- | midi.c | 2 | ||||
| -rw-r--r-- | midimonster.c | 106 | ||||
| -rw-r--r-- | midimonster.h | 8 | 
8 files changed, 186 insertions, 10 deletions
| @@ -0,0 +1 @@ +Wide channels (DMX/MIDI) @@ -3,6 +3,13 @@  #define BACKEND_NAME "artnet"  static uint8_t default_net = 0; +static struct { +	char* host; +	char* port; +} bind = { +	.host = NULL, +	.port = NULL +};  int artnet_init(){  	backend artnet = { @@ -26,8 +33,20 @@ int artnet_init(){  }  static int artnet_configure(char* option, char* value){ +	char* separator = value;  	if(!strcmp(option, "bind")){ -		//TODO create socket, hand over to be managed (unregister previous socket?) +		for(; *separator && *separator != ' '; separator++){ +		} + +		if(*separator){ +			*separator = 0; +			separator++; +			free(bind.port); +			bind.port = strdup(separator); +		} + +		free(bind.host); +		bind.host = strdup(value);  		return 0;  	}  	else if(!strcmp(option, "net")){ @@ -67,10 +86,10 @@ static int artnet_configure_instance(instance* instance, char* option, char* val  	}  	else if(!strcmp(option, "output")){  		if(!strcmp(value, "true")){ -			data->mode |= MODE_OUTPUT; +			data->mode |= output;  		}  		else{ -			data->mode &= ~MODE_OUTPUT; +			data->mode &= ~output;  		}  		return 0;  	} @@ -99,8 +118,25 @@ static int artnet_handle(size_t num, int* fd, void** data){  }  static int artnet_start(){ -	//TODO -	return 1; +	if(!bind.host){ +		bind.host = strdup("127.0.0.1"); +	} + +	if(!bind.port){ +		bind.port = strdup("6454"); +	} + +	if(!bind.host || !bind.port){ +		fprintf(stderr, "Failed to allocate memory\n"); +		return 1; +	} + +	//TODO allocate all active universes +	//TODO open socket +	fprintf(stderr, "Listening for ArtNet data on %s port %s\n", bind.host, bind.port); +	//TODO parse all universe destinations + +	return 0;  }  static int artnet_shutdown(){ @@ -115,6 +151,9 @@ static int artnet_shutdown(){  		free(inst[p]->impl);  	}  	free(inst); + +	free(bind.host); +	free(bind.port);  	fprintf(stderr, "ArtNet backend shut down\n");  	return 0;  } @@ -10,10 +10,23 @@ static int artnet_handle(size_t num, int* fd, void** data);  static int artnet_start();  static int artnet_shutdown(); -#define MODE_OUTPUT 1 -  typedef struct /*_artnet_instance_model*/ {  	uint8_t net;  	uint8_t uni;  	uint8_t mode; +	char* dest;  } artnet_instance_data; + +enum { +	output = 1, +	mark = 2 +}; + +typedef struct /*_artnet_universe_model*/ { +	uint8_t net; +	uint8_t uni; +	uint8_t flags; +	uint8_t last_frame; +	uint8_t data[512]; +	uint8_t mask[512]; +} artnet_universe; @@ -127,6 +127,16 @@ instance* instance_match(char* name){  	return NULL;  } +struct timeval backend_timeout(){ +	//TODO fetch minimum poll interval from backends +	struct timeval tv = { +		0, +		10000 +	}; + +	return tv; +} +  int mm_backend_register(backend b){  	if(!backend_match(b.name)){  		backends = realloc(backends, (nbackends + 1) * sizeof(backend)); @@ -1,5 +1,8 @@ +#include <sys/types.h> +  backend* backend_match(char* name);  instance* instance_match(char* name); +struct timeval backend_timeout();  int backends_start();  int backends_stop();  void instances_free(); @@ -141,7 +141,7 @@ static int midi_handle(size_t num, int* fd, void** data){  }  static int midi_start(){ -	return 1; +	return 0;  }  static int midi_shutdown(){ diff --git a/midimonster.c b/midimonster.c index 367ca6f..2c3013d 100644 --- a/midimonster.c +++ b/midimonster.c @@ -1,4 +1,8 @@  #include <string.h> +#include <signal.h> +#include <sys/select.h> +#include <unistd.h> +#include <errno.h>  #include "midimonster.h"  #include "config.h"  #include "backend.h" @@ -10,6 +14,13 @@ int osc_init();  static size_t mappings = 0;  static channel_mapping* map = NULL; +static size_t fds = 0; +static managed_fd* fd = NULL; +volatile static sig_atomic_t shutdown_requested = 0; + +void signal_handler(int signum){ +	shutdown_requested = 1; +}  int mm_map_channel(channel* from, channel* to){  	size_t u, m; @@ -60,6 +71,68 @@ void map_free(){  	map = NULL;  } +int mm_manage_fd(int new_fd, char* back, int manage, void* impl){ +	backend* b = backend_match(back); +	size_t u; + +	if(!b){ +		fprintf(stderr, "Unknown backend %s registered for managed fd\n", back); +		return 1; +	} + +	//find exact match +	for(u = 0; u < fds; u++){ +		if(fd[u].fd == new_fd && fd[u].backend == b){ +			if(!manage){ +				fd[u].fd = -1; +				fd[u].backend = NULL; +				fd[u].impl = NULL; +			} +			return 0; +		} +	} + +	if(!manage){ +		return 0; +	} + +	//find free slot +	for(u = 0; u < fds; u++){ +		if(fd[u].fd < 0){ +			break; +		} +	} +	//if necessary expand +	if(u == fds){ +		fd = realloc(fd, (fds + 1) * sizeof(managed_fd)); +		if(!fd){ +			fprintf(stderr, "Failed to allocate memory\n"); +			return 1; +		} +		fds++; +	} + +	//store new fd +	fd[u].fd = new_fd; +	fd[u].backend = b; +	fd[u].impl = impl; +	return 0; +} + +void fds_free(){ +	size_t u; +	for(u = 0; u < fds; u++){ +		//TODO free impl +		if(fd[u].fd >= 0){ +			close(fd[u].fd); +			fd[u].fd = -1; +		} +	} +	free(fd); +	fds = 0; +	fd = NULL; +} +  int usage(char* fn){  	fprintf(stderr, "MIDIMonster v0.1\n");  	fprintf(stderr, "Usage:\n"); @@ -68,7 +141,10 @@ int usage(char* fn){  }  int main(int argc, char** argv){ -	int rv = EXIT_FAILURE; +	fd_set all_fds, read_fds; +	struct timeval tv; +	size_t u; +	int rv = EXIT_FAILURE, error, maxfd = -1;  	char* cfg_file = DEFAULT_CFG;  	if(argc > 1){  		cfg_file = argv[1]; @@ -88,6 +164,7 @@ int main(int argc, char** argv){  		channels_free();  		instances_free();  		map_free(); +		fds_free();  		return usage(argv[0]);  	} @@ -97,7 +174,31 @@ int main(int argc, char** argv){  		goto bail;  	} -	//TODO wait for & translate events +	signal(SIGINT, signal_handler); + +	//create initial fd set +	FD_ZERO(&all_fds); +	for(u = 0; u < fds; u++){ +		if(fd[u].fd >= 0){ +			FD_SET(fd[u].fd, &all_fds); +			maxfd = max(maxfd, fd[u].fd); +		} +	} + +	//process events +	while(!shutdown_requested){ +		//wait for & translate events +		read_fds = all_fds; +		tv = backend_timeout(); +		error = select(maxfd + 1, &read_fds, NULL, NULL, &tv); +		if(error < 0){ +			fprintf(stderr, "select failed: %s\n", strerror(errno)); +			break; +		} +		//TODO process all backends, collect events +		//TODO push all events to backends +		//FIXME notify non-fd backends +	}  	rv = EXIT_SUCCESS;  bail: @@ -106,6 +207,7 @@ bail:  	channels_free();  	instances_free();  	map_free(); +	fds_free();  	return rv;  } diff --git a/midimonster.h b/midimonster.h index b2af7a3..181f1da 100644 --- a/midimonster.h +++ b/midimonster.h @@ -3,6 +3,7 @@  #include <stdio.h>  #include <stdlib.h>  #include <stdint.h> +#define max(a,b) (((a) > (b)) ? (a) : (b))  #define DEFAULT_CFG "monster.cfg" @@ -54,6 +55,7 @@ typedef struct _backend_channel {  } channel;  //FIXME might be replaced by struct pollfd +//FIXME who frees impl  typedef struct /*_mm_managed_fd*/ {  	int fd;  	backend* backend; @@ -97,6 +99,12 @@ instance* mm_instance();   * will receive a call to its channel_free function.   */  channel* mm_channel(instance* i, uint64_t ident); +/* + * Register a file descriptor to be selected on. The backend + * will be notified via the mmbackend_process_fd call. + * This function may only be called from within the + * mmbackend_start procedure. + */  int mm_manage_fd(int fd, char* backend, int manage, void* impl);  int mm_channel_event(channel* c, channel_value v);  /* | 
