Commit 21b59266 authored by Anders Blomdell's avatar Anders Blomdell
Browse files

AnalogIn works for comedi

parent 87b88706
......@@ -44,6 +44,7 @@ test: all
clean:
find build -type f -delete
rm -f *~
make -C test clean
build/libmoberg.so: build/lib/moberg_config.o
build/libmoberg.so: build/lib/moberg_device.o
......
......@@ -13,6 +13,7 @@
#include <moberg.h>
#include <moberg_config.h>
#include <moberg_parser.h>
#include <moberg_module.h>
struct moberg {
struct moberg_config *config;
......@@ -20,19 +21,19 @@ struct moberg {
int capacity;
struct moberg_channel **value;
} analog_in, analog_out, digital_in, digital_out, encoder_in;
};
struct deferred_action {
struct deferred_action *next;
int (*action)(void *param);
void *param;
} *deferred_action;
static struct deferred_action {
struct deferred_action *next;
int (*action)(void *param);
void *param;
} *deferred_action = NULL;
};
static void run_deferred_actions()
static void run_deferred_actions(struct moberg *moberg)
{
while (deferred_action) {
struct deferred_action *deferred = deferred_action;
deferred_action = deferred_action->next;
while (moberg->deferred_action) {
struct deferred_action *deferred = moberg->deferred_action;
moberg->deferred_action = deferred->next;
deferred->action(deferred->param);
free(deferred);
}
......@@ -100,7 +101,7 @@ static void parse_config_at(
buf[statbuf.st_size] = 0;
}
printf("Parsing... %s %d %d\n", pathname, dirfd, fd);
struct moberg_config *config = moberg_parse(buf);
struct moberg_config *config = moberg_parse(moberg, buf);
printf("-> %p\n", config);
if (config) {
if (! moberg->config) {
......@@ -236,6 +237,7 @@ struct moberg *moberg_new(
result->digital_out.value = NULL;
result->encoder_in.capacity = 0;
result->encoder_in.value = NULL;
result->deferred_action = NULL;
if (config) {
result->config = config;
} else {
......@@ -263,7 +265,7 @@ struct moberg *moberg_new(
/* Parse environment overrides */
}
install_config(result);
run_deferred_actions();
run_deferred_actions(result);
err:
return result;
......@@ -278,37 +280,72 @@ void moberg_free(struct moberg *moberg)
channel_list_free(&moberg->digital_in);
channel_list_free(&moberg->digital_out);
channel_list_free(&moberg->encoder_in);
run_deferred_actions(moberg);
free(moberg);
}
run_deferred_actions();
}
enum moberg_status moberg_start(
/* Input/output */
int moberg_analog_in_open(struct moberg *moberg,
int index,
struct moberg_analog_in *analog_in)
{
struct moberg_channel *channel = NULL;
channel_list_get(&moberg->analog_in, index, &channel);
if (channel) {
printf("Call open\n");
channel->open(channel);
channel->up(channel);
*analog_in = channel->action.analog_in;
return 1;
}
return 0;
}
int moberg_analog_in_close(struct moberg *moberg,
int index,
struct moberg_analog_in analog_in)
{
struct moberg_channel *channel = NULL;
channel_list_get(&moberg->analog_in, index, &channel);
if (channel && channel->action.analog_in.context == analog_in.context) {
printf("Call close\n");
channel->close(channel);
channel->down(channel);
}
return 1;
}
/* System init functionality (systemd/init/...) */
int moberg_start(
struct moberg *moberg,
FILE *f)
{
return moberg_config_start(moberg->config, f);
return moberg_OK;
}
enum moberg_status moberg_stop(
int moberg_stop(
struct moberg *moberg,
FILE *f)
{
return moberg_config_stop(moberg->config, f);
return moberg_OK;
}
void moberg_deferred_action(
int (*action)(void *param),
void *param)
/* Intended for final cleanup actions (dlclose so far...) */
void moberg_deferred_action(struct moberg *moberg,
int (*action)(void *param),
void *param)
{
struct deferred_action *deferred = malloc(sizeof(*deferred));
if (deferred) {
deferred->next = deferred_action;
deferred->next = moberg->deferred_action;
deferred->action = action;
deferred->param = param;
deferred_action = deferred;
moberg->deferred_action = deferred;
}
}
......@@ -6,46 +6,54 @@
struct moberg;
struct moberg_config;
enum moberg_status { moberg_OK };
/* Creation & free */
struct moberg *moberg_new(struct moberg_config *config);
void moberg_free(struct moberg *moberg);
/* Input/output functions */
/* Input/output */
enum moberg_status moberg_analog_in(
double *value,
struct moberg *moberg,
int channel);
struct moberg_analog_in {
struct moberg_channel_analog_in *context;
int (*read)(struct moberg_channel_analog_in *, double *value);
};
enum moberg_status moberg_analog_out(
double value,
struct moberg *moberg,
int channel);
struct moberg_analog_out {
struct moberg_channel_analog_out *context;
int (*write)(struct moberg_channel_analog_in *, double value);
};
enum moberg_status moberg_digital_in(
int *value,
struct moberg *moberg,
int channel);
struct moberg_digital_in {
struct moberg_channel_digital_in *context;
int (*read)(struct moberg_channel_digital_in *, int *value);
};
enum moberg_status moberg_digital_out(
int value,
struct moberg *moberg,
int channel);
struct moberg_digital_out {
struct moberg_channel_digital_out *context;
int (*write)(struct moberg_channel_digital_out *, int value);
};
enum moberg_status moberg_encoder_in(
long *value,
struct moberg *moberg,
int channel);
struct moberg_encoder_in {
struct moberg_channel_encoder_in *context;
int (*read)(struct moberg_channel_encoder_in *, long *value);
};
int moberg_analog_in_open(struct moberg *moberg,
int index,
struct moberg_analog_in *analog_in);
int moberg_analog_in_close(struct moberg *moberg,
int index,
struct moberg_analog_in analog_in);
/* Install functionality */
/* System init functionality (systemd/init/...) */
enum moberg_status moberg_start(
int moberg_start(
struct moberg *moberg,
FILE *f);
enum moberg_status moberg_stop(
int moberg_stop(
struct moberg *moberg,
FILE *f);
......
......@@ -25,26 +25,11 @@ struct moberg_channel {
/* I/O operations */
enum moberg_channel_kind kind;
union moberg_channel_action {
struct {
struct moberg_channel_analog_in *context;
int (*read)(struct moberg_channel_analog_in *, double *value);
} analog_in;
struct {
struct moberg_channel_analog_out *context;
int (*write)(struct moberg_channel_context *, double value);
} analog_out;
struct {
struct moberg_channel_digital_in *context;
int (*read)(struct moberg_channel_context *, int *value);
} digital_in;
struct {
struct moberg_channel_digital_out *context;
int (*write)(struct moberg_channel_context *, int value);
} digital_out;
struct {
struct moberg_channel_encoder_in *context;
int (*read)(struct moberg_channel_context *, long *value);
} encoder_in;
struct moberg_analog_in analog_in;
struct moberg_analog_out analog_out;
struct moberg_digital_in digital_in;
struct moberg_digital_out digital_out;
struct moberg_encoder_in encoder_in;
} action;
};
......
......@@ -30,7 +30,8 @@ struct moberg_device {
} *range;
};
struct moberg_device *moberg_device_new(const char *driver)
struct moberg_device *moberg_device_new(struct moberg *moberg,
const char *driver)
{
struct moberg_device *result = NULL;
......@@ -54,7 +55,7 @@ struct moberg_device *moberg_device_new(const char *driver)
goto dlclose_driver;
}
result->driver = *device_driver;
result->device_context = result->driver.new(dlclose, handle);
result->device_context = result->driver.new(moberg, dlclose, handle);
if (result->device_context) {
result->driver.up(result->device_context);
} else {
......
......@@ -13,7 +13,8 @@ struct moberg_parser_context;
struct moberg_device_driver {
/* Create new device context */
struct moberg_device_context *(*new)(int (*dlclose)(void *dlhandle),
struct moberg_device_context *(*new)(struct moberg *moberg,
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);
......@@ -41,7 +42,8 @@ struct moberg_device_driver {
struct moberg_device;
struct moberg_device *moberg_device_new(const char *driver);
struct moberg_device *moberg_device_new(struct moberg *moberg,
const char *driver);
void moberg_device_free(struct moberg_device *device);
......
......@@ -55,6 +55,7 @@ void moberg_parser_failed(
FILE *f);
void moberg_deferred_action(
struct moberg *moberg,
int (*action)(void *param),
void *param);
......
......@@ -361,7 +361,8 @@ err:
return 0;
}
static int parse(context_t *c)
static int parse(struct moberg *moberg,
context_t *c)
{
for (;;) {
if (acceptsym(c, tok_EOF, NULL)) {
......@@ -381,18 +382,20 @@ static int parse(context_t *c)
t.u.idstr.length, t.u.idstr.value);
goto err;
}
device = moberg_device_new(name);
device = moberg_device_new(moberg, name);
free(name);
if (! device) { goto err; }
if (! parse_device(c, device)) {
moberg_device_free(device);
goto err;
goto device_free;
}
if (! moberg_config_add_device(c->config, device)) {
moberg_device_free(device);
goto err;
goto device_free;
}
continue;
device_free:
moberg_device_free(device);
goto err;
}
}
return 1;
......@@ -403,7 +406,8 @@ err:
return 0;
}
struct moberg_config *moberg_parse(const char *buf)
struct moberg_config *moberg_parse(struct moberg *moberg,
const char *buf)
{
context_t context;
......@@ -413,7 +417,7 @@ struct moberg_config *moberg_parse(const char *buf)
context.buf = buf;
context.p = context.buf;
nextsym(&context);
if (! parse(&context)) {
if (! parse(moberg, &context)) {
moberg_config_free(context.config);
context.config = NULL;
}
......
#ifndef __MOBERG_PARSER_H__
#define __MOBERG_PARSER_H__
#include <moberg.h>
#include <moberg_config.h>
struct moberg_parser_context;
struct moberg_config *moberg_parse(const char *buf);
struct moberg_config *moberg_parse(struct moberg* moberg,
const char *buf);
#endif
LIBRARIES=libmoberg_comedi.so
CCFLAGS+=-Wall -Werror -I../.. -g
LDFLAGS+=-Lbuild/ -lmoberg
MODULES=$(wildcard modules/*)
all: $(LIBRARIES:%=../../build/%)
../../build/libmoberg_comedi.so: comedi.c Makefile
$(CC) -o $@ $(CCFLAGS) -shared -fPIC $<
$(CC) -o $@ $(CCFLAGS) -shared -fPIC -lcomedi $<
../../build/libmoberg_comedi.so: ../../moberg_module.h
......@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <comedilib.h>
typedef enum moberg_parser_token_kind kind_t;
typedef struct moberg_parser_token token_t;
......@@ -12,10 +13,15 @@ typedef struct moberg_parser_ident ident_t;
typedef struct moberg_parser_context context_t;
struct moberg_device_context {
struct moberg *moberg;
int (*dlclose)(void *dlhandle);
void *dlhandle;
int use_count;
char *name;
struct {
int count;
comedi_t *handle;
} comedi;
struct idstr {
struct idstr *next;
struct idstr *prev;
......@@ -28,6 +34,15 @@ 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 channel_descriptor {
int subdevice;
int subchannel;
int route;
lsampl_t maxdata;
double min;
double max;
double delta;
} descriptor;
};
struct moberg_channel_analog_in {
......@@ -55,13 +70,29 @@ struct moberg_channel_encoder_in {
struct moberg_channel_context channel_context;
};
static struct moberg_device_context *new_context(
int (*dlclose)(void *dlhandle),
void *dlhandle)
static int analog_in_read(struct moberg_channel_analog_in *analog_in,
double *value)
{
struct channel_descriptor descriptor = analog_in->channel_context.descriptor;
lsampl_t data;
comedi_data_read(analog_in->channel_context.device->comedi.handle,
descriptor.subdevice,
descriptor.subchannel,
0, 0, &data);
*value = descriptor.min + data * descriptor.delta;
fprintf(stderr, "Data: %d %f\n", data, *value);
return 1;
}
static struct moberg_device_context *new_context(struct moberg *moberg,
int (*dlclose)(void *dlhandle),
void *dlhandle)
{
struct moberg_device_context *result = malloc(sizeof(*result));
if (result) {
memset(result, 0, sizeof(*result));
result->moberg = moberg;
result->dlclose = dlclose;
result->dlhandle = dlhandle;
result->modprobe_list.next = &result->modprobe_list;
......@@ -72,41 +103,67 @@ static struct moberg_device_context *new_context(
return result;
}
static int device_up(struct moberg_device_context *context)
static int device_up(struct moberg_device_context *device)
{
context->use_count++;
return context->use_count;
device->use_count++;
return device->use_count;
}
static int device_down(struct moberg_device_context *context)
static int device_down(struct moberg_device_context *device)
{
context->use_count--;
int result = context->use_count;
if (context->use_count <= 0) {
moberg_deferred_action(context->dlclose, context->dlhandle);
free(context->name);
device->use_count--;
int result = device->use_count;
if (device->use_count <= 0) {
moberg_deferred_action(device->moberg,
device->dlclose, device->dlhandle);
free(device->name);
struct idstr *e;
e = context->modprobe_list.next;
while (e != &context->modprobe_list) {
e = device->modprobe_list.next;
while (e != &device->modprobe_list) {
struct idstr *next = e->next;
free(e->value);
free(e);
e = next;
}
e = context->config_list.next;
while (e != &context->config_list) {
e = device->config_list.next;
while (e != &device->config_list) {
struct idstr *next = e->next;
free(e->value);
free(e);
e = next;
}
free(context);
free(device);
return 0;
}
return result;
}
static int device_open(struct moberg_device_context *device)
{
if (device->comedi.count == 0) {
device->comedi.handle = comedi_open(device->name);
if (device->comedi.handle == NULL) {
goto err;
}
}
device->comedi.count++;
return 1;
err:
fprintf(stderr, "Failed to open %s\n", device->name);
return 0;
}
static int device_close(struct moberg_device_context *device)
{
device->comedi.count--;
if (device->comedi.count == 0) {
comedi_close(device->comedi.handle);
}
return 1;
}
static int channel_up(struct moberg_channel *channel)
{
device_up(channel->context->device);
......@@ -125,22 +182,73 @@ static int channel_down(struct moberg_channel *channel)
return channel->context->use_count;
}
static int channel_open(struct moberg_channel *channel)
{
channel_up(channel);
if (! device_open(channel->context->device)) { goto err; }
fprintf(stderr, "Open %s[%d][%d]\n",
channel->context->device->name,
channel->context->descriptor.subdevice,
channel->context->descriptor.subchannel);
lsampl_t maxdata;
comedi_range *range;
maxdata = comedi_get_maxdata(channel->context->device->comedi.handle,
channel->context->descriptor.subdevice,
channel->context->descriptor.subchannel);
range = comedi_get_range(channel->context->device->comedi.handle,
channel->context->descriptor.subdevice,
channel->context->descriptor.subchannel,
0);
if (! maxdata) {
fprintf(stderr, "Failed to get maxdata for %s[%d][%d]\n",
channel->context->device->name,
channel->context->descriptor.subdevice,
channel->context->descriptor.subchannel);
goto err;
}
if (! range) {
fprintf(stderr, "Failed to get range for %s[%d][%d]\n",
channel->context->device->name,
channel->context->descriptor.subdevice,
channel->context->descriptor.subchannel);
goto err;
}
channel->context->descriptor.maxdata = maxdata;
channel->context->descriptor.min = range->min;
channel->context->descriptor.max = range->max;
channel->context->descriptor.delta = (range->max - range->min) / maxdata;
return 1;
err:
return 0;
}
static int channel_close(struct moberg_channel *channel)
{
device_close(channel->context->device);
channel_down(channel);
return 1;
}
static void init_channel(struct moberg_channel *channel,
void *to_free,
struct moberg_channel_context *context,
struct moberg_device_context *device,
struct channel_descriptor descriptor,
enum moberg_channel_kind kind,
union moberg_channel_action action)
{
context->to_free = to_free;
context->device = device;
context->use_count = 0;
context->descriptor = descriptor;
channel->context = context;
channel->up = channel_up;
channel->down = channel_down;
channel->open