diff --git a/include/villas/nodes/comedi.h b/include/villas/nodes/comedi.h index f9a14743f..fd61d52ff 100644 --- a/include/villas/nodes/comedi.h +++ b/include/villas/nodes/comedi.h @@ -34,9 +34,21 @@ #include #include +struct comedi_direction { + double rate; + + bool enabled; + int subdevice; + + unsigned *chanlist; + size_t chanlist_len; +}; + struct comedi { char *device; + struct comedi_direction in, out; + comedi_t *it; }; diff --git a/lib/nodes/comedi.c b/lib/nodes/comedi.c index c918aa390..17d103602 100644 --- a/lib/nodes/comedi.c +++ b/lib/nodes/comedi.c @@ -27,6 +27,153 @@ #include #include +static int comedi_parse_direction(struct comedi_direction *d, json_t *cfg) +{ + int ret; + + json_t *json_chans; + json_error_t err; + + d->subdevice = -1; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s: o, s: F }", + "subdevice", &d->subdevice, + "channels", &json_chans, + "rate", &d->rate + ); + if (ret) + jerror(&err, "Failed to parse configuration"); + + if (!json_is_array(json_chans)) + return -1; + + size_t i; + json_t *json_chan; + + json_array_foreach(json_chans, i, json_chan) { + if (!json_is_integer(json_chan)) + return -1; + + + } + + return 0; +} + +static int comedi_start_in(struct node *n) +{ + int ret; + struct comedi *c = (struct comedi *) n->_vd; + struct comedi_direction *d = &c->in; + + if (d->subdevice >= 0) { + + } + else { + d->subdevice = comedi_find_subdevice_by_type(c->it, COMEDI_SUBD_AI, 0); + if (d->subdevice < 0) + error("Cannot find analog input device for node '%s'", node_name(n)); + } + + /* Check if subdevice is usable */ + ret = comedi_get_subdevice_type(c->it, d->subdevice); + if (ret != COMEDI_SUBD_AI) + error("Input subdevice of node '%s' is not an analog input", node_name(n)); + + ret = comedi_get_subdevice_flags(c->it, d->subdevice); + if (ret ) + + ret = comedi_lock(c->it, d->subdevice); + if (ret) + error("Failed to lock subdevice %d for node '%s'", d->subdevice, node_name(n)); + +#if 0 + comedi_cmd cmd = { + .subdev = d->subdevice, + .flags = CMDF_READ, + .start_src = TRIG_INT, + .start_arg = 0, + .scan_begin_src = TRIG_TIMER, + .scan_begin_arg = 1e9 / c->in.rate, + .convert_src = TRIG_NOW, + .convert_arg = 0, + .scan_end_src = TRIG_COUNT, + .scan_end_arg = c->in.chanlist_len, + .stop_src = TRIG_NONE, + .stop_arg = 0, + .chanlist = c->in.chanlist, + .chanlist_len = c->in.chanlist_len, + }; +#endif + + return 0; +} + +static int comedi_start_out(struct node *n) +{ + int ret; + struct comedi *c = (struct comedi *) n->_vd; + struct comedi_direction *d = &c->out; + + ret = comedi_get_subdevice_type(c->it, d->subdevice); + if (ret != COMEDI_SUBD_AO) + error("Output subdevice of node '%s' is not an analog output", node_name(n)); + + ret = comedi_get_subdevice_flags(c->it, d->subdevice); + if (ret ) + + ret = comedi_lock(c->it, d->subdevice); + if (ret) + error("Failed to lock subdevice %d for node '%s'", d->subdevice, node_name(n)); + +#if 0 + comedi_cmd cmd = { + .subdev = c->out.subdevice, + .flags = CMDF_WRITE, + .start_src = TRIG_INT, + .start_arg = 0, + .scan_begin_src = TRIG_TIMER, + .scan_begin_arg = 1e9 / c->out.rate, + .convert_src = TRIG_NOW, + .convert_arg = 0, + .scan_end_src = TRIG_COUNT, + .scan_end_arg = c->out.chanlist_len, + .stop_src = TRIG_NONE, + .stop_arg = 0, + .chanlist = c->out.chanlist, + .chanlist_len = c->out.chanlist_len, + }; +#endif + + return 0; +} + +static int comedi_stop_in(struct node *n) +{ + int ret; + struct comedi *c = (struct comedi *) n->_vd; + struct comedi_direction *d = &c->in; + + ret = comedi_unlock(c->it, d->subdevice); + if (ret) + error("Failed to lock subdevice %d for node '%s'", d->subdevice, node_name(n)); + + return 0; +} + +static int comedi_stop_out(struct node *n) +{ + int ret; + struct comedi *c = (struct comedi *) n->_vd; + struct comedi_direction *d = &c->out; + + ret = comedi_unlock(c->it, d->subdevice); + if (ret) + error("Failed to lock subdevice %d for node '%s'", d->subdevice, node_name(n)); + + return 0; +} + int comedi_parse(struct node *n, json_t *cfg) { int ret; @@ -34,14 +181,30 @@ int comedi_parse(struct node *n, json_t *cfg) const char *device; + json_t *json_in = NULL; + json_t *json_out = NULL; json_error_t err; ret = json_unpack_ex(cfg, &err, 0, "{ s: s }", - "device", &device + "device", &device, + "in", &json_in, + "out", &json_out ); if (ret) jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + if (json_in) { + ret = comedi_parse_direction(&c->in, json_in); + if (ret) + return -1; + } + + if (json_out) { + ret = comedi_parse_direction(&c->out, json_out); + if (ret) + return -1; + } + c->device = strdup(device); return 0; @@ -53,7 +216,10 @@ char * comedi_print(struct node *n) char *buf = NULL; - strcatf(&buf, "device=%s", c->device); + const char *board = comedi_get_board_name(c->it); + const char *driver = comedi_get_driver_name(c->it); + + strcatf(&buf, "board=%s, driver=%s, device=%s", board, driver, c->device); return buf; } @@ -68,6 +234,9 @@ int comedi_start(struct node *n) error("Failed to open device: %s", err); } + comedi_start_in(n); + comedi_start_out(n); + return 0; } @@ -76,6 +245,9 @@ int comedi_stop(struct node *n) int ret; struct comedi *c = (struct comedi *) n->_vd; + comedi_stop_in(n); + comedi_stop_out(n); + ret = comedi_close(c->it); if (ret) return ret; @@ -85,23 +257,23 @@ int comedi_stop(struct node *n) int comedi_read(struct node *n, struct sample *smps[], unsigned cnt) { - //struct comedi *c = (struct comedi *) n->_vd; +// struct comedi *c = (struct comedi *) n->_vd; return -1; } int comedi_write(struct node *n, struct sample *smps[], unsigned cnt) { - //struct comedi *c = (struct comedi *) n->_vd; +// struct comedi *c = (struct comedi *) n->_vd; return -1; } int comedi_fd(struct node *n) { - //struct comedi *c = (struct comedi *) n->_vd; + struct comedi *c = (struct comedi *) n->_vd; - return -1; + return comedi_fileno(c->it); } static struct plugin p = { @@ -117,6 +289,8 @@ static struct plugin p = { .stop = comedi_stop, .read = comedi_read, .write = comedi_write, +// .create = comedi_create, +// .destroy = comedi_destroy, .fd = comedi_fd } };