X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fdemo%2Fprotocol.c;h=05be1d31682a309b1514957bacfee4941877e522;hb=6449b2e035b8d6ceaa7120c36b69a5be15113ab1;hp=ce897ad903bc0790223bc5e82182b8f41cd6695b;hpb=d10781808d391bb861f3ad918109148e58026e6d;p=libsigrok.git diff --git a/src/hardware/demo/protocol.c b/src/hardware/demo/protocol.c index ce897ad9..05be1d31 100644 --- a/src/hardware/demo/protocol.c +++ b/src/hardware/demo/protocol.c @@ -5,6 +5,7 @@ * Copyright (C) 2011 Olivier Fauchon * Copyright (C) 2012 Alexandru Gagniuc * Copyright (C) 2015 Bartosz Golaszewski + * Copyright (C) 2019 Frank Stettner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -172,77 +173,77 @@ 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; + + /* + * 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. + */ - 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; + /* 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) @@ -389,9 +390,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; @@ -400,23 +404,112 @@ 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; + + /* Set a unit for the given quantity. */ + if (ag->mq == SR_MQ_VOLTAGE) + ag->packet.meaning->unit = SR_UNIT_VOLT; + else if (ag->mq == SR_MQ_CURRENT) + ag->packet.meaning->unit = SR_UNIT_AMPERE; + else if (ag->mq == SR_MQ_RESISTANCE) + ag->packet.meaning->unit = SR_UNIT_OHM; + else if (ag->mq == SR_MQ_CAPACITANCE) + ag->packet.meaning->unit = SR_UNIT_FARAD; + else if (ag->mq == SR_MQ_TEMPERATURE) + ag->packet.meaning->unit = SR_UNIT_CELSIUS; + else if (ag->mq == SR_MQ_FREQUENCY) + ag->packet.meaning->unit = SR_UNIT_HERTZ; + else if (ag->mq == SR_MQ_DUTY_CYCLE) + ag->packet.meaning->unit = SR_UNIT_PERCENTAGE; + else if (ag->mq == SR_MQ_CONTINUITY) + ag->packet.meaning->unit = SR_UNIT_OHM; + else if (ag->mq == SR_MQ_PULSE_WIDTH) + ag->packet.meaning->unit = SR_UNIT_PERCENTAGE; + else if (ag->mq == SR_MQ_CONDUCTANCE) + ag->packet.meaning->unit = SR_UNIT_SIEMENS; + else if (ag->mq == SR_MQ_POWER) + ag->packet.meaning->unit = SR_UNIT_WATT; + else if (ag->mq == SR_MQ_GAIN) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else if (ag->mq == SR_MQ_SOUND_PRESSURE_LEVEL) + ag->packet.meaning->unit = SR_UNIT_DECIBEL_SPL; + else if (ag->mq == SR_MQ_CARBON_MONOXIDE) + ag->packet.meaning->unit = SR_UNIT_CONCENTRATION; + else if (ag->mq == SR_MQ_RELATIVE_HUMIDITY) + ag->packet.meaning->unit = SR_UNIT_HUMIDITY_293K; + else if (ag->mq == SR_MQ_TIME) + ag->packet.meaning->unit = SR_UNIT_SECOND; + else if (ag->mq == SR_MQ_WIND_SPEED) + ag->packet.meaning->unit = SR_UNIT_METER_SECOND; + else if (ag->mq == SR_MQ_PRESSURE) + ag->packet.meaning->unit = SR_UNIT_HECTOPASCAL; + else if (ag->mq == SR_MQ_PARALLEL_INDUCTANCE) + ag->packet.meaning->unit = SR_UNIT_HENRY; + else if (ag->mq == SR_MQ_PARALLEL_CAPACITANCE) + ag->packet.meaning->unit = SR_UNIT_FARAD; + else if (ag->mq == SR_MQ_PARALLEL_RESISTANCE) + ag->packet.meaning->unit = SR_UNIT_OHM; + else if (ag->mq == SR_MQ_SERIES_INDUCTANCE) + ag->packet.meaning->unit = SR_UNIT_HENRY; + else if (ag->mq == SR_MQ_SERIES_CAPACITANCE) + ag->packet.meaning->unit = SR_UNIT_FARAD; + else if (ag->mq == SR_MQ_SERIES_RESISTANCE) + ag->packet.meaning->unit = SR_UNIT_OHM; + else if (ag->mq == SR_MQ_DISSIPATION_FACTOR) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else if (ag->mq == SR_MQ_QUALITY_FACTOR) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else if (ag->mq == SR_MQ_PHASE_ANGLE) + ag->packet.meaning->unit = SR_UNIT_DEGREE; + else if (ag->mq == SR_MQ_DIFFERENCE) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else if (ag->mq == SR_MQ_COUNT) + ag->packet.meaning->unit = SR_UNIT_PIECE; + else if (ag->mq == SR_MQ_POWER_FACTOR) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else if (ag->mq == SR_MQ_APPARENT_POWER) + ag->packet.meaning->unit = SR_UNIT_VOLT_AMPERE; + else if (ag->mq == SR_MQ_MASS) + ag->packet.meaning->unit = SR_UNIT_GRAM; + else if (ag->mq == SR_MQ_HARMONIC_RATIO) + ag->packet.meaning->unit = SR_UNIT_UNITLESS; + else + 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 unchanged, 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)) @@ -424,7 +517,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;