]> sigrok.org Git - libsigrok.git/blobdiff - hardware/demo/demo.c
Fix 'aquisition' typo in a few places.
[libsigrok.git] / hardware / demo / demo.c
index 154305d21d5c420a0a2085c9fe7cd816dbed32e8..329fd170e79cf62868c6fc97fc82f65cf1fa45f2 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <math.h>
 #ifdef _WIN32
 #include <io.h>
 #include <fcntl.h>
@@ -41,6 +42,9 @@
 /* Size of the analog pattern space per channel. */
 #define ANALOG_BUFSIZE       4096
 
+#define ANALOG_AMPLITUDE 25
+#define ANALOG_SAMPLES_PER_PERIOD 20
+
 /* Logic patterns we can generate. */
 enum {
        /**
@@ -73,6 +77,9 @@ enum {
         * Square wave.
         */
        PATTERN_SQUARE,
+       PATTERN_SINE,
+       PATTERN_TRIANGLE,
+       PATTERN_SAWTOOTH,
 };
 
 static const char *logic_pattern_str[] = {
@@ -85,6 +92,9 @@ static const char *logic_pattern_str[] = {
 
 static const char *analog_pattern_str[] = {
        "square",
+       "sine",
+       "triangle",
+       "sawtooth",
 };
 
 struct analog_gen {
@@ -101,7 +111,8 @@ struct dev_context {
        uint64_t cur_samplerate;
        uint64_t limit_samples;
        uint64_t limit_msec;
-       uint64_t samples_counter;
+       uint64_t logic_counter;
+       uint64_t analog_counter;
        int64_t starttime;
        uint64_t step;
        /* Logic */
@@ -155,30 +166,29 @@ static struct sr_dev_driver *di = &demo_driver_info;
 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
 
 
-static int dev_clear(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
 static int init(struct sr_context *sr_ctx)
 {
        return std_init(sr_ctx, di, LOG_PREFIX);
 }
 
-static void set_analog_pattern(const struct sr_probe_group *probe_group, int pattern)
+static void generate_analog_pattern(const struct sr_probe_group *probe_group, uint64_t sample_rate)
 {
        struct analog_gen *ag;
+       double t, frequency;
        float value;
        unsigned int num_samples, i;
        int last_end;
 
        ag = probe_group->priv;
-       ag->pattern = pattern;
+       num_samples = ANALOG_BUFSIZE / sizeof(float);
+
+       sr_dbg("Generating %s pattern for probe group %s",
+              analog_pattern_str[ag->pattern],
+              probe_group->name);
 
-       switch (pattern) {
+       switch (ag->pattern) {
        case PATTERN_SQUARE:
-               num_samples = ANALOG_BUFSIZE / sizeof(float);
-               value = 5.0;
+               value = ANALOG_AMPLITUDE;
                last_end = 0;
                for (i = 0; i < num_samples; i++) {
                        if (i % 5 == 0)
@@ -189,6 +199,55 @@ static void set_analog_pattern(const struct sr_probe_group *probe_group, int pat
                }
                ag->num_samples = last_end;
                break;
+
+       case PATTERN_SINE:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               /* Make sure the number of samples we put out is an integer
+                * multiple of our period size */
+               /* FIXME we actually need only one period. A ringbuffer would be
+                * usefull here.*/
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = ANALOG_AMPLITUDE *
+                                               sin(2 * M_PI * frequency * t);
+               }
+
+               ag->num_samples = num_samples;
+               break;
+
+       case PATTERN_TRIANGLE:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = (2 * ANALOG_AMPLITUDE / M_PI) *
+                                               asin(sin(2 * M_PI * frequency * t));
+               }
+
+               ag->num_samples = num_samples;
+               break;
+
+       case PATTERN_SAWTOOTH:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = 2 * ANALOG_AMPLITUDE *
+                                               ((t * frequency) - floor(0.5f + t * frequency));
+               }
+
+               ag->num_samples = num_samples;
+               break;
        }
 }
 
@@ -202,7 +261,7 @@ static GSList *scan(GSList *options)
        struct sr_config *src;
        struct analog_gen *ag;
        GSList *devices, *l;
-       int num_logic_probes, num_analog_probes, i;
+       int num_logic_probes, num_analog_probes, pattern, i;
        char probe_name[16];
 
        drvc = di->priv;
@@ -259,9 +318,12 @@ static GSList *scan(GSList *options)
        sdi->probe_groups = g_slist_append(NULL, pg);
 
        /* Analog probes, probe groups and pattern generators. */
+
+       pattern = 0;
        for (i = 0; i < num_analog_probes; i++) {
                sprintf(probe_name, "A%d", i);
-               if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE, probe_name)))
+               if (!(probe = sr_probe_new(i + num_logic_probes,
+                               SR_PROBE_ANALOG, TRUE, probe_name)))
                        return NULL;
                sdi->probes = g_slist_append(sdi->probes, probe);
 
@@ -279,11 +341,14 @@ static GSList *scan(GSList *options)
                ag->packet.mqflags = 0;
                ag->packet.unit = SR_UNIT_VOLT;
                ag->packet.data = ag->pattern_data;
+               ag->pattern = pattern;
                pg->priv = ag;
-               set_analog_pattern(pg, PATTERN_SQUARE);
 
                sdi->probe_groups = g_slist_append(sdi->probe_groups, pg);
                devc->analog_probe_groups = g_slist_append(devc->analog_probe_groups, pg);
+
+               if (++pattern == ARRAY_SIZE(analog_pattern_str))
+                       pattern = 0;
        }
 
        sdi->priv = devc;
@@ -314,7 +379,7 @@ static int dev_close(struct sr_dev_inst *sdi)
 
 static int cleanup(void)
 {
-       return dev_clear();
+       return std_dev_clear(di, NULL);
 }
 
 static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
@@ -370,6 +435,7 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
                const struct sr_probe_group *probe_group)
 {
        struct dev_context *devc;
+       struct analog_gen *ag;
        struct sr_probe *probe;
        int pattern, ret;
        unsigned int i;
@@ -429,9 +495,11 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
                        }
                        if (pattern == -1)
                                return SR_ERR_ARG;
