demo: Get/Set amplitude while data acquisition is running.

This commit is contained in:
Frank Stettner 2019-02-21 16:34:17 +01:00 committed by Uwe Hermann
parent 94f364ec11
commit a6e5d2f676
3 changed files with 118 additions and 96 deletions

View File

@ -33,9 +33,6 @@
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK #define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
#define DEFAULT_NUM_ANALOG_CHANNELS 4 #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. */ /* Note: No spaces allowed because of sigrok-cli. */
static const char *logic_pattern_str[] = { 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. */ /* Analog channels, channel groups and pattern generators. */
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal); devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
if (num_analog_channels > 0) { 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; pattern = 0;
/* An "Analog" channel group with all analog channels in it. */ /* An "Analog" channel group with all analog channels in it. */
acg = g_malloc0(sizeof(struct sr_channel_group)); 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->mq_flags = SR_MQFLAG_DC;
ag->unit = SR_UNIT_VOLT; ag->unit = SR_UNIT_VOLT;
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE; ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
ag->offset = DEFAULT_ANALOG_OFFSET;
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2); sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
ag->packet.meaning->channels = cg->channels; ag->packet.meaning->channels = cg->channels;
ag->packet.meaning->mq = ag->mq; 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.meaning->unit = ag->unit;
ag->packet.encoding->digits = DEFAULT_ANALOG_ENCODING_DIGITS; ag->packet.encoding->digits = DEFAULT_ANALOG_ENCODING_DIGITS;
ag->packet.spec->spec_digits = DEFAULT_ANALOG_SPEC_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->pattern = pattern;
ag->avg_val = 0.0f; ag->avg_val = 0.0f;
ag->num_avgs = 0; ag->num_avgs = 0;
@ -472,8 +477,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct sr_channel *ch; struct sr_channel *ch;
int bitpos; int bitpos;
uint8_t mask; uint8_t mask;
GHashTableIter iter;
void *value;
struct sr_trigger *trigger; struct sr_trigger *trigger;
devc = sdi->priv; 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_index,
devc->first_partial_logic_mask); 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, sr_session_source_add(sdi->session, -1, 0, 100,
demo_prepare_data, (struct sr_dev_inst *)sdi); demo_prepare_data, (struct sr_dev_inst *)sdi);

