From 6ca5f79ff0f301f7931af734e8d093cf66656ca6 Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@gmail.com>
Date: Fri, 15 Mar 2019 13:58:21 +0100
Subject: [PATCH] add timeout parameter to serial_2002 driver

---
 plugins/serial2002/Makefile                   |   1 +
 plugins/serial2002/serial2002.c               |  27 +-
 plugins/serial2002/serial2002_lib.c           | 408 +-----------------
 plugins/serial2002/serial2002_lib.h           |   3 +-
 .../moberg.d/00-comedi_ttyUSB0_serial.conf    |  14 +
 .../moberg.d/30-comedi_ttyUSB0_serial.conf    |  17 +
 6 files changed, 62 insertions(+), 408 deletions(-)
 create mode 100644 test/.config/moberg.d/00-comedi_ttyUSB0_serial.conf
 create mode 100644 test/.config/moberg.d/30-comedi_ttyUSB0_serial.conf

diff --git a/plugins/serial2002/Makefile b/plugins/serial2002/Makefile
index f5a9a0a..a6b40ea 100644
--- a/plugins/serial2002/Makefile
+++ b/plugins/serial2002/Makefile
@@ -17,5 +17,6 @@ build:
 
 build/serial2002.o: ../../moberg_module.h
 build/serial2002.o: serial2002_lib.h
+build/serial2002_lib.o: serial2002_lib.h
 build/libmoberg_serial2002.so: build/serial2002.o
 build/libmoberg_serial2002.so: build/serial2002_lib.o