-                       sr_dbg("Setting analog pattern to %s",
+                       sr_dbg("Setting analog pattern for probe group %s to %s",
+                                       probe_group->name,
                                        analog_pattern_str[pattern]);
-                       set_analog_pattern(probe_group, pattern);
+                       ag = probe_group->priv;
+                       ag->pattern = pattern;
                } else
                        return SR_ERR_BUG;
                break;
@@ -552,7 +620,7 @@ static int prepare_data(int fd, int revents, void *cb_data)
        struct sr_probe_group *pg;
        struct analog_gen *ag;
        GSList *l;
-       uint64_t samples_to_send, expected_samplenum, analog_samples, sending_now;
+       uint64_t logic_todo, analog_todo, expected_samplenum, analog_samples, sending_now;
        int64_t time, elapsed;
 
        (void)fd;
@@ -565,20 +633,15 @@ static int prepare_data(int fd, int revents, void *cb_data)
        time = g_get_monotonic_time();
        elapsed = time - devc->starttime;
        expected_samplenum = elapsed * devc->cur_samplerate / 1000000;
-       /* Of those, how many do we still have to send? */
-       samples_to_send = expected_samplenum - devc->samples_counter;
 
-       if (devc->limit_samples) {
-               samples_to_send = MIN(samples_to_send,
-                               devc->limit_samples - devc->samples_counter);
-       }
-
-       while (samples_to_send > 0) {
-               sending_now = 0;
+       /* Of those, how many do we still have to send? */
+       logic_todo = MIN(expected_samplenum, devc->limit_samples) - devc->logic_counter;
+       analog_todo = MIN(expected_samplenum, devc->limit_samples) - devc->analog_counter;
 
+       while (logic_todo || analog_todo) {
                /* Logic */
-               if (devc->num_logic_probes > 0) {
-                       sending_now = MIN(samples_to_send,
+               if (devc->num_logic_probes > 0 && logic_todo > 0) {
+                       sending_now = MIN(logic_todo,
                                        LOGIC_BUFSIZE / devc->logic_unitsize);
                        logic_generator(sdi, sending_now * devc->logic_unitsize);
                        packet.type = SR_DF_LOGIC;
@@ -587,31 +650,38 @@ static int prepare_data(int fd, int revents, void *cb_data)
                        logic.unitsize = devc->logic_unitsize;
                        logic.data = devc->logic_data;
                        sr_session_send(sdi, &packet);
+                       logic_todo -= sending_now;
+                       devc->logic_counter += sending_now;
                }
 
                /* Analog, one probe at a time */
-               if (devc->num_analog_probes > 0) {
+               if (devc->num_analog_probes > 0 && analog_todo > 0) {
                        sending_now = 0;
                        for (l = devc->analog_probe_groups; l; l = l->next) {
                                pg = l->data;
                                ag = pg->priv;
                                packet.type = SR_DF_ANALOG;
                                packet.payload = &ag->packet;
-                               analog_samples = MIN(samples_to_send, ag->num_samples);
+
+                               /* FIXME we should make sure we output a whole
+                                * period of data before we send out again the
+                                * beginning of our buffer. A ring buffer would
+                                * help here as well */
+
+                               analog_samples = MIN(analog_todo, ag->num_samples);
                                /* Whichever probe group gets there first. */
                                sending_now = MAX(sending_now, analog_samples);
                                ag->packet.num_samples = analog_samples;
                                sr_session_send(sdi, &packet);
                        }
+                       analog_todo -= sending_now;
+                       devc->analog_counter += sending_now;
                }
-
-               samples_to_send -= sending_now;
-               devc->samples_counter += sending_now;
        }
 
-       if (devc->limit_samples &&
-               devc->samples_counter >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
+       if (devc->logic_counter >= devc->limit_samples &&
+                       devc->analog_counter >= devc->limit_samples) {
+               sr_dbg("Requested number of samples reached.");
                dev_acquisition_stop(sdi, cb_data);
                return TRUE;
        }
@@ -621,14 +691,16 @@ static int prepare_data(int fd, int revents, void *cb_data)
 
 static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
 {
+       GSList *l;
        struct dev_context *devc;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       /* TODO: don't start without a sample limit set */
        devc = sdi->priv;
-       devc->samples_counter = 0;
+       if (devc->limit_samples == 0)
+               return SR_ERR;
+       devc->logic_counter = devc->analog_counter = 0;
 
        /*
         * Setting two channels connected by a pipe is a remnant from when the
@@ -642,6 +714,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
                return SR_ERR;
        }
 
+       for (l = devc->analog_probe_groups; l; l = l->next) {
+               generate_analog_pattern(l->data, devc->cur_samplerate);
+       }
+
        devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
 
        g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
@@ -672,7 +748,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
        (void)cb_data;
 
        devc = sdi->priv;
-       sr_dbg("Stopping aquisition.");
+       sr_dbg("Stopping acquisition.");
 
        sr_session_source_remove_channel(devc->channel);
        g_io_channel_shutdown(devc->channel, FALSE, NULL);
@@ -694,7 +770,7 @@ SR_PRIV struct sr_dev_driver demo_driver_info = {
        .cleanup = cleanup,
        .scan = scan,
        .dev_list = dev_list,
-       .dev_clear = dev_clear,
+       .dev_clear = NULL,
        .config_get = config_get,
        .config_set = config_set,
        .config_list = config_list,