demo: Implement sine wave pattern.

This adds sine wave generation capabilities for the analog channels in the demo
driver. The frequency of the sine wave depends on the configured sample rate of
the demo device. The frequency of the sine wave is always 20 times smaller than
the sample rate, in other words we always have 20 samples per period.
This commit is contained in:
poljar (Damir Jelić) 2014-01-14 23:03:08 +01:00 committed by Bert Vermeulen
parent e196cb6193
commit 4374219bc8
1 changed files with 50 additions and 7 deletions

View File

@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <math.h>
#ifdef _WIN32 #ifdef _WIN32
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
@ -41,6 +42,9 @@
/* Size of the analog pattern space per channel. */ /* Size of the analog pattern space per channel. */
#define ANALOG_BUFSIZE 4096 #define ANALOG_BUFSIZE 4096
#define ANALOG_AMPLITUDE 25
#define ANALOG_SAMPLES_PER_PERIOD 20
/* Logic patterns we can generate. */ /* Logic patterns we can generate. */
enum { enum {
/** /**
@ -73,6 +77,7 @@ enum {
* Square wave. * Square wave.
*/ */
PATTERN_SQUARE, PATTERN_SQUARE,
PATTERN_SINE,
}; };
static const char *logic_pattern_str[] = { static const char *logic_pattern_str[] = {
@ -85,6 +90,7 @@ static const char *logic_pattern_str[] = {
static const char *analog_pattern_str[] = { static const char *analog_pattern_str[] = {
"square", "square",
"sine",
}; };
struct analog_gen { struct analog_gen {
@ -165,19 +171,23 @@ static int init(struct sr_context *sr_ctx)
return std_init(sr_ctx, di, LOG_PREFIX); 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; struct analog_gen *ag;
double t, frequency;
float value; float value;
unsigned int num_samples, i; unsigned int num_samples, i;
int last_end; int last_end;
ag = probe_group->priv; ag = probe_group->priv;
ag->pattern = pattern; num_samples = ANALOG_BUFSIZE / sizeof(float);
switch (pattern) { sr_dbg("Generating %s pattern for probe group %s",
analog_pattern_str[ag->pattern],
probe_group->name);
switch (ag->pattern) {
case PATTERN_SQUARE: case PATTERN_SQUARE:
num_samples = ANALOG_BUFSIZE / sizeof(float);
value = 5.0; value = 5.0;
last_end = 0; last_end = 0;
for (i = 0; i < num_samples; i++) { for (i = 0; i < num_samples; i++) {
@ -189,6 +199,25 @@ static void set_analog_pattern(const struct sr_probe_group *probe_group, int pat
} }
ag->num_samples = last_end; ag->num_samples = last_end;
break; break;
case PATTERN_SINE:
frequency = 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;
} }
} }
@ -279,8 +308,8 @@ static GSList *scan(GSList *options)
ag->packet.mqflags = 0; ag->packet.mqflags = 0;
ag->packet.unit = SR_UNIT_VOLT; ag->packet.unit = SR_UNIT_VOLT;
ag->packet.data = ag->pattern_data; ag->packet.data = ag->pattern_data;
ag->pattern = PATTERN_SINE;
pg->priv = ag; pg->priv = ag;
set_analog_pattern(pg, PATTERN_SQUARE);
sdi->probe_groups = g_slist_append(sdi->probe_groups, pg); sdi->probe_groups = g_slist_append(sdi->probe_groups, pg);
devc->analog_probe_groups = g_slist_append(devc->analog_probe_groups, pg); devc->analog_probe_groups = g_slist_append(devc->analog_probe_groups, pg);
@ -370,6 +399,7 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_probe_group *probe_group) const struct sr_probe_group *probe_group)
{ {
struct dev_context *devc; struct dev_context *devc;
struct analog_gen *ag;
struct sr_probe *probe; struct sr_probe *probe;
int pattern, ret; int pattern, ret;
unsigned int i; unsigned int i;
@ -429,9 +459,11 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
} }
if (pattern == -1) if (pattern == -1)
return SR_ERR_ARG; 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]); analog_pattern_str[pattern]);
set_analog_pattern(probe_group, pattern); ag = probe_group->priv;
ag->pattern = pattern;
} else } else
return SR_ERR_BUG; return SR_ERR_BUG;
break; break;
@ -597,6 +629,12 @@ static int prepare_data(int fd, int revents, void *cb_data)
ag = pg->priv; ag = pg->priv;
packet.type = SR_DF_ANALOG; packet.type = SR_DF_ANALOG;
packet.payload = &ag->packet; packet.payload = &ag->packet;
/* 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(samples_to_send, ag->num_samples); analog_samples = MIN(samples_to_send, ag->num_samples);
/* Whichever probe group gets there first. */ /* Whichever probe group gets there first. */
sending_now = MAX(sending_now, analog_samples); sending_now = MAX(sending_now, analog_samples);
@ -621,6 +659,7 @@ 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) static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
{ {
GSList *l;
struct dev_context *devc; struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE) if (sdi->status != SR_ST_ACTIVE)
@ -642,6 +681,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
return SR_ERR; 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]); devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL); g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);