diff --git a/plugins/serial2002/serial2002.c b/plugins/serial2002/serial2002.c
index 379da56..79de31d 100644
--- a/plugins/serial2002/serial2002.c
+++ b/plugins/serial2002/serial2002.c
@@ -47,6 +47,7 @@ struct moberg_device_context {
     int count;
     char *name;
     int baud;
+    long timeout;
     int fd;
   } port;
   struct remap_analog {
@@ -108,14 +109,14 @@ static struct moberg_status analog_in_read(
   
   struct moberg_channel_context *channel = &analog_in->channel_context;
   struct moberg_device_context *device = channel->device;
-  struct serial2002_data data = { 0, 0 };
+  struct serial2002_data data;
   struct analog_map map = device->analog_in.map[channel->index];
   struct moberg_status result = serial2002_poll_channel(
     device->port.fd, map.index);
   if (! OK(result)) {
     goto return_result;
   }
-  result = serial2002_read(device->port.fd, 1000, &data);
+  result = serial2002_read(device->port.fd, device->port.timeout, &data);
   if (OK(result)) {
     *value = (data.value * map.delta + map.min);
   }
@@ -157,7 +158,7 @@ static struct moberg_status digital_in_read(
   if (! OK(result)) {
     goto return_result;
   }
-  result = serial2002_read(device->port.fd, 1000, &data);
+  result = serial2002_read(device->port.fd, device->port.timeout, &data);
   if (OK(result)) {
     *value = data.value != 0;
   }
@@ -188,14 +189,14 @@ static struct moberg_status encoder_in_read(
   
   struct moberg_channel_context *channel = &encoder_in->channel_context;
   struct moberg_device_context *device = channel->device;
-  struct serial2002_data data = { 0, 0 };
+  struct serial2002_data data;
   struct digital_map map = device->encoder_in.map[channel->index];
   struct moberg_status result = serial2002_poll_channel(
     device->port.fd, map.index);
   if (! OK(result)) {
     goto return_result;
   }
-  result = serial2002_read(device->port.fd, 1000, &data);
+  result = serial2002_read(device->port.fd, device->port.timeout, &data);
   if (OK(result)) {
     *value = (data.value);
   }
@@ -307,7 +308,7 @@ static struct moberg_status device_open(struct moberg_device_context *device)
       ioctl(fd, TIOCSSERIAL, &settings);
     }
     struct serial2002_config config;
-    result = serial2002_read_config(fd, &config);
+    result = serial2002_read_config(fd, device->port.timeout, &config);
     if (! OK(result)) { goto err_result; }
     remap_analog(&device->analog_in, SERIAL2002_ANALOG_IN,
                   config.channel_in, 31);
@@ -426,6 +427,20 @@ static struct moberg_status parse_config(
       if (! acceptsym(c, tok_INTEGER, &baud)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
       device->port.baud = baud.u.integer.value;
+    } else if (acceptkeyword(c, "timeout")) {
+      token_t timeout;
+      int multiplier = 0;
+      if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
+      if (! acceptsym(c, tok_INTEGER, &timeout)) { goto syntax_err; }
+      if (acceptkeyword(c, "s")) {
+        multiplier = 1000000;
+      } else if (acceptkeyword(c, "ms")) {
+        multiplier = 1000;
+      } else if (acceptkeyword(c, "us")) {
+        multiplier = 1;
+      } 
+      if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
+      device->port.timeout = timeout.u.integer.value * multiplier;
     } else {
       goto syntax_err;
     }
diff --git a/plugins/serial2002/serial2002_lib.c b/plugins/serial2002/serial2002_lib.c
index 295b43e..5fb5354 100644
--- a/plugins/serial2002/serial2002_lib.c
+++ b/plugins/serial2002/serial2002_lib.c
@@ -43,7 +43,7 @@ static struct moberg_status tty_write(int fd, unsigned char *buf, int count)
   return MOBERG_OK;
 }
 
-static struct moberg_status tty_read(int fd, int timeout, unsigned char *value)
+static struct moberg_status tty_read(int fd, long timeout, unsigned char *value)
 {
   struct pollfd pollfd;
 
@@ -83,8 +83,8 @@ struct moberg_status serial2002_poll_channel(int fd, int channel)
   return tty_write(fd, &cmd, 1);
 }
 
-struct moberg_status serial2002_read(int f, int timeout,
-                                            struct serial2002_data *value)
+struct moberg_status serial2002_read(int f, long timeout,
+                                     struct serial2002_data *value)
 {
   int length;
   
@@ -211,6 +211,7 @@ static struct moberg_status update_channel(struct serial2002_channel *channel,
 
 static struct moberg_status do_read_config(
   int fd,
+  long timeout,
   struct serial2002_config *config)
 {
   struct serial2002_data data = { 0, 0 };
@@ -218,7 +219,7 @@ static struct moberg_status do_read_config(
   memset(config, 0, sizeof(*config));
   serial2002_poll_channel(fd, 31);
   while (1) {
-    struct moberg_status result = serial2002_read(fd, 1000, &data);
+    struct moberg_status result = serial2002_read(fd, timeout, &data);
     if (! OK(result)) { return result; }
     unsigned int channel = (data.value & 0x0001f);
     unsigned int kind = (data.value & 0x00e0) >> 5;
@@ -285,9 +286,10 @@ static struct moberg_status check_config(struct serial2002_config *c)
 
 struct moberg_status serial2002_read_config(
   int fd,
+  long timeout,
   struct serial2002_config *config)
 { 
-  struct moberg_status result = do_read_config(fd, config);
+  struct moberg_status result = do_read_config(fd, timeout, config);
   if (OK(result)) {
     result = check_config(config);
   }
@@ -295,399 +297,3 @@ struct moberg_status serial2002_read_config(
 }
 
 
-#if 0
-
-static void x() {
-  typedef struct {
-    short int kind;
-    short int bits;
-    int min;
-    int max;
-  } config_t;
-  config_t *dig_in_config;
-  config_t *dig_out_config;
-  config_t *chan_in_config;
-  config_t *chan_out_config;
-  int i;
-  
-  result = 0;
-  dig_in_config = kcalloc(32, sizeof(config_t), GFP_KERNEL);
-  dig_out_config = kcalloc(32, sizeof(config_t), GFP_KERNEL);
-  chan_in_config = kcalloc(32, sizeof(config_t), GFP_KERNEL);
-  chan_out_config = kcalloc(32, sizeof(config_t), GFP_KERNEL);
-  if (!dig_in_config || !dig_out_config
-      || !chan_in_config || !chan_out_config) {
-    result = -ENOMEM;
-    goto err_alloc_configs;
-  }
-
-  tty_setspeed(devpriv->tty, devpriv->speed);
-  poll_channel(devpriv->tty, 31);	// Start reading configuration
-  while (1) {
-    struct serial2002_data data;
-    
-    data = serial_read(devpriv->tty, 1000);
-    if (data.kind != is_channel || data.index != 31
-        || !(data.value & 0xe0)) {
-      break;
-    } else {
-      int command, channel, kind;
-      config_t *cur_config = 0;
-      
-      channel = data.value & 0x1f;
-      kind = (data.value >> 5) & 0x7;
-      command = (data.value >> 8) & 0x3;
-      switch (kind) {
-        case 1:{
-          cur_config = dig_in_config;
-        }
-          break;
-        case 2:{
-          cur_config = dig_out_config;
-        }
-          break;
-        case 3:{
-          cur_config = chan_in_config;
-        }
-          break;
-        case 4:{
-          cur_config = chan_out_config;
-        }
-          break;
-        case 5:{
-          cur_config = chan_in_config;
-        }
-          break;
-      }
-      
-      if (cur_config) {
-        cur_config[channel].kind = kind;
-        switch (command) {
-          case 0:{
-            cur_config[channel].
-              bits =
-              (data.
-               value >> 10) &
-              0x3f;
-          }
-            break;
-          case 1:{
-            int unit, sign, min;
-            unit = (data.
-                    value >> 10) &
-              0x7;
-            sign = (data.
-                    value >> 13) &
-              0x1;
-            min = (data.
-                   value >> 14) &
-              0xfffff;
-            
-            switch (unit) {
-              case 0:{
-                min = min * 1000000;
-              }
-                break;
-              case 1:{
-                min = min * 1000;
-              }
-                break;
-              case 2:{
-                min = min * 1;
-              }
-                break;
-            }
-            if (sign) {
-              min = -min;
-            }
-            cur_config[channel].
-              min = min;
-          }
-            break;
-          case 2:{
-            int unit, sign, max;
-            unit = (data.
-                    value >> 10) &
-              0x7;
-            sign = (data.
-                    value >> 13) &
-              0x1;
-            max = (data.
-                   value >> 14) &
-              0xfffff;
-            
-            switch (unit) {
-              case 0:{
-                max = max * 1000000;
-              }
-                break;
-              case 1:{
-                max = max * 1000;
-              }
-                break;
-              case 2:{
-                max = max * 1;
-              }
-                break;
-            }
-            if (sign) {
-              max = -max;
-            }
-            cur_config[channel].
-              max = max;
-          }
-            break;
-        }
-      }
-    }
-  }
-  for (i = 0; i <= 4; i++) {
-    // Fill in subdev data
-    config_t *c;
-    unsigned char *mapping = 0;
-    serial2002_range_table_t *range = 0;
-    int kind = 0;
-    
-    switch (i) {
-      case 0:{
-        c = dig_in_config;
-        mapping = devpriv->digital_in_mapping;
-        kind = 1;
-      }
-        break;
-      case 1:{
-        c = dig_out_config;
-        mapping = devpriv->digital_out_mapping;
-        kind = 2;
-      }
-        break;
-      case 2:{
-        c = chan_in_config;
-        mapping = devpriv->analog_in_mapping;
-        range = devpriv->in_range;
-        kind = 3;
-      }
-        break;
-      case 3:{
-        c = chan_out_config;
-        mapping = devpriv->analog_out_mapping;
-        range = devpriv->out_range;
-        kind = 4;
-      }
-        break;
-      case 4:{
-        c = chan_in_config;
-        mapping = devpriv->encoder_in_mapping;
-        range = devpriv->in_range;
-        kind = 5;
-      }
-        break;
-      default:{
-        c = 0;
-      }
-        break;
-    }
-    if (c) {
-      comedi_subdevice *s;
-      const comedi_lrange **range_table_list = NULL;
-      unsigned int *maxdata_list;
-      int j, chan;
-      
-      for (chan = 0, j = 0; j < 32; j++) {
-        if (c[j].kind == kind) {
-          chan++;
-        }
-      }
-      s = &dev->subdevices[i];
-      s->n_chan = chan;
-      s->maxdata = 0;
-      kfree(s->maxdata_list);
-      s->maxdata_list = maxdata_list =
-        kmalloc(sizeof(lsampl_t) * s->n_chan,
-                GFP_KERNEL);
-      if (!s->maxdata_list) {
-        break;	/* error handled below */
-      }
-      kfree(s->range_table_list);
-      s->range_table = 0;
-      s->range_table_list = 0;
-      if (kind == 1 || kind == 2) {
-        s->range_table = &range_digital;
-      } else if (range) {
-        s->range_table_list = range_table_list =
-          kmalloc(sizeof
-                  (serial2002_range_table_t) *
-                  s->n_chan, GFP_KERNEL);
-        if (!s->range_table_list) {
-          break;	/* error handled below */
-        }
-      }
-      for (chan = 0, j = 0; j < 32; j++) {
-        if (c[j].kind == kind) {
-          if (mapping) {
-            mapping[chan] = j;
-          }
-          if (range) {
-            range[j].length = 1;
-            range[j].range.min =
-              c[j].min;
-            range[j].range.max =
-              c[j].max;
-            range_table_list[chan] =
-              (const
-               comedi_lrange *)
-              &range[j];
-          }
-          maxdata_list[chan] =
-            ((long long)1 << c[j].
-             bits) - 1;
-          chan++;
-        }
-      }
-    }
-  }
-  if (i <= 4) {
-    /* Failed to allocate maxdata_list or range_table_list
-     * for a subdevice that needed it. */
-    result = -ENOMEM;
-    for (i = 0; i <= 4; i++) {
-      comedi_subdevice *s = &dev->subdevices[i];
-      
-      kfree(s->maxdata_list);
-      s->maxdata_list = NULL;
-      kfree(s->range_table_list);
-      s->range_table_list = NULL;
-    }
-  }
-err_alloc_configs:
-  kfree(dig_in_config);
-  kfree(dig_out_config);
-  kfree(chan_in_config);
-  kfree(chan_out_config);
-  if (result) {
-    if (devpriv->tty) {
-      filp_close(devpriv->tty, 0);
-      devpriv->tty = NULL;
-    }
-  }
-}
-return result;
-}
-
-static int serial2002_di_rinsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan;
-
-	chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
-	for (n = 0; n < insn->n; n++) {
-		struct serial2002_data read;
-
-		poll_digital(devpriv->tty, chan);
-		while (1) {
-			read = serial_read(devpriv->tty, 1000);
-			if (read.kind != is_digital || read.index == chan) {
-				break;
-			}
-		}
-		data[n] = read.value;
-	}
-	return n;
-}
-
-static int serial2002_do_winsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan;
-
-	chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
-	for (n = 0; n < insn->n; n++) {
-		struct serial2002_data write;
-
-		write.kind = is_digital;
-		write.index = chan;
-		write.value = data[n];
-		serial_write(devpriv->tty, write);
-	}
-	return n;
-}
-
-static int serial2002_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan;
-
-	chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
-	for (n = 0; n < insn->n; n++) {
-		struct serial2002_data read;
-
-		poll_channel(devpriv->tty, chan);
-		while (1) {
-			read = serial_read(devpriv->tty, 1000);
-			if (read.kind != is_channel || read.index == chan) {
-				break;
-			}
-		}
-		data[n] = read.value;
-	}
-	return n;
-}
-
-static int serial2002_ao_winsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan;
-
-	chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
-	for (n = 0; n < insn->n; n++) {
-		struct serial2002_data write;
-
-		write.kind = is_channel;
-		write.index = chan;
-		write.value = data[n];
-		serial_write(devpriv->tty, write);
-		devpriv->ao_readback[chan] = data[n];
-	}
-	return n;
-}
-
-static int serial2002_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan = CR_CHAN(insn->chanspec);
-
-	for (n = 0; n < insn->n; n++) {
-		data[n] = devpriv->ao_readback[chan];
-	}
-
-	return n;
-}
-
-static int serial2002_ei_rinsn(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
-{
-	int n;
-	int chan;
-
-	chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
-	for (n = 0; n < insn->n; n++) {
-		struct serial2002_data read;
-
-		poll_channel(devpriv->tty, chan);
-		while (1) {
-			read = serial_read(devpriv->tty, 1000);
-			if (read.kind != is_channel || read.index == chan) {
-				break;
-			}
-		}
-		data[n] = read.value;
-	}
-	return n;
-}
-
-#endif
diff --git a/plugins/serial2002/serial2002_lib.h b/plugins/serial2002/serial2002_lib.h
index f53133a..dc56e3e 100644
--- a/plugins/serial2002/serial2002_lib.h
+++ b/plugins/serial2002/serial2002_lib.h
@@ -53,12 +53,13 @@ struct moberg_status serial2002_poll_digital(int fd, int channel);
 
 struct moberg_status serial2002_poll_channel(int fd, int channel);
 
-struct moberg_status serial2002_read(int fd, int timeout,
+struct moberg_status serial2002_read(int fd, long timeout,
                                      struct serial2002_data *data);
 
 struct moberg_status serial2002_write(int fd, struct serial2002_data data);
 
 struct moberg_status serial2002_read_config(int fd,
+                                            long timeout,
                                             struct serial2002_config *config);
 
 #endif
diff --git a/test/.config/moberg.d/00-comedi_ttyUSB0_serial.conf b/test/.config/moberg.d/00-comedi_ttyUSB0_serial.conf
new file mode 100644
index 0000000..22ffc4a
--- /dev/null
+++ b/test/.config/moberg.d/00-comedi_ttyUSB0_serial.conf
@@ -0,0 +1,14 @@
+driver(serial2002) {
+    config {
+        /* Parsed by parse_config in libmoberg_serial2002.so */
+        device = "/dev/ttyUSB0" ;
+        baud = 115200 ;
+    }
+    /* Moberg mapping[indices] = {driver specific}[indices]
+      {driver specific} is parsed by parse_map in libmoberg_serial2002.so */
+    map analog_in[0:7] = analog_in[0:7] ;
+    map analog_out[0:7] = analog_out[0:7] ;
+    map digital_in[0:7] = digital_in[0:7] ;
+    map digital_out[0:7] = digital_out[0:7] ;
+    map encoder_in[0:7] = encoder_in[0:7] ;
+}
diff --git a/test/.config/moberg.d/30-comedi_ttyUSB0_serial.conf b/test/.config/moberg.d/30-comedi_ttyUSB0_serial.conf
new file mode 100644
index 0000000..480bc5d
--- /dev/null
+++ b/test/.config/moberg.d/30-comedi_ttyUSB0_serial.conf
@@ -0,0 +1,17 @@
+driver(serial2002) {
+    config {
+        /* Parsed by parse_config in libmoberg_serial2002.so */
+        device = "/dev/ttyUSB0" ;
+        baud = 115200 ;
+        timeout = 1 s ;
+        timeout = 100 ms ;
+        timeout = 10000 us ;
+    }
+    /* Moberg mapping[indices] = {driver specific}[indices]
+      {driver specific} is parsed by parse_map in libmoberg_serial2002.so */
+    map analog_in[30:37] = analog_in[0:7] ;
+    map analog_out[30:37] = analog_out[0:7] ;
+    map digital_in[30:37] = digital_in[0:7] ;
+    map digital_out[30:37] = digital_out[0:7] ;
+    map encoder_in[30:37] = encoder_in[0:7] ;
+}
-- 
GitLab