]> sigrok.org Git - libsigrok.git/commitdiff
demo: Get/Set amplitude while data acquisition is running.
authorFrank Stettner <redacted>
Thu, 21 Feb 2019 15:34:17 +0000 (16:34 +0100)
committerUwe Hermann <redacted>
Fri, 29 Mar 2019 15:15:37 +0000 (16:15 +0100)
src/hardware/demo/api.c
src/hardware/demo/protocol.c
src/hardware/demo/protocol.h

index 1f9b9d2c04892c988a5dbbbd104ec3027ad9d6b4..e5ee21b71debde80b167aa21afeb65e7be2f2497 100644 (file)
@@ -33,9 +33,6 @@
 #define DEFAULT_LOGIC_PATTERN                  PATTERN_SIGROK
 
 #define DEFAULT_NUM_ANALOG_CHANNELS            4
-#define DEFAULT_ANALOG_ENCODING_DIGITS 4
-#define DEFAULT_ANALOG_SPEC_DIGITS             4
-#define DEFAULT_ANALOG_AMPLITUDE               10
 
 /* Note: No spaces allowed because of sigrok-cli. */
 static const char *logic_pattern_str[] = {
@@ -165,6 +162,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
        /* Analog channels, channel groups and pattern generators. */
        devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
        if (num_analog_channels > 0) {
+               /*
+                * Have the waveform for analog patterns pre-generated. It's
+                * supposed to be periodic, so the generator just needs to
+                * access the prepared sample data (DDS style).
+                */
+               demo_generate_analog_pattern(devc);
+
                pattern = 0;
                /* An "Analog" channel group with all analog channels in it. */
                acg = g_malloc0(sizeof(struct sr_channel_group));
@@ -190,6 +194,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                        ag->mq_flags = SR_MQFLAG_DC;
                        ag->unit = SR_UNIT_VOLT;
                        ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
+                       ag->offset = DEFAULT_ANALOG_OFFSET;
                        sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
                        ag->packet.meaning->channels = cg->channels;
                        ag->packet.meaning->mq = ag->mq;
@@ -197,7 +202,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                        ag->packet.meaning->unit = ag->unit;
                        ag->packet.encoding->digits = DEFAULT_ANALOG_ENCODING_DIGITS;
                        ag->packet.spec->spec_digits = DEFAULT_ANALOG_SPEC_DIGITS;
-                       ag->packet.data = ag->pattern_data;
+                       ag->packet.data = devc->analog_patterns[pattern];
                        ag->pattern = pattern;
                        ag->avg_val = 0.0f;
                        ag->num_avgs = 0;
@@ -472,8 +477,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
        struct sr_channel *ch;
        int bitpos;
        uint8_t mask;
-       GHashTableIter iter;
-       void *value;
        struct sr_trigger *trigger;
 
        devc = sdi->priv;
@@ -539,15 +542,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
                devc->first_partial_logic_index,
                devc->first_partial_logic_mask);
 
-       /*
-        * Have the waveform for analog patterns pre-generated. It's
-        * supposed to be periodic, so the generator just needs to
-        * access the prepared sample data (DDS style).
-        */
-       g_hash_table_iter_init(&iter, devc->ch_ag);
-       while (g_hash_table_iter_next(&iter, NULL, &value))
-               demo_generate_analog_pattern(value, devc->cur_samplerate);
-
        sr_session_source_add(sdi->session, -1, 0, 100,
                        demo_prepare_data, (struct sr_dev_inst *)sdi);
 
index 8db7cbbfacaf3e85776a1bd0edaeee27e1989867..42348a374f224d234a1bf4d6612bae45a53b43f6 100644 (file)
@@ -173,77 +173,75 @@ static const uint8_t pattern_squid[128][128 / 8] = {
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
 };
 
-SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate)
+SR_PRIV void demo_generate_analog_pattern(struct dev_context *devc)
 {
        double t, frequency;
-       float value;
+       float amplitude, offset;
+       struct analog_pattern *pattern;
        unsigned int num_samples, i;
+       float value;
        int last_end;
 
-       sr_dbg("Generating %s pattern.", analog_pattern_str[ag->pattern]);
-
        num_samples = ANALOG_BUFSIZE / sizeof(float);
-
-       switch (ag->pattern) {
-       case PATTERN_SQUARE:
-               value = ag->amplitude;
-               last_end = 0;
-               for (i = 0; i < num_samples; i++) {
-                       if (i % 5 == 0)
-                               value = -value;
-                       if (i % 10 == 0)
-                               last_end = i;
-                       ag->pattern_data[i] = value;
-               }
-               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
-                * useful 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] = ag->amplitude *
-                                               sin(2 * G_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 * ag->amplitude / G_PI) *
-                                               asin(sin(2 * G_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 * ag->amplitude *
-                                               ((t * frequency) - floor(0.5f + t * frequency));
-               }
-
-               ag->num_samples = num_samples;
-               break;
+       frequency = (double) devc->cur_samplerate / ANALOG_SAMPLES_PER_PERIOD;
+       amplitude = DEFAULT_ANALOG_AMPLITUDE;
+       offset = DEFAULT_ANALOG_OFFSET;
+
+       /* FIXME we actually need only one period. A ringbuffer would be
+        * useful here. */
+       /* Make sure the number of samples we put out is an integer
+        * multiple of our period size */
+
+       /* PATTERN_SQUARE */
+       sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SQUARE]);
+       pattern = g_malloc(sizeof(struct analog_pattern));
+       value = amplitude;
+       last_end = 0;
+       for (i = 0; i < num_samples; i++) {
+               if (i % 5 == 0)
+                       value = -value;
+               if (i % 10 == 0)
+                       last_end = i;
+               pattern->data[i] = value + offset;
        }
+       pattern->num_samples = last_end;
+       devc->analog_patterns[PATTERN_SQUARE] = pattern;
+
+       /*  Readjusting num_samples for all other patterns */
+       while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+               num_samples--;
+
+       /* PATTERN_SINE: */
+       sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SINE]);
+       pattern = g_malloc(sizeof(struct analog_pattern));
+       for (i = 0; i < num_samples; i++) {
+               t = (double) i / (double) devc->cur_samplerate;
+               pattern->data[i] = sin(2 * G_PI * frequency * t) * amplitude + offset;
+       }
+       pattern->num_samples = last_end;
+       devc->analog_patterns[PATTERN_SINE] = pattern;
+
+       /* PATTERN_TRIANGLE: */
+       sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_TRIANGLE]);
+       pattern = g_malloc(sizeof(struct analog_pattern));
+       for (i = 0; i < num_samples; i++) {
+               t = (double) i / (double) devc->cur_samplerate;
+               pattern->data[i] = (2 / G_PI) * asin(sin(2 * G_PI * frequency * t)) *
+                       amplitude + offset;
+       }
+       pattern->num_samples = last_end;
+       devc->analog_patterns[PATTERN_TRIANGLE] = pattern;
+
+       /* PATTERN_SAWTOOTH: */
+       sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SAWTOOTH]);
+       pattern = g_malloc(sizeof(struct analog_pattern));
+       for (i = 0; i < num_samples; i++) {
+               t = (double) i / (double) devc->cur_samplerate;
+               pattern->data[i] = 2 * ((t * frequency) - floor(0.5f + t * frequency)) *
+                       amplitude + offset;
+       }
+       pattern->num_samples = last_end;
+       devc->analog_patterns[PATTERN_SAWTOOTH] = pattern;
 }
 
 static uint64_t encode_number_to_gray(uint64_t nr)
