demo: Get/Set amplitude while data acquisition is running.
This commit is contained in:
parent
94f364ec11
commit
a6e5d2f676
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
last_end = 0;
|
* multiple of our period size */
|
||||||
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
|
/* PATTERN_SQUARE */
|
||||||
* multiple of our period size */
|
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SQUARE]);
|
||||||
/* FIXME we actually need only one period. A ringbuffer would be
|
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||||
* useful here. */
|
value = amplitude;
|
||||||
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
|
last_end = 0;
|
||||||
num_samples--;
|
for (i = 0; i < num_samples; i++) {
|
||||||
|
if (i % 5 == 0)
|
||||||
for (i = 0; i < num_samples; i++) {
|
value = -value;
|
||||||
t = (double) i / (double) sample_rate;
|
if (i % 10 == 0)
|
||||||
ag->pattern_data[i] = ag->amplitude *
|
last_end = i;
|
||||||
sin(2 * G_PI * frequency * t);
|
pattern->data[i] = value + offset;
|
||||||
}
|
|
||||||
|
|
||||||
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->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)
|
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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue