From a6e5d2f676d2887978f193be2e6bb451185ba36d Mon Sep 17 00:00:00 2001 From: Frank Stettner Date: Thu, 21 Feb 2019 16:34:17 +0100 Subject: [PATCH] demo: Get/Set amplitude while data acquisition is running. --- src/hardware/demo/api.c | 24 ++---- src/hardware/demo/protocol.c | 160 +++++++++++++++++++---------------- src/hardware/demo/protocol.h | 30 ++++--- 3 files changed, 118 insertions(+), 96 deletions(-) diff --git a/src/hardware/demo/api.c b/src/hardware/demo/api.c index 1f9b9d2c..e5ee21b7 100644 --- a/src/hardware/demo/api.c +++ b/src/hardware/demo/api.c @@ -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); diff --git a/src/hardware/demo/protocol.c b/src/hardware/demo/protocol.c index 8db7cbbf..42348a37 100644 --- a/src/hardware/demo/protocol.c +++ b/src/hardware/demo/protocol.c @@ -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); + frequency = (double) devc->cur_samplerate / ANALOG_SAMPLES_PER_PERIOD; + amplitude = DEFAULT_ANALOG_AMPLITUDE; + offset = DEFAULT_ANALOG_OFFSET; - 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; + /* 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 */ - /* 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; + /* 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; diff --git a/src/hardware/demo/protocol.h b/src/hardware/demo/protocol.h index de0ac7a8..9877f553 100644 --- a/src/hardware/demo/protocol.h +++ b/src/hardware/demo/protocol.h @@ -38,6 +38,11 @@ #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