From 40e123db7713b188162cd94d935f7a395405567a Mon Sep 17 00:00:00 2001 From: cbdev Date: Mon, 5 Jun 2017 18:53:41 +0200 Subject: Core select loop --- TODO | 1 + artnet.c | 49 ++++++++++++++++++++++++--- artnet.h | 17 ++++++++-- backend.c | 10 ++++++ backend.h | 3 ++ midi.c | 2 +- midimonster.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- midimonster.h | 8 +++++ 8 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..c83eb34 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +Wide channels (DMX/MIDI) diff --git a/artnet.c b/artnet.c index 2684d46..6eef2fe 100644 --- a/artnet.c +++ b/artnet.c @@ -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; } diff --git a/artnet.h b/artnet.h index 8e05153..4976938 100644 --- a/artnet.h +++ b/artnet.h @@ -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; diff --git a/backend.c b/backend.c index 65ee748..f49bd91 100644 --- a/backend.c +++ b/backend.c @@ -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)); diff --git a/backend.h b/backend.h index e1ad4ab..16cf77e 100644 --- a/backend.h +++ b/backend.h @@ -1,5 +1,8 @@ +#include + backend* backend_match(char* name); instance* instance_match(char* name); +struct timeval backend_timeout(); int backends_start(); int backends_stop(); void instances_free(); diff --git a/midi.c b/midi.c index 3cd8507..00ff0a4 100644 --- a/midi.c +++ b/midi.c @@ -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 +#include +#include +#include +#include #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 #include #include +#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); /* -- cgit v1.2.3