Module: xenomai-abe
Branch: analogy
Commit: f32e5bf61dbe956845d0d21c2cca802ea41892de
URL:    
http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=f32e5bf61dbe956845d0d21c2cca802ea41892de

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Thu Jan  6 00:37:11 2011 +0100

analogy: 1st rework of fake driver

The goal is to remove loop testing driver; fake integrates now three
subdevices to reproduce the loop behaviour. The implementation is
cleaner and that will help validate the waveform tools.

---

 ksrc/drivers/analogy/testing/fake.c |  331 +++++++++++++++++++++++++++--------
 1 files changed, 260 insertions(+), 71 deletions(-)

diff --git a/ksrc/drivers/analogy/testing/fake.c 
b/ksrc/drivers/analogy/testing/fake.c
index c8e8682..803ff00 100644
--- a/ksrc/drivers/analogy/testing/fake.c
+++ b/ksrc/drivers/analogy/testing/fake.c
@@ -1,24 +1,34 @@
 #include <linux/module.h>
 #include <analogy/analogy_driver.h>
 
-#define AI_TASK_PERIOD 1000000
+#define TASK_PERIOD 1000000
 
 #define AI_SUBD 0
 #define DIO_SUBD 1
+#define AO_SUBD 2
+#define AI2_SUBD 3
+
+#define TRANSFER_SIZE 0x1000
 
 /* --- Driver related structures --- */
 
 struct fake_priv {
-       /* Configuration parameters */
+       /* Attach configuration parameters 
+          (they should be relocated in ai_priv) */
        unsigned long amplitude_div;
        unsigned long quanta_cnt;
-};
-
-struct ai_priv {
 
        /* Task descriptor */
-       a4l_task_t timer_task;
+       a4l_task_t task;
 
+       /* Statuses of the asynchronous subdevices */
+       int ai_running;
+       int ao_running;
+       int ai2_running;
+};
+
+struct ai_priv {
+  
        /* Specific timing fields */
        unsigned long scan_period_ns;
        unsigned long convert_period_ns;
@@ -29,8 +39,11 @@ struct ai_priv {
        /* Misc fields */
        unsigned long amplitude_div;
        unsigned long quanta_cnt;
-       int timer_running;
+};
 
+struct ao_ai2_priv {
+       uint8_t buffer[TRANSFER_SIZE];
+       int count;
 };
 
 struct dio_priv {
@@ -40,8 +53,9 @@ struct dio_priv {
 
 /* --- Channels / ranges part --- */
 
-/* Channels descriptor */
-static a4l_chdesc_t ai_chandesc = {
+/* Channels descriptors */
+
+static a4l_chdesc_t analog_chandesc = {
        .mode = A4L_CHAN_GLOBAL_CHANDESC,
        .length = 8,
        .chans = {
@@ -58,7 +72,7 @@ static a4l_chdesc_t dio_chandesc = {
 };
 
 /* Ranges tab */
-static a4l_rngtab_t ai_rngtab = {
+static a4l_rngtab_t analog_rngtab = {
        .length = 2,
        .rngs = {
                RANGE_V(-5,5),
@@ -66,10 +80,11 @@ static a4l_rngtab_t ai_rngtab = {
        },
 };
 /* Ranges descriptor */
-static a4l_rngdesc_t ai_rngdesc = RNG_GLOBAL(ai_rngtab);
+static a4l_rngdesc_t analog_rngdesc = RNG_GLOBAL(analog_rngtab);
+
+/* Command options masks */
 
-/* Command options mask */
-static a4l_cmd_t test_cmd_mask = {
+static a4l_cmd_t ai_cmd_mask = {
        .idx_subd = 0,
        .start_src = TRIG_NOW,
        .scan_begin_src = TRIG_TIMER,
@@ -78,9 +93,20 @@ static a4l_cmd_t test_cmd_mask = {
        .stop_src = TRIG_COUNT|TRIG_NONE,
 };
 
+static a4l_cmd_t ao_cmd_mask = {
+       .idx_subd = 0,
+       .start_src = TRIG_NOW | TRIG_INT,
+       .scan_begin_src = TRIG_TIMER,
+       .convert_src = TRIG_NOW | TRIG_TIMER,
+       .scan_end_src = TRIG_COUNT,
+       .stop_src = TRIG_COUNT| TRIG_NONE,
+};
+
 /* --- Analog input simulation --- */
 
-static uint16_t ai_value_output(struct ai_priv *priv)
+/* --- Values generation for 1st AI --- */
+
+static inline uint16_t ai_value_output(struct ai_priv *priv)
 {
        static uint16_t output_tab[8] = {
                0x0001, 0x2000, 0x4000, 0x6000,
@@ -104,76 +130,137 @@ static uint16_t ai_value_output(struct ai_priv *priv)
        return output_tab[idx] / priv->amplitude_div;
 }
 
-/* --- Task part --- */
-
-/* Timer task routine */
-static void ai_task_proc(void *arg)
+int ai_push_values(a4l_subd_t *subd)
 {
-       a4l_subd_t *subd = (a4l_subd_t *)arg;
        struct ai_priv *priv = (struct ai_priv *)subd->priv;
-       a4l_cmd_t *cmd = NULL;
-       uint64_t now_ns, elapsed_ns=0;
+       a4l_cmd_t *cmd = a4l_get_cmd(subd);
+       uint64_t now_ns, elapsed_ns = 0;
+       int i = 0;
+
+       if (!cmd)
+               return -EPIPE;
+       
+       now_ns = a4l_get_time();
+       elapsed_ns += now_ns - priv->last_ns + priv->reminder_ns;
+       priv->last_ns = now_ns;
+
+       while(elapsed_ns >= priv->scan_period_ns) {
+               int j;
+                               
+               for(j = 0; j < cmd->nb_chan; j++) {
+                       uint16_t value = ai_value_output(priv);
+                       a4l_buf_put(subd, &value, sizeof(uint16_t));
+               }
+                               
+               elapsed_ns -= priv->scan_period_ns;
+               i++;
+       }                      
 
-       while(1) {
-               int running;
+       priv->current_ns += i * priv->scan_period_ns;
+       priv->reminder_ns = elapsed_ns;
+
+       if (i != 0)
+               a4l_buf_evt(subd, 0);
+       
+       return 0;
+}
+
+/* --- Data retrieval for AO --- */
+
+int ao_pull_values(a4l_subd_t *subd)
+{
+       struct ao_ai2_priv *priv = (struct ao_ai2_priv *)subd->priv;
+       int err;
+
+       /* Let's have a look at how many samples are available */
+       priv->count = a4l_buf_count(subd) < TRANSFER_SIZE ? 
+               a4l_buf_count(subd) : TRANSFER_SIZE;
+
+       err = a4l_buf_get(subd, priv->buffer, priv->count);
+       if (err < 0) {
+               priv->count = 0;
+               a4l_err(subd->dev, 
+                       "ao_get_values: a4l_buf_get failed (err=%d)\n", err);
+       }
 
-               RTDM_EXECUTE_ATOMICALLY(running = priv->timer_running);
+       return err;
+}
 
-               if(running)
-               {
-                       int i = 0;
+/* --- Data redirection for 2nd AI (from AO) --- */
 
-                       cmd = a4l_get_cmd(subd);
+int ai2_push_values(a4l_subd_t *subd)
+{
+       struct ao_ai2_priv *priv = *((struct ao_ai2_priv **)subd->priv);
+       int err = 0;
+
+       if (priv->count) {
+               err = a4l_buf_put(subd, priv->buffer, priv->count);
+               a4l_err(subd->dev, 
+                       "ao_redirect_values: "
+                       "a4l_buf_get failed (err=%d)\n", err);
+       }
 
-                       now_ns = a4l_get_time();
-                       elapsed_ns += now_ns - priv->last_ns + 
priv->reminder_ns;
-                       priv->last_ns = now_ns;
+       return err;
+}
 
-                       while(elapsed_ns >= priv->scan_period_ns) {
-                               int j;
+/* --- Global task part --- */
 
-                               for(j = 0; j < cmd->nb_chan; j++) {
-                                       uint16_t value = ai_value_output(priv);
-                                       a4l_buf_put(subd, &value, 
sizeof(uint16_t));
-                               }
+/* One task is enough for all the asynchronous subdevices, it is just
+   a fake driver after all */
 
-                               elapsed_ns -= priv->scan_period_ns;
-                               i++;
+static void task_proc(void *arg)
+{
+       a4l_dev_t *dev = (a4l_dev_t *)arg;      
+       a4l_subd_t *ai_subd = (a4l_subd_t *)a4l_get_subd(dev, AI_SUBD);
+       a4l_subd_t *ao_subd = (a4l_subd_t *)a4l_get_subd(dev, AO_SUBD);
+       a4l_subd_t *ai2_subd = (a4l_subd_t *)a4l_get_subd(dev, AI2_SUBD);
 
-                       }
+       struct fake_priv *priv = (struct fake_priv *)dev->priv;
 
-                       priv->current_ns += i * priv->scan_period_ns;
-                       priv->reminder_ns = elapsed_ns;
+       while (1) {
+
+               int running;
+               
+               RTDM_EXECUTE_ATOMICALLY(running = priv->ai_running);
+               if (running && ai_push_values(ai_subd) < 0)
+                       break;
+
+               RTDM_EXECUTE_ATOMICALLY(running = priv->ao_running);
+               if (running && ao_pull_values(ao_subd) < 0)
+                       break;
 
-                       if (i != 0)
-                               a4l_buf_evt(subd, 0);
-               }
 
-               a4l_task_sleep(AI_TASK_PERIOD);
+               RTDM_EXECUTE_ATOMICALLY(running = priv->ai2_running);
+               if (running && ai2_push_values(ai2_subd) < 0)
+                       break;
+
+               a4l_task_sleep(TASK_PERIOD);
        }
 }
 
+
 /* --- Asynchronous AI functions --- */
 
 static int ai_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd)
 {
-       struct ai_priv *priv = (struct ai_priv *)subd->priv;
-
-       priv->scan_period_ns = cmd->scan_begin_arg;
-       priv->convert_period_ns = (cmd->convert_src==TRIG_TIMER)?
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
+       struct ai_priv *ai_priv = (struct ai_priv *)subd->priv;
+  
+       ai_priv->scan_period_ns = cmd->scan_begin_arg;
+       ai_priv->convert_period_ns = (cmd->convert_src==TRIG_TIMER)?
                cmd->convert_arg:0;
 
        a4l_dbg(1, drv_dbg, subd->dev,
                "ai_cmd: scan_period=%luns convert_period=%luns\n",
-               priv->scan_period_ns, priv->convert_period_ns);
-
-       priv->last_ns = a4l_get_time();
+               ai_priv->scan_period_ns, ai_priv->convert_period_ns);
 
-       priv->current_ns = ((unsigned long)priv->last_ns);
-       priv->reminder_ns = 0;
+       ai_priv->last_ns = a4l_get_time();
 
-       RTDM_EXECUTE_ATOMICALLY(priv->timer_running = 1);
+       ai_priv->current_ns = ((unsigned long)ai_priv->last_ns);
+       ai_priv->reminder_ns = 0;
 
+       RTDM_EXECUTE_ATOMICALLY(priv->ai_running = 1);
+ 
        return 0;
 
 }
@@ -195,9 +282,9 @@ static int ai_cmdtest(a4l_subd_t *subd, a4l_cmd_t *cmd)
 
 static int ai_cancel(a4l_subd_t *subd)
 {
-       struct ai_priv *priv = (struct ai_priv *)subd->priv;
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
 
-       RTDM_EXECUTE_ATOMICALLY(priv->timer_running = 0);
+       RTDM_EXECUTE_ATOMICALLY(priv->ai_running = 0);
 
        return 0;
 }
@@ -210,6 +297,54 @@ static void ai_munge(a4l_subd_t *subd, void *buf, unsigned 
long size)
                ((uint16_t *)buf)[i] += 1;
 }
 
+/* --- Asynchronous A0 functions --- */
+
+int ao_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd)
+{
+       a4l_info(subd->dev, "ao_cmd: (subd=%d)\n", subd->idx);  
+       return 0;
+}
+
+int ao_trigger(a4l_subd_t *subd, lsampl_t trignum)
+{
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
+
+       a4l_info(subd->dev, "ao_trigger: (subd=%d)\n", subd->idx);  
+       RTDM_EXECUTE_ATOMICALLY(priv->ao_running = 1);
+       return 0;
+}
+
+int ao_cancel(a4l_subd_t *subd)
+{
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
+
+       a4l_info(subd->dev, "ao_cancel: (subd=%d)\n", subd->idx);
+       RTDM_EXECUTE_ATOMICALLY(priv->ao_running = 0);
+       return 0;
+}
+
+/* --- Asynchronous 2nd AI functions --- */
+
+int ai2_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd)
+{
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
+
+       a4l_info(subd->dev, "ao_cmd: (subd=%d)\n", subd->idx);  
+       RTDM_EXECUTE_ATOMICALLY(priv->ai2_running = 1);
+       return 0;
+}
+
+int ai2_cancel(a4l_subd_t *subd)
+{
+       struct fake_priv *priv = (struct fake_priv *)subd->dev->priv;
+
+       a4l_info(subd->dev, "ao_cancel: (subd=%d)\n", subd->idx);
+       RTDM_EXECUTE_ATOMICALLY(priv->ai2_running = 0);
+       return 0;
+}
+
+
+
 /* --- Synchronous AI functions --- */
 
 static int ai_insn_read(a4l_subd_t *subd, a4l_kinsn_t *insn)
@@ -252,13 +387,13 @@ void setup_ai_subd(a4l_subd_t *subd)
        subd->flags |= A4L_SUBD_AI;
        subd->flags |= A4L_SUBD_CMD;
        subd->flags |= A4L_SUBD_MMAP;
-       subd->rng_desc = &ai_rngdesc;
-       subd->chan_desc = &ai_chandesc;
+       subd->rng_desc = &analog_rngdesc;
+       subd->chan_desc = &analog_chandesc;
        subd->do_cmd = ai_cmd;
        subd->do_cmdtest = ai_cmdtest;
        subd->cancel = ai_cancel;
        subd->munge = ai_munge;
-       subd->cmd_mask = &test_cmd_mask;
+       subd->cmd_mask = &ai_cmd_mask;
        subd->insn_read = ai_insn_read;
 }
 
@@ -271,6 +406,32 @@ void setup_dio_subd(a4l_subd_t *subd)
        subd->insn_bits = dio_insn_bits;
 }
 
+void setup_ao_subd(a4l_subd_t *subd)
+{
+       /* Fill the subdevice structure */
+       subd->flags |= A4L_SUBD_AO;
+       subd->flags |= A4L_SUBD_CMD;
+       subd->flags |= A4L_SUBD_MMAP;
+       subd->rng_desc = &analog_rngdesc;
+       subd->chan_desc = &analog_chandesc;
+       subd->do_cmd = ao_cmd;
+       subd->cancel = ao_cancel;
+       subd->cmd_mask = &ao_cmd_mask;
+}
+
+void setup_ai2_subd(a4l_subd_t *subd)
+{
+       /* Fill the subdevice structure */
+       subd->flags |= A4L_SUBD_AI;
+       subd->flags |= A4L_SUBD_CMD;
+       subd->flags |= A4L_SUBD_MMAP;
+       subd->rng_desc = &analog_rngdesc;
+       subd->chan_desc = &analog_chandesc;
+       subd->do_cmd = ai2_cmd;
+       subd->cancel = ai2_cancel;
+       subd->cmd_mask = &ai_cmd_mask;
+}
+
 /* --- Attach / detach functions ---  */
 
 int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
@@ -278,7 +439,8 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
        int ret = 0;
        a4l_subd_t *subd;
        struct fake_priv *priv = (struct fake_priv *)dev->priv;
-       struct ai_priv * ai_priv;
+       struct ai_priv *ai_priv;
+       struct ao_ai2_priv *shared_priv;
 
        a4l_dbg(1, drv_dbg, dev, "starting attach procedure...\n");
 
@@ -305,15 +467,9 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
                return -ENOMEM;
 
        ai_priv = (struct ai_priv*)subd->priv;
-       ai_priv->timer_running = 0;
        ai_priv->amplitude_div = priv->amplitude_div;
        ai_priv->quanta_cnt = priv->quanta_cnt;
 
-       ret = a4l_task_init(&ai_priv->timer_task,
-                           "Fake AI task",
-                           ai_task_proc,
-                           subd, A4L_TASK_HIGHEST_PRIORITY);
-
        ret = a4l_add_subd(dev, subd);
        if(ret != AI_SUBD)
                return (ret < 0) ? ret : -EINVAL;
@@ -331,6 +487,40 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
 
        a4l_dbg(1, drv_dbg, dev, "DIO subdevice registered\n");
 
+
+       /* Add the AO subdevice to the device */
+       subd = a4l_alloc_subd(sizeof(struct ao_ai2_priv), setup_ao_subd);
+       if(subd == NULL)
+               return -ENOMEM;
+
+       memset(subd->priv, 0, sizeof(struct ao_ai2_priv));
+       shared_priv = (struct ao_ai2_priv *)subd->priv;
+
+       ret = a4l_add_subd(dev, subd);
+       if(ret != AO_SUBD)
+               return (ret < 0) ? ret : -EINVAL;
+
+       a4l_dbg(1, drv_dbg, dev, "AO subdevice registered\n");
+
+       /* Add the 2nd AI subdevice to the device */
+       subd = a4l_alloc_subd(sizeof(struct ao_ai2_priv *), setup_ai2_subd);
+       if(subd == NULL)
+               return -ENOMEM;
+
+       memcpy(subd->priv, &shared_priv, sizeof(struct ao_ai2_priv *));
+       ret = a4l_add_subd(dev, subd);
+       if(ret != AI2_SUBD)
+               return (ret < 0) ? ret : -EINVAL;
+
+       a4l_dbg(1, drv_dbg, dev, "AI2 subdevice registered\n");
+
+       ret = a4l_task_init(&priv->task, 
+                           "Fake AI task", 
+                           task_proc, 
+                           dev, A4L_TASK_HIGHEST_PRIORITY);
+
+       a4l_dbg(1, drv_dbg, dev, "AI2 subdevice registered\n");
+
        a4l_dbg(1, drv_dbg, dev, "attach procedure complete\n");
 
        return 0;
@@ -338,10 +528,9 @@ int test_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
 
 int test_detach(a4l_dev_t *dev)
 {
-       a4l_subd_t *subd = a4l_get_subd(dev, AI_SUBD);
-       struct ai_priv *priv = (struct ai_priv *)subd->priv;
+       struct fake_priv *priv = (struct fake_priv *)dev->priv;
 
-       a4l_task_destroy(&priv->timer_task);
+       a4l_task_destroy(&priv->task);
 
        a4l_dbg(1, drv_dbg, dev, "detach procedure complete\n");
 


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to