View 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, }, { 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; double t, frequency;
float value; float amplitude, offset;
struct analog_pattern *pattern;
unsigned int num_samples, i; unsigned int num_samples, i;
float value;
int last_end; int last_end;
sr_dbg("Generating %s pattern.", analog_pattern_str[ag->pattern]);
num_samples = ANALOG_BUFSIZE / sizeof(float); 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) { /* FIXME we actually need only one period. A ringbuffer would be
case PATTERN_SQUARE: * useful here. */
value = ag->amplitude; /* 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; last_end = 0;
for (i = 0; i < num_samples; i++) { for (i = 0; i < num_samples; i++) {
if (i % 5 == 0) if (i % 5 == 0)
value = -value; value = -value;
if (i % 10 == 0) if (i % 10 == 0)
last_end = i; last_end = i;
ag->pattern_data[i] = value; pattern->data[i] = value + offset;
} }
ag->num_samples = last_end; pattern->num_samples = last_end;
break; devc->analog_patterns[PATTERN_SQUARE] = pattern;
case PATTERN_SINE:
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
/* Make sure the number of samples we put out is an integer /* Readjusting num_samples for all other patterns */
* 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) while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
num_samples--; 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++) { for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate; t = (double) i / (double) devc->cur_samplerate;
ag->pattern_data[i] = ag->amplitude * pattern->data[i] = sin(2 * G_PI * frequency * t) * amplitude + offset;
sin(2 * G_PI * frequency * t);
} }
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_SINE] = pattern;
ag->num_samples = num_samples; /* PATTERN_TRIANGLE: */
break; sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_TRIANGLE]);
case PATTERN_TRIANGLE: pattern = g_malloc(sizeof(struct analog_pattern));
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++) { for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate; t = (double) i / (double) devc->cur_samplerate;
ag->pattern_data[i] = (2 * ag->amplitude / G_PI) * pattern->data[i] = (2 / G_PI) * asin(sin(2 * G_PI * frequency * t)) *
asin(sin(2 * G_PI * frequency * t)); amplitude + offset;
} }
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_TRIANGLE] = pattern;
ag->num_samples = num_samples; /* PATTERN_SAWTOOTH: */
break; sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SAWTOOTH]);
case PATTERN_SAWTOOTH: pattern = g_malloc(sizeof(struct analog_pattern));
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++) { for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate; t = (double) i / (double) devc->cur_samplerate;
ag->pattern_data[i] = 2 * ag->amplitude * pattern->data[i] = 2 * ((t * frequency) - floor(0.5f + t * frequency)) *
((t * frequency) - floor(0.5f + t * frequency)); amplitude + offset;
}
ag->num_samples = num_samples;
break;
} }
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_SAWTOOTH] = pattern;
} }
static uint64_t encode_number_to_gray(uint64_t nr) 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 sr_datafeed_packet packet;
struct dev_context *devc; struct dev_context *devc;
struct analog_pattern *pattern;
uint64_t sending_now, to_avg; uint64_t sending_now, to_avg;
int ag_pattern_pos; int ag_pattern_pos;
unsigned int i; unsigned int i;
float amplitude, offset, value;
float *data;
if (!ag->ch || !ag->ch->enabled) if (!ag->ch || !ag->ch->enabled)
return; return;
@ -401,6 +402,8 @@ static void send_analog_packet(struct analog_gen *ag,
packet.type = SR_DF_ANALOG; packet.type = SR_DF_ANALOG;
packet.payload = &ag->packet; packet.payload = &ag->packet;
pattern = devc->analog_patterns[ag->pattern];
ag->packet.meaning->channels = g_slist_append(NULL, ag->ch); ag->packet.meaning->channels = g_slist_append(NULL, ag->ch);
ag->packet.meaning->mq = ag->mq; ag->packet.meaning->mq = ag->mq;
ag->packet.meaning->mqflags = ag->mq_flags; 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; ag->packet.meaning->unit = SR_UNIT_UNITLESS;
if (!devc->avg) { if (!devc->avg) {
ag_pattern_pos = analog_pos % ag->num_samples; ag_pattern_pos = analog_pos % pattern->num_samples;
sending_now = MIN(analog_todo, ag->num_samples - ag_pattern_pos); sending_now = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
ag->packet.data = ag->pattern_data + 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; ag->packet.num_samples = sending_now;
sr_session_send(sdi, &packet); sr_session_send(sdi, &packet);
/* Whichever channel group gets there first. */ /* Whichever channel group gets there first. */
*analog_sent = MAX(*analog_sent, sending_now); *analog_sent = MAX(*analog_sent, sending_now);
} else { } else {
ag_pattern_pos = analog_pos % ag->num_samples; ag_pattern_pos = analog_pos % pattern->num_samples;
to_avg = MIN(analog_todo, ag->num_samples - ag_pattern_pos); 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++) { for (i = 0; i < to_avg; i++) {
ag->avg_val = (ag->avg_val + value = *(pattern->data + ag_pattern_pos + i) * amplitude + offset;
*(ag->pattern_data + ag->avg_val = (ag->avg_val + value) / 2;
ag_pattern_pos + i)) / 2;
ag->num_avgs++; ag->num_avgs++;
/* Time to send averaged data? */ /* Time to send averaged data? */
if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples)) 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) { 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. * sending until the very end.
*/ */
*analog_sent = ag->num_avgs; *analog_sent = ag->num_avgs;

View File

@ -38,6 +38,11 @@
#define SAMPLES_PER_FRAME 1000UL #define SAMPLES_PER_FRAME 1000UL
#define DEFAULT_LIMIT_FRAMES 0 #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. */ /* Logic patterns we can generate. */
enum logic_pattern_type { enum logic_pattern_type {
/** /**
@ -92,6 +97,18 @@ enum analog_pattern_type {
PATTERN_SAWTOOTH, 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 { struct dev_context {
uint64_t cur_samplerate; uint64_t cur_samplerate;
uint64_t limit_samples; uint64_t limit_samples;
@ -110,6 +127,7 @@ struct dev_context {
enum logic_pattern_type logic_pattern; enum logic_pattern_type logic_pattern;
uint8_t logic_data[LOGIC_BUFSIZE]; uint8_t logic_data[LOGIC_BUFSIZE];
/* Analog */ /* Analog */
struct analog_pattern *analog_patterns[ARRAY_SIZE(analog_pattern_str)];
int32_t num_analog_channels; int32_t num_analog_channels;
GHashTable *ch_ag; GHashTable *ch_ag;
gboolean avg; /* True if averaging is enabled */ gboolean avg; /* True if averaging is enabled */
@ -124,13 +142,6 @@ struct dev_context {
struct soft_trigger_logic *stl; struct soft_trigger_logic *stl;
}; };
static const char *analog_pattern_str[] = {
"square",
"sine",
"triangle",
"sawtooth",
};
struct analog_gen { struct analog_gen {
struct sr_channel *ch; struct sr_channel *ch;
enum sr_mq mq; enum sr_mq mq;
@ -138,8 +149,7 @@ struct analog_gen {
enum sr_unit unit; enum sr_unit unit;
enum analog_pattern_type pattern; enum analog_pattern_type pattern;
float amplitude; float amplitude;
float pattern_data[ANALOG_BUFSIZE]; float offset;
unsigned int num_samples;
struct sr_datafeed_analog packet; struct sr_datafeed_analog packet;
struct sr_analog_encoding encoding; struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning; struct sr_analog_meaning meaning;
@ -148,7 +158,7 @@ struct analog_gen {
unsigned int num_avgs; /* Number of samples averaged */ 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); SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data);
#endif #endif