@@ -390,9 +388,12 @@ static void send_analog_packet(struct analog_gen *ag,
 {
        struct sr_datafeed_packet packet;
        struct dev_context *devc;
+       struct analog_pattern *pattern;
        uint64_t sending_now, to_avg;
        int ag_pattern_pos;
        unsigned int i;
+       float amplitude, offset, value;
+       float *data;
 
        if (!ag->ch || !ag->ch->enabled)
                return;
@@ -401,6 +402,8 @@ static void send_analog_packet(struct analog_gen *ag,
        packet.type = SR_DF_ANALOG;
        packet.payload = &ag->packet;
 
+       pattern = devc->analog_patterns[ag->pattern];
+
        ag->packet.meaning->channels = g_slist_append(NULL, ag->ch);
        ag->packet.meaning->mq = ag->mq;
        ag->packet.meaning->mqflags = ag->mq_flags;
@@ -476,22 +479,36 @@ static void send_analog_packet(struct analog_gen *ag,
                ag->packet.meaning->unit = SR_UNIT_UNITLESS;
 
        if (!devc->avg) {
-               ag_pattern_pos = analog_pos % ag->num_samples;
-               sending_now = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
-               ag->packet.data = ag->pattern_data + ag_pattern_pos;
+               ag_pattern_pos = analog_pos % pattern->num_samples;
+               sending_now = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
+               if (ag->amplitude != DEFAULT_ANALOG_AMPLITUDE ||
+                       ag->offset != DEFAULT_ANALOG_OFFSET) {
+
+                       /* Amplitude or offset changed, modify each sample */
+                       amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
+                       offset = ag->offset - DEFAULT_ANALOG_OFFSET;
+                       data = ag->packet.data;
+                       for (i = 0; i < sending_now; i++) {
+                               data[i] = pattern->data[ag_pattern_pos + i] * amplitude + offset;
+                       }
+               } else {
+                       /* Amplitude and offset not changed, use the fast way */
+                       ag->packet.data = pattern->data + ag_pattern_pos;
+               }
                ag->packet.num_samples = sending_now;
                sr_session_send(sdi, &packet);
 
                /* Whichever channel group gets there first. */
                *analog_sent = MAX(*analog_sent, sending_now);
        } else {
-               ag_pattern_pos = analog_pos % ag->num_samples;
-               to_avg = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
+               ag_pattern_pos = analog_pos % pattern->num_samples;
+               to_avg = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
+               amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
+               offset = ag->offset - DEFAULT_ANALOG_OFFSET;
 
                for (i = 0; i < to_avg; i++) {
-                       ag->avg_val = (ag->avg_val +
-                                       *(ag->pattern_data +
-                                         ag_pattern_pos + i)) / 2;
+                       value = *(pattern->data + ag_pattern_pos + i) * amplitude + offset;
+                       ag->avg_val = (ag->avg_val + value) / 2;
                        ag->num_avgs++;
                        /* Time to send averaged data? */
                        if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples))
@@ -499,7 +516,8 @@ static void send_analog_packet(struct analog_gen *ag,
                }
 
                if (devc->avg_samples == 0) {
-                       /* We're averaging all the samples, so wait with
+                       /*
+                        * We're averaging all the samples, so wait with
                         * sending until the very end.
                         */
                        *analog_sent = ag->num_avgs;
index de0ac7a86078d125f1925c801638249bdff37a7c..9877f55367b2a84f16374bc52a64deba5c8cfee2 100644 (file)
 #define SAMPLES_PER_FRAME              1000UL
 #define DEFAULT_LIMIT_FRAMES           0
 
+#define DEFAULT_ANALOG_ENCODING_DIGITS 4
+#define DEFAULT_ANALOG_SPEC_DIGITS             4
+#define DEFAULT_ANALOG_AMPLITUDE               10
+#define DEFAULT_ANALOG_OFFSET                  0.
+
 /* Logic patterns we can generate. */
 enum logic_pattern_type {
        /**
@@ -92,6 +97,18 @@ enum analog_pattern_type {
        PATTERN_SAWTOOTH,
 };
 
+static const char *analog_pattern_str[] = {
+       "square",
+       "sine",
+       "triangle",
+       "sawtooth",
+};
+
+struct analog_pattern {
+       float data[ANALOG_BUFSIZE];
+       unsigned int num_samples;
+};
+
 struct dev_context {
        uint64_t cur_samplerate;
        uint64_t limit_samples;
@@ -110,6 +127,7 @@ struct dev_context {
        enum logic_pattern_type logic_pattern;
        uint8_t logic_data[LOGIC_BUFSIZE];
        /* Analog */
+       struct analog_pattern *analog_patterns[ARRAY_SIZE(analog_pattern_str)];
        int32_t num_analog_channels;
        GHashTable *ch_ag;
        gboolean avg; /* True if averaging is enabled */
@@ -124,13 +142,6 @@ struct dev_context {
        struct soft_trigger_logic *stl;
 };
 
-static const char *analog_pattern_str[] = {
-       "square",
-       "sine",
-       "triangle",
-       "sawtooth",
-};
-
 struct analog_gen {
        struct sr_channel *ch;
        enum sr_mq mq;
@@ -138,8 +149,7 @@ struct analog_gen {
        enum sr_unit unit;
        enum analog_pattern_type pattern;
        float amplitude;
-       float pattern_data[ANALOG_BUFSIZE];
-       unsigned int num_samples;
+       float offset;
        struct sr_datafeed_analog packet;
        struct sr_analog_encoding encoding;
        struct sr_analog_meaning meaning;
@@ -148,7 +158,7 @@ struct analog_gen {
        unsigned int num_avgs; /* Number of samples averaged */
 };
 
-SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate);
+SR_PRIV void demo_generate_analog_pattern(struct dev_context *devc);
 SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data);
 
 #endif