diff --git a/Makefile b/Makefile index acf30dc1c502706a173b38430864690dd7b1d2a6..c0c47ed8572fdb7076379e03e017cfb70654c01e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ CCFLAGS+=-Wall -Werror -I$(shell pwd) -g LDFLAGS+=-L$(shell pwd)/build/ -lmoberg MODULES:=$(wildcard modules/*) export CCFLAGS LDFLAGS -LDFLAGS_parse_config=-ldl -export-dynamic +LDFLAGS_parse_config=-ldl +#-export-dynamic all: $(LIBRARIES:%=build/%) $(MODULES) echo $(MODULES) diff --git a/moberg.c b/moberg.c index 59de337df28ae1d040e9933a4bb8c4c43a3ba1a1..f66eac786437ad2640b5fa2774b80e11d6adcdfe 100644 --- a/moberg.c +++ b/moberg.c @@ -14,19 +14,66 @@ #include <moberg_config.h> #include <moberg_parser.h> -struct moberg_digital_in_t { - int index; - char *driver; -}; +static struct deferred_action { + struct deferred_action *next; + int (*action)(void *param); + void *param; +} *deferred_action = NULL; struct moberg { struct moberg_config *config; - struct { - int count; - struct moberg_digital_in_t *value; - } digital_in; + struct channel_list { + int capacity; + struct moberg_channel **value; + } analog_in, analog_out, digital_in, digital_out, encoder_in; }; +static int channel_list_set(struct channel_list *list, + int index, + struct moberg_channel *value) +{ + if (list->capacity <= index) { + int capacity; + for (capacity = 2 ; capacity <= index ; capacity *= 2); + void *new = realloc(list->value, capacity * sizeof(**list->value)); + if (!new) { + goto err; + } + void *p = new + list->capacity * sizeof(*list->value); + memset(p, 0, (capacity - list->capacity) * sizeof(**list->value)); + list->value = new; + list->capacity = capacity; + } + + if (0 <= index && index < list->capacity) { + list->value[index] = value; + return 1; + } +err: + return 0; +} + +static int channel_list_get(struct channel_list *list, + int index, + struct moberg_channel **value) +{ + if (0 <= index && index < list->capacity) { + *value = list->value[index]; + return 1; + } + return 0; +} + +static void channel_list_free(struct channel_list *list) +{ + for (int i = 0 ; i < list->capacity ; i++) { + if (list->value[i]) { + list->value[i]->down(list->value[i]); + } + } + free(list->value); +} + static void parse_config_at( struct moberg *moberg, int dirfd, @@ -88,12 +135,77 @@ static void parse_config_dir_at( } +static int install_channel(struct moberg *moberg, + int index, + struct moberg_device* device, + struct moberg_channel *channel) +{ + fprintf(stderr, "CHAN %p %d %d\n", channel, channel->kind, index); + if (channel) { + struct moberg_channel *old = NULL; + switch (channel->kind) { + case chan_ANALOGIN: + channel_list_get(&moberg->analog_in, index, &old); + break; + case chan_ANALOGOUT: + channel_list_get(&moberg->analog_out, index, &old); + break; + case chan_DIGITALIN: + channel_list_get(&moberg->digital_in, index, &old); + break; + case chan_DIGITALOUT: + channel_list_get(&moberg->digital_out, index, &old); + break; + case chan_ENCODERIN: + channel_list_get(&moberg->encoder_in, index, &old); + break; + } + if (old) { + old->down(old); + } + channel->up(channel); + /* TODO: Clean up old channel */ + switch (channel->kind) { + case chan_ANALOGIN: + if (! channel_list_set(&moberg->analog_in, index, channel)) { + goto err; + } + break; + case chan_ANALOGOUT: + if (! channel_list_set(&moberg->analog_out, index, channel)) { + goto err; + } + break; + case chan_DIGITALIN: + if (! channel_list_set(&moberg->digital_in, index, channel)) { + goto err; + } + break; + case chan_DIGITALOUT: + if (! channel_list_set(&moberg->digital_out, index, channel)) { + goto err; + } + break; + case chan_ENCODERIN: + if (! channel_list_set(&moberg->encoder_in, index, channel)) { + goto err; + } + break; + } + } + return 1; +err: + return 0; +} + static int install_config(struct moberg *moberg) { - struct moberg_install_channels install = { - .context=moberg + struct moberg_channel_install install = { + .context=moberg, + .channel=install_channel }; return moberg_config_install_channels(moberg->config, &install); + /* TODO cleanup unused devices...*/ } struct moberg *moberg_new( @@ -104,6 +216,16 @@ struct moberg *moberg_new( fprintf(stderr, "Failed to allocate moberg struct\n"); goto err; } + result->analog_in.capacity = 0; + result->analog_in.value = NULL; + result->analog_out.capacity = 0; + result->analog_out.value = NULL; + result->digital_in.capacity = 0; + result->digital_in.value = NULL; + result->digital_out.capacity = 0; + result->digital_out.value = NULL; + result->encoder_in.capacity = 0; + result->encoder_in.value = NULL; if (config) { result->config = config; } else { @@ -118,7 +240,6 @@ struct moberg *moberg_new( parse_config_at(result, dirfd1, "moberg.conf"); int dirfd2 = openat(dirfd1, "moberg.d", O_DIRECTORY); if (dirfd2 >= 0) { - parse_config_dir_at(result, dirfd2); parse_config_dir_at(result, dirfd2); close(dirfd2); } @@ -141,8 +262,20 @@ void moberg_free(struct moberg *moberg) { if (moberg) { moberg_config_free(moberg->config); + channel_list_free(&moberg->analog_in); + channel_list_free(&moberg->analog_out); + channel_list_free(&moberg->digital_in); + channel_list_free(&moberg->digital_out); + channel_list_free(&moberg->encoder_in); free(moberg); } + while (deferred_action) { + fprintf(stderr, "RUNNING deferred\n"); + struct deferred_action *deferred = deferred_action; + deferred_action = deferred_action->next; + deferred->action(deferred->param); + free(deferred); + } } enum moberg_status moberg_start( @@ -160,3 +293,16 @@ enum moberg_status moberg_stop( return moberg_OK; } +void moberg_deferred_action( + int (*action)(void *param), + void *param) +{ + struct deferred_action *deferred = malloc(sizeof(*deferred)); + if (deferred) { + fprintf(stderr, "DEFERRED %p %p\n", action, param); + deferred->next = deferred_action; + deferred->action = action; + deferred->param = param; + deferred_action = deferred; + } +} diff --git a/moberg_config.c b/moberg_config.c index 98491e068497723b9489bc6ece7caa842435e001..aac3855000b642f256850d527f04b534a2e5fa05 100644 --- a/moberg_config.c +++ b/moberg_config.c @@ -2,71 +2,12 @@ #include <string.h> #include <moberg_config.h> -#define LIST_COND_GROW(LIST, INDEX, ONERR) \ - ({ \ - if (LIST.capacity <= INDEX) { \ - int new_cap; \ - for (new_cap = 2 ; new_cap <= INDEX ; new_cap *= 2); \ - void *new = realloc(LIST.value, new_cap * sizeof(*LIST.value)); \ - if (! new) { ONERR; } \ - void *p = new + LIST.capacity * sizeof(*LIST.value); \ - memset(p, 0, (new_cap - LIST.capacity) * sizeof(*LIST.value)); \ - LIST.value = new; \ - LIST.capacity= new_cap; \ - } \ - }) - -#define LIST_SET(LIST, INDEX, VALUE, ONERR) \ - ( LIST_COND_GROW(LIST, INDEX, ONERR), \ - LIST.value[INDEX] = VALUE ) - -#define LIST_GET(LIST, INDEX, VALUE, ONERR) \ - ( LIST_COND_GROW(LIST, INDEX, ONERR), \ - LIST.value[INDEX] ) - struct moberg_config { struct device_entry { struct device_entry *next; struct moberg_device *device; - } *device; -#if 0 - struct { - int capacity; - struct analog_in_entry { - struct moberg_device* device; - struct moberg_device_analog_in *channel; - } *value; - } analog_in; - struct { - int capacity; - struct analog_out_entry { - struct moberg_device* device; - struct moberg_device_analog_out *channel; - } *value; - } analog_out; - struct { - int capacity; - struct digital_in_entry { - struct moberg_device* device; - struct moberg_device_digital_in *channel; - } *value; - } digital_in; - struct { - int capacity; - struct digital_out_entry { - struct moberg_device* device; - struct moberg_device_digital_out *channel; - } *value; - } digital_out; - struct { - int capacity; - struct encoder_in_entry { - struct moberg_device* device; - struct moberg_device_encoder_in *channel; - } *value; - } encoder_in; -#endif + } *device_head, **device_tail; }; struct moberg_config *moberg_config_new() @@ -74,19 +15,8 @@ struct moberg_config *moberg_config_new() struct moberg_config *result = malloc(sizeof *result); if (result) { - result->device = NULL; -#if 0 - result->analog_in.capacity = 0; - result->analog_in.value = NULL; - result->analog_out.capacity = 0; - result->analog_out.value = NULL; - result->digital_in.capacity = 0; - result->digital_in.value = NULL; - result->digital_out.capacity = 0; - result->digital_out.value = NULL; - result->encoder_in.capacity = 0; - result->encoder_in.value = NULL; -#endif + result->device_head = NULL; + result->device_tail = &result->device_head; } return result; @@ -94,31 +24,30 @@ struct moberg_config *moberg_config_new() void moberg_config_free(struct moberg_config *config) { - struct device_entry *entry = config->device; + struct device_entry *entry = config->device_head; while (entry) { struct device_entry *tmp = entry; entry = entry->next; moberg_device_free(tmp->device); free(tmp); } -#if 0 - free(config->analog_in.value); - free(config->analog_out.value); - free(config->digital_in.value); - free(config->digital_out.value); - free(config->encoder_in.value); -#endif free(config); } int moberg_config_join(struct moberg_config *dest, struct moberg_config *src) { - if (src && dest) { - struct device_entry **tail; - for (tail = &dest->device ; *tail ; tail = &(*tail)->next) { } - *tail = src->device; - src->device = NULL; + if (src && dest) { + while (src->device_head) { + struct device_entry *d = src->device_head; + src->device_head = d->next; + if (! src->device_head) { + src->device_tail = &src->device_head; + } + + *dest->device_tail = d; + dest->device_tail = &d->next; + } return 1; } return 0; @@ -129,79 +58,25 @@ int moberg_config_add_device(struct moberg_config *config, { struct device_entry *entry = malloc(sizeof(*entry)); - entry->next = config->device; + if (! entry) { goto err; } + entry->next = NULL; entry->device = device; - config->device = entry; + *config->device_tail = entry; + config->device_tail = &entry->next; return 1; +err: + return 0; } int moberg_config_install_channels(struct moberg_config *config, - struct moberg_install_channels *install) + struct moberg_channel_install *install) { - return moberg_device_install_channels(config->device->device, install); + int result = 1; + for (struct device_entry *d = config->device_head ; d ; d = d->next) { + result &= moberg_device_install_channels(d->device, install); + } + return result; } -#if 0 -int moberg_config_add_analog_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_analog_in *channel) -{ - struct analog_in_entry e = { device, channel }; - LIST_SET(config->analog_in, index, e, goto err); - return 1; -err: - return 0; -} - -int moberg_config_add_analog_out(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_analog_out *channel) -{ - struct analog_out_entry e = { device, channel }; - LIST_SET(config->analog_out, index, e, goto err); - return 1; -err: - return 0; -} - -int moberg_config_add_digital_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_digital_in *channel) -{ - struct digital_in_entry e = { device, channel }; - LIST_SET(config->digital_in, index, e, goto err); - return 1; -err: - return 0; -} - -int moberg_config_add_digital_out(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_digital_out *channel) -{ - struct digital_out_entry e = { device, channel }; - LIST_SET(config->digital_out, index, e, goto err); - return 1; -err: - return 0; -} - -int moberg_config_add_encoder_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_encoder_in *channel) -{ - struct encoder_in_entry e = { device, channel }; - LIST_SET(config->encoder_in, index, e, goto err); - return 1; -err: - return 0; -} - -#endif diff --git a/moberg_config.h b/moberg_config.h index 25401c303740abea1336a370cc3dfbd2929fb5a5..1aae2e4dbd0489415c2ad192e8a6c4fb3d2ffc1e 100644 --- a/moberg_config.h +++ b/moberg_config.h @@ -15,33 +15,6 @@ int moberg_config_add_device(struct moberg_config *config, struct moberg_device *device); int moberg_config_install_channels(struct moberg_config *config, - struct moberg_install_channels *install); - -#if 0 -int moberg_config_add_analog_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_analog_in *channel); - -int moberg_config_add_analog_out(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_analog_out *channel); - -int moberg_config_add_digital_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_digital_in *channel); - -int moberg_config_add_digital_out(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_digital_out *channel); - -int moberg_config_add_encoder_in(struct moberg_config *config, - int index, - struct moberg_device* device, - struct moberg_device_encoder_in *channel); -# endif + struct moberg_channel_install *install); #endif diff --git a/moberg_device.c b/moberg_device.c index 0d7226e5f36a1c96a48926cafd9c832a9d6862de..a6e6d8649a6ab915552e01e74c165d62e5417c0d 100644 --- a/moberg_device.c +++ b/moberg_device.c @@ -4,25 +4,26 @@ #include <dlfcn.h> #include <moberg_config.h> #include <moberg_device.h> +#include <moberg_channel.h> struct moberg_device { - void *driver_handle; struct moberg_device_driver driver; - struct moberg_device_config *device_config; + struct moberg_device_context *device_context; struct channel_list { struct channel_list *next; enum moberg_channel_kind kind; int index; union channel { - struct moberg_device_analog_in *analog_in; - struct moberg_device_analog_out *analog_out; - struct moberg_device_digital_in *digital_in; - struct moberg_device_digital_out *digital_out; - struct moberg_device_encoder_in *encoder_in; + struct moberg_channel_analog_in *analog_in; + struct moberg_channel_analog_out *analog_out; + struct moberg_channel_digital_in *digital_in; + struct moberg_channel_digital_out *digital_out; + struct moberg_channel_encoder_in *encoder_in; + struct moberg_channel *channel; } u; } *channel_head, **channel_tail; struct map_range { - struct moberg_config *config; + struct moberg_device *device; enum moberg_channel_kind kind; int min; int max; @@ -52,15 +53,21 @@ struct moberg_device *moberg_device_new(const char *driver) fprintf(stderr, "Could not allocate result for %s\n", name); goto dlclose_driver; } - result->driver_handle = handle; result->driver = *device_driver; - result->device_config = NULL; + result->device_context = result->driver.new(dlclose, handle); + if (result->device_context) { + result->driver.up(result->device_context); + } else { + fprintf(stderr, "Could not allocate context for %s\n", name); + goto free_result; + } result->channel_head = NULL; result->channel_tail = &result->channel_head; result->range = NULL; - goto free_name; +free_result: + free(result); dlclose_driver: dlclose(handle); free_name: @@ -78,48 +85,15 @@ void moberg_device_free(struct moberg_device *device) free(channel); channel = next; } - device->driver.config_free(device->device_config); - free(device->device_config); - dlclose(device->driver_handle); + int use = device->driver.down(device->device_context); + fprintf(stderr, "USE: %d\n", use); free(device); } int moberg_device_parse_config(struct moberg_device *device, - struct moberg_parser_context *context) -{ - return device->driver.parse_config(device, context); -} - -int moberg_device_set_config(struct moberg_device *device, - struct moberg_device_config *config) + struct moberg_parser_context *parser) { - if (device->device_config) { - device->driver.config_free(device->device_config); - free(device->device_config); - } - device->device_config = config; - return 1; -} - -int moberg_device_parse_map(struct moberg_device* device, - struct moberg_config *config, - struct moberg_parser_context *context, - enum moberg_channel_kind kind, - int min, - int max) -{ - int result; - struct map_range r = { - .config=config, - .kind=kind, - .min=min, - .max=max - }; - device->range = &r; - result = device->driver.parse_map(device, context, kind); - device->range = NULL; - printf("RRR %d %d\n", r.min, r.max); - return result; + return device->driver.parse_config(device->device_context, parser); } static int add_channel(struct moberg_device* device, @@ -141,7 +115,7 @@ err: } int moberg_device_add_analog_in(struct moberg_device* device, - struct moberg_device_analog_in *channel) + struct moberg_channel_analog_in *channel) { int result = 0; @@ -156,7 +130,7 @@ int moberg_device_add_analog_in(struct moberg_device* device, } int moberg_device_add_analog_out(struct moberg_device* device, - struct moberg_device_analog_out *channel) + struct moberg_channel_analog_out *channel) { int result = 0; @@ -171,7 +145,7 @@ int moberg_device_add_analog_out(struct moberg_device* device, } int moberg_device_add_digital_in(struct moberg_device* device, - struct moberg_device_digital_in *channel) + struct moberg_channel_digital_in *channel) { int result = 0; @@ -186,7 +160,7 @@ int moberg_device_add_digital_in(struct moberg_device* device, } int moberg_device_add_digital_out(struct moberg_device* device, - struct moberg_device_digital_out *channel) + struct moberg_channel_digital_out *channel) { int result = 0; @@ -201,7 +175,7 @@ int moberg_device_add_digital_out(struct moberg_device* device, } int moberg_device_add_encoder_in(struct moberg_device* device, - struct moberg_device_encoder_in *channel) + struct moberg_channel_encoder_in *channel) { int result = 0; @@ -215,10 +189,112 @@ int moberg_device_add_encoder_in(struct moberg_device* device, return result; } +static int map(struct moberg_device* device, + struct moberg_channel *channel) +{ + int result = 0; + + if (device->range->kind == channel->kind && + device->range->min <= device->range->max) { + printf("XX Mapping %d\n", device->range->min); + result = add_channel(device, device->range->kind, device->range->min, + (union channel) { .channel=channel }); + device->range->min++; + } + return result; + +} + +int moberg_device_parse_map(struct moberg_device* device, + struct moberg_parser_context *parser, + enum moberg_channel_kind kind, + int min, + int max) +{ + int result; + struct map_range r = { + .device=device, + .kind=kind, + .min=min, + .max=max + }; + struct moberg_channel_map map_channel = { + .device=device, +#if 0 + .analog_in=moberg_device_add_analog_in, + .analog_out=moberg_device_add_analog_out, + .digital_in=moberg_device_add_digital_in, + .digital_out= moberg_device_add_digital_out, + .encoder_in= moberg_device_add_encoder_in, +#endif + .map=map + }; + + device->range = &r; + result = device->driver.parse_map(device->device_context, parser, + kind, &map_channel); + device->range = NULL; + printf("RRR %d %d\n", r.min, r.max); + return result; +} + int moberg_device_install_channels(struct moberg_device *device, - struct moberg_install_channels *install) + struct moberg_channel_install *install) { + printf("INSTALL\n"); + struct channel_list *channel = device->channel_head; + while (channel) { + struct channel_list *next; + next = channel->next; + install->channel(install->context, + channel->index, + device, + channel->u.channel); + switch (channel->kind) { + case chan_ANALOGIN: { +/* + install->analog_in(install->context, + channel->index, + device, + channel->u.analog_in); +*/ + } break; + case chan_ANALOGOUT: { +/* + install->analog_out(install->context, + channel->index, + device, + channel->u.analog_out); +*/ + } break; + case chan_DIGITALIN: { +/* + install->digital_in(install->context, + channel->index, + device, + channel->u.digital_in); +*/ + } break; + case chan_DIGITALOUT: { +/* + install->digital_out(install->context, + channel->index, + device, + channel->u.digital_out); +*/ + } break; + case chan_ENCODERIN: { +/* + install->encoder_in(install->context, + channel->index, + device, + channel->u.encoder_in); +*/ + } break; + } + channel = next; + } return 1; } diff --git a/moberg_device.h b/moberg_device.h index 275c540b21abd5e6e0d5c9cc86bff88e2c36f1e5..6a5085eefed7c20bacb59aa89ab320cfe63475e0 100644 --- a/moberg_device.h +++ b/moberg_device.h @@ -1,76 +1,32 @@ #ifndef __MOBERG_DEVICE_H__ #define __MOBERG_DEVICE_H__ +struct moberg_device; +struct moberg_device_context; + #include <moberg.h> #include <moberg_config.h> #include <moberg_parser.h> - -enum moberg_channel_kind { - chan_ANALOGIN, - chan_ANALOGOUT, - chan_DIGITALIN, - chan_DIGITALOUT, - chan_ENCODERIN -}; - -struct moberg_device_analog_in { - struct moberg_device_analog_in_context *context; - int (*open)(struct moberg_device_analog_in_context *); - int (*close)(struct moberg_device_analog_in_context *); - int (*read)(struct moberg_device_analog_in_context *, double *value); -}; - -struct moberg_device_analog_out { - struct moberg_device_analog_out_context *context; - int (*open)(struct moberg_device_analog_out_context *); - int (*close)(struct moberg_device_analog_out_context *); - int (*write)(struct moberg_device_analog_out_context *, double value); -}; - -struct moberg_device_digital_in { - struct moberg_device_digital_in_context *context; - int (*open)(struct moberg_device_digital_in_context *); - int (*close)(struct moberg_device_digital_in_context *); - int (*read)(struct moberg_device_digital_in_context *, int *value); -}; - -struct moberg_device_digital_out { - struct moberg_device_digital_out_context *context; - int (*open)(struct moberg_device_digital_out_context *); - int (*close)(struct moberg_device_digital_out_context *); - int (*write)(struct moberg_device_digital_out_context *, int value); -}; - -struct moberg_device_encoder_in { - struct moberg_device_encoder_in_context *context; - int (*open)(struct moberg_device_encoder_in_context *); - int (*close)(struct moberg_device_encoder_in_context *); - int (*read)(struct moberg_device_encoder_in_context *, long *value); -}; - -struct moberg_install_channels { - struct moberg *context; - int (*analog_in)(int index, struct moberg_device_analog_in *channel); - int (*analog_out)(int index, struct moberg_device_analog_out *channel); - int (*digital_in)(int index, struct moberg_device_digital_in *channel); - int (*digital_out)(int index, struct moberg_device_digital_in *channel); - int (*encoder_in)(int index, struct moberg_device_encoder_in *channel); -}; +#include <moberg_channel.h> struct moberg_parser_context; -struct moberg_device; -struct moberg_device_config; struct moberg_device_driver { + /* Create new device context */ + struct moberg_device_context *(*new)(int (*dlclose)(void *dlhandle), + void *dlhandle); + /* Use-count of device, when it reaches zero, device will be free'd */ + int (*up)(struct moberg_device_context *context); + int (*down)(struct moberg_device_context *context); + /* Parse driver dependent parts of config file */ int (*parse_config)( - struct moberg_device* device, - struct moberg_parser_context *context); + struct moberg_device_context *device, + struct moberg_parser_context *parser); int (*parse_map)( - struct moberg_device* device, - struct moberg_parser_context *context, - enum moberg_channel_kind kind); - int (*config_free)( - struct moberg_device_config *config); + struct moberg_device_context *device, + struct moberg_parser_context *parser, + enum moberg_channel_kind kind, + struct moberg_channel_map *map); }; struct moberg_device; @@ -82,33 +38,14 @@ void moberg_device_free(struct moberg_device *device); int moberg_device_parse_config(struct moberg_device* device, struct moberg_parser_context *context); -int moberg_device_set_config(struct moberg_device* device, - struct moberg_device_config *config); - int moberg_device_parse_map(struct moberg_device* device, - struct moberg_config *config, - struct moberg_parser_context *context, + struct moberg_parser_context *parser, enum moberg_channel_kind kind, int min, int max); -int moberg_device_add_analog_in(struct moberg_device* device, - struct moberg_device_analog_in *channel); - -int moberg_device_add_analog_out(struct moberg_device* device, - struct moberg_device_analog_out *channel); - -int moberg_device_add_digital_in(struct moberg_device* device, - struct moberg_device_digital_in *channel); - -int moberg_device_add_digital_out(struct moberg_device* device, - struct moberg_device_digital_out *channel); - -int moberg_device_add_encoder_in(struct moberg_device* device, - struct moberg_device_encoder_in *channel); - int moberg_device_install_channels(struct moberg_device *device, - struct moberg_install_channels *install); + struct moberg_channel_install *install); #endif diff --git a/moberg_module.h b/moberg_module.h index 29ce50166c323fd44e6f763a6b1e09cfa9a643b6..6916bbf88d6b85120846bf81b4d0916afa1488b7 100644 --- a/moberg_module.h +++ b/moberg_module.h @@ -55,4 +55,8 @@ void moberg_parser_failed( struct moberg_parser_context *c, FILE *f); +void moberg_deferred_action( + int (*action)(void *param), + void *param); + #endif diff --git a/moberg_parser.c b/moberg_parser.c index da0c64600ef7d81e9029d25d19e1ee441a267f6a..61cd5cce769e879697846b4df74c40702554d6f7 100644 --- a/moberg_parser.c +++ b/moberg_parser.c @@ -328,7 +328,7 @@ static int parse_map(context_t *c, else { goto syntax_err; } if (! parse_map_range(c, &min, &max)) { goto syntax_err; } if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; } - if (! moberg_device_parse_map(device, c->config, c, kind, min, max)) { + if (! moberg_device_parse_map(device, c, kind, min, max)) { goto err; } if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; } diff --git a/modules/comedi/comedi.c b/modules/comedi/comedi.c index 4c078e6bda4a794c3999f4383cdfa2ce5d9314d0..c53521cda07ec014bc11c0a94befd1fb395f687c 100644 --- a/modules/comedi/comedi.c +++ b/modules/comedi/comedi.c @@ -11,11 +11,115 @@ typedef struct moberg_parser_token token_t; typedef struct moberg_parser_ident ident_t; typedef struct moberg_parser_context context_t; -struct moberg_device_map {}; -struct moberg_device_config { +struct moberg_device_context { + int (*dlclose)(void *dlhandle); + void *dlhandle; + int use_count; char *device; }; +struct moberg_channel_context { + void *to_free; /* To be free'd when use_count goes to zero */ + struct moberg_device_context *device; + int use_count; +}; + +struct moberg_channel_analog_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_analog_out { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_digital_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_digital_out { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_encoder_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +static struct moberg_device_context *new_context( + int (*dlclose)(void *dlhandle), + void *dlhandle) +{ + struct moberg_device_context *result = malloc(sizeof(*result)); + if (result) { + memset(result, 0, sizeof(*result)); + result->dlclose = dlclose; + result->dlhandle = dlhandle; + } + return result; +} + +static int device_up(struct moberg_device_context *context) +{ + context->use_count++; + return context->use_count; +} + +static int device_down(struct moberg_device_context *context) +{ + context->use_count--; + int result = context->use_count; + if (context->use_count <= 0) { + moberg_deferred_action(context->dlclose, context->dlhandle); + free(context->device); + free(context); + return 0; + } + return result; +} + +static int channel_up(struct moberg_channel *channel) +{ + device_up(channel->context->device); + channel->context->use_count++; + return channel->context->use_count; +} + +static int channel_down(struct moberg_channel *channel) +{ + device_down(channel->context->device); + channel->context->use_count--; + if (channel->context->use_count <= 0) { + free(channel->context->to_free); + return 0; + } + return channel->context->use_count; +} + +static void init_channel( + struct moberg_channel *channel, + void *to_free, + struct moberg_channel_context *context, + struct moberg_device_context *device, + enum moberg_channel_kind kind, + union moberg_channel_action action) +{ + context->to_free = to_free; + context->device = device; + context->use_count = 0; + + channel->context = context; + channel->up = channel_up; + channel->down = channel_down; + channel->open = NULL; + channel->close = NULL; + channel->kind = kind; + channel->action = action; +}; + static inline int acceptsym(context_t *c, kind_t kind, token_t *token) @@ -30,24 +134,19 @@ static inline int acceptkeyword(context_t *c, } static int parse_config( - struct moberg_device *device, + struct moberg_device_context *device, struct moberg_parser_context *c) { - struct moberg_device_config *config = malloc(sizeof *config); - if (! config) { - fprintf(stderr, "Failed to allocate moberg device config\n"); - goto err; - } if (! acceptsym(c, tok_LBRACE, NULL)) { goto syntax_err; } for (;;) { if (acceptsym(c, tok_RBRACE, NULL)) { break; } else if (acceptkeyword(c, "device")) { - token_t device; + token_t name; if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; } - if (! acceptsym(c, tok_STRING, &device)) { goto syntax_err; } + if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; } if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; } - config->device = strndup(device.u.string.value, device.u.string.length); + device->device = strndup(name.u.string.value, name.u.string.length); } else if (acceptkeyword(c, "config")) { if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; } if (! acceptsym(c, tok_LBRACKET, NULL)) { goto syntax_err; } @@ -78,19 +177,17 @@ static int parse_config( goto syntax_err; } } - moberg_device_set_config(device, config); return 1; syntax_err: moberg_parser_failed(c, stderr); - free(config); -err: return 0; } static int parse_map( - struct moberg_device *device, + struct moberg_device_context *device, struct moberg_parser_context *c, - enum moberg_channel_kind kind) + enum moberg_channel_kind kind, + struct moberg_channel_map *map) { token_t min, max; @@ -114,21 +211,86 @@ static int parse_map( } for (int i = min.u.integer.value ; i <= max.u.integer.value ; i++) { switch (kind) { - case chan_ANALOGIN: - moberg_device_add_analog_in(device, NULL); - break; - case chan_ANALOGOUT: - moberg_device_add_analog_out(device, NULL); - break; - case chan_DIGITALIN: - moberg_device_add_digital_in(device, NULL); - break; - case chan_DIGITALOUT: - moberg_device_add_digital_out(device, NULL); - break; - case chan_ENCODERIN: - moberg_device_add_encoder_in(device, NULL); - break; + case chan_ANALOGIN: { + struct moberg_channel_analog_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .analog_in.context=channel, + .analog_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_ANALOGOUT: { + struct moberg_channel_analog_out *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .analog_out.context=channel, + .analog_out.write=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_DIGITALIN: { + struct moberg_channel_digital_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .digital_in.context=channel, + .digital_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_DIGITALOUT: { + struct moberg_channel_digital_out *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .digital_out.context=channel, + .digital_out.write=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_ENCODERIN: { + struct moberg_channel_encoder_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .encoder_in.context=channel, + .encoder_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; } } if (! acceptsym(c, tok_RBRACKET, NULL)) { goto err; } @@ -142,14 +304,10 @@ err: return 0; } -static int config_free(struct moberg_device_config *config) -{ - free(config->device); - return 1; -} - struct moberg_device_driver moberg_device_driver = { - .parse_config = parse_config, - .parse_map = parse_map, - .config_free = config_free + .new=new_context, + .up=device_up, + .down=device_down, + .parse_config=parse_config, + .parse_map=parse_map, }; diff --git a/modules/serial2002/serial2002.c b/modules/serial2002/serial2002.c index 0c3448d94dd1aa52601b8a0521e72549146c90e7..9ab9e43fb108835ca3a56bb562133b8c875f42bf 100644 --- a/modules/serial2002/serial2002.c +++ b/modules/serial2002/serial2002.c @@ -10,6 +10,115 @@ typedef enum moberg_parser_token_kind kind_t; typedef struct moberg_parser_token token_t; typedef struct moberg_parser_context context_t; +struct moberg_device_context { + int (*dlclose)(void *dlhandle); + void *dlhandle; + int use_count; + char *name; + int baud; +}; + +struct moberg_channel_context { + void *to_free; /* To be free'd when use_count goes to zero */ + struct moberg_device_context *device; + int use_count; +}; + +struct moberg_channel_analog_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_analog_out { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_digital_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_digital_out { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +struct moberg_channel_encoder_in { + struct moberg_channel channel; + struct moberg_channel_context channel_context; +}; + +static struct moberg_device_context *new_context( + int (*dlclose)(void *dlhandle), + void *dlhandle) +{ + struct moberg_device_context *result = malloc(sizeof(*result)); + if (result) { + memset(result, 0, sizeof(*result)); + result->dlclose = dlclose; + result->dlhandle = dlhandle; + } + return result; +} + +static int device_up(struct moberg_device_context *context) +{ + context->use_count++; + return context->use_count; +} + +static int device_down(struct moberg_device_context *context) +{ + context->use_count--; + if (context->use_count <= 0) { + moberg_deferred_action(context->dlclose, context->dlhandle); + free(context->name); + free(context); + return 0; + } + return context->use_count; +} + +static int channel_up(struct moberg_channel *channel) +{ + device_up(channel->context->device); + channel->context->use_count++; + return channel->context->use_count; +} + +static int channel_down(struct moberg_channel *channel) +{ + device_down(channel->context->device); + channel->context->use_count--; + if (channel->context->use_count <= 0) { + free(channel->context->to_free); + return 0; + } + return channel->context->use_count; +} + +static void init_channel( + struct moberg_channel *channel, + void *to_free, + struct moberg_channel_context *context, + struct moberg_device_context *device, + enum moberg_channel_kind kind, + union moberg_channel_action action) +{ + context->to_free = to_free; + context->device = device; + context->use_count = 0; + + channel->context = context; + channel->up = channel_up; + channel->down = channel_down; + channel->open = NULL; + channel->close = NULL; + channel->kind = kind; + channel->action = action; +}; + static inline int acceptsym(context_t *c, kind_t kind, token_t *token) @@ -23,53 +132,41 @@ static inline int acceptkeyword(context_t *c, return moberg_parser_acceptkeyword(c, keyword); } -struct moberg_device_config { - char *device; - int baud; -}; - static int parse_config( - struct moberg_device *device, + struct moberg_device_context *device, struct moberg_parser_context *c) { - struct moberg_device_config *config = malloc(sizeof *config); - if (! config) { - fprintf(stderr, "Failed to allocate moberg device config\n"); - goto err; - } if (! acceptsym(c, tok_LBRACE, NULL)) { goto syntax_err; } for (;;) { if (acceptsym(c, tok_RBRACE, NULL)) { break; } else if (acceptkeyword(c, "device")) { - token_t device; + token_t name; if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; } - if (! acceptsym(c, tok_STRING, &device)) { goto syntax_err; } + if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; } if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; } - config->device = strndup(device.u.string.value, device.u.string.length); + device->name = strndup(name.u.string.value, name.u.string.length); } else if (acceptkeyword(c, "baud")) { token_t baud; if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; } if (! acceptsym(c, tok_INTEGER, &baud)) { goto syntax_err; } if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; } - config->baud = baud.u.integer.value; + device->baud = baud.u.integer.value; } else { goto syntax_err; } } - moberg_device_set_config(device, config); return 1; syntax_err: moberg_parser_failed(c, stderr); - free(config); -err: return 0; } static int parse_map( - struct moberg_device *device, + struct moberg_device_context *device, struct moberg_parser_context *c, - enum moberg_channel_kind ignore) + enum moberg_channel_kind ignore, + struct moberg_channel_map *map) { enum moberg_channel_kind kind; token_t min, max; @@ -90,21 +187,86 @@ static int parse_map( if (! acceptsym(c, tok_RBRACKET, NULL)) { goto syntax_err; } for (int i = min.u.integer.value ; i <= max.u.integer.value ; i++) { switch (kind) { - case chan_ANALOGIN: - moberg_device_add_analog_in(device, NULL); - break; - case chan_ANALOGOUT: - moberg_device_add_analog_out(device, NULL); - break; - case chan_DIGITALIN: - moberg_device_add_digital_in(device, NULL); - break; - case chan_DIGITALOUT: - moberg_device_add_digital_out(device, NULL); - break; - case chan_ENCODERIN: - moberg_device_add_encoder_in(device, NULL); - break; + case chan_ANALOGIN: { + struct moberg_channel_analog_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .analog_in.context=channel, + .analog_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_ANALOGOUT: { + struct moberg_channel_analog_out *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .analog_out.context=channel, + .analog_out.write=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_DIGITALIN: { + struct moberg_channel_digital_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .digital_in.context=channel, + .digital_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_DIGITALOUT: { + struct moberg_channel_digital_out *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .digital_out.context=channel, + .digital_out.write=NULL }); + map->map(map->device, &channel->channel); + } + } break; + case chan_ENCODERIN: { + struct moberg_channel_encoder_in *channel = + malloc(sizeof(*channel)); + + if (channel) { + init_channel(&channel->channel, + channel, + &channel->channel_context, + device, + kind, + (union moberg_channel_action) { + .encoder_in.context=channel, + .encoder_in.read=NULL }); + map->map(map->device, &channel->channel); + } + } break; } } return 1; @@ -113,15 +275,10 @@ syntax_err: return 0; } -static int config_free(struct moberg_device_config *config) -{ - free(config->device); - return 1; -} - - struct moberg_device_driver moberg_device_driver = { - .parse_config = parse_config, - .parse_map = parse_map, - .config_free = config_free + .new=new_context, + .up=device_up, + .down=device_down, + .parse_config=parse_config, + .parse_map=parse_map, };