+/*
+ * We treat logic packets the same as analog packets, though it's not
+ * strictly required. This allows us to process mixed signals properly.
+ */
+static void process_logic(struct context *ctx,
+ const struct sr_datafeed_logic *logic)
+{
+ unsigned int i, j, ch, num_samples;
+ int idx;
+ uint8_t *sample;
+
+ num_samples = logic->length / logic->unitsize;
+ ctx->channels_seen += ctx->logic_channel_count;
+ sr_dbg("Logic packet had %d channels", logic->unitsize * 8);
+ if (!ctx->logic_samples) {
+ ctx->logic_samples = g_malloc(num_samples * ctx->num_logic_channels);
+ if (!ctx->num_samples)
+ ctx->num_samples = num_samples;
+ }
+ if (ctx->num_samples != num_samples)
+ sr_warn("Expecting %u samples, got %u",
+ ctx->num_samples, num_samples);
+
+ for (j = ch = 0; ch < ctx->num_logic_channels; j++) {
+ if (ctx->channels[j].ch->type == SR_CHANNEL_LOGIC) {
+ for (i = 0; i < num_samples; i++) {
+ sample = logic->data + i * logic->unitsize;
+ idx = ctx->channels[j].ch->index;
+ if (ctx->label_do && !ctx->label_names)
+ ctx->channels[j].label = "logic";
+ ctx->logic_samples[i * ctx->num_logic_channels + ch] = sample[idx / 8] & (1 << (idx % 8));
+ }
+ ch++;
+ }
+ }
+}
+
+static void dump_saved_values(struct context *ctx, GString **out)
+{
+ unsigned int i, j, analog_size, num_channels;
+ float *analog_sample, value;
+ uint8_t *logic_sample;
+
+ /* If we haven't seen samples we're expecting, skip them. */
+ if ((ctx->num_analog_channels && !ctx->analog_samples) ||
+ (ctx->num_logic_channels && !ctx->logic_samples)) {
+ sr_warn("Discarding partial packet");
+ } else {
+ sr_info("Dumping %u samples", ctx->num_samples);
+
+ *out = g_string_sized_new(512);
+ num_channels =
+ ctx->num_logic_channels + ctx->num_analog_channels;
+
+ if (ctx->label_do) {
+ if (ctx->time)
+ g_string_append_printf(*out, "%s%s",
+ ctx->label_names ? "Time" :
+ ctx->xlabel, ctx->value);
+ for (i = 0; i < num_channels; i++) {
+ g_string_append_printf(*out, "%s%s",
+ ctx->channels[i].label, ctx->value);
+ if (ctx->channels[i].ch->type == SR_CHANNEL_ANALOG
+ && ctx->label_names)
+ g_free(ctx->channels[i].label);
+ }
+ if (ctx->do_trigger)
+ g_string_append_printf(*out, "Trigger%s",
+ ctx->value);
+ /* Drop last separator. */
+ g_string_truncate(*out, (*out)->len - 1);
+ g_string_append(*out, ctx->record);
+
+ ctx->label_do = FALSE;
+ }
+
+ analog_size = ctx->num_analog_channels * sizeof(float);
+ if (ctx->dedup && !ctx->previous_sample)
+ ctx->previous_sample = g_malloc0(analog_size + ctx->num_logic_channels);
+
+ for (i = 0; i < ctx->num_samples; i++) {
+ ctx->sample_time += ctx->period;
+ analog_sample =
+ &ctx->analog_samples[i * ctx->num_analog_channels];
+ logic_sample =
+ &ctx->logic_samples[i * ctx->num_logic_channels];
+
+ if (ctx->dedup) {
+ if (i > 0 && i < ctx->num_samples - 1 &&
+ !memcmp(logic_sample, ctx->previous_sample,
+ ctx->num_logic_channels) &&
+ !memcmp(analog_sample,
+ ctx->previous_sample +
+ ctx->num_logic_channels,
+ analog_size))
+ continue;
+ memcpy(ctx->previous_sample, logic_sample,
+ ctx->num_logic_channels);
+ memcpy(ctx->previous_sample
+ + ctx->num_logic_channels,
+ analog_sample, analog_size);
+ }
+
+ if (ctx->time)
+ g_string_append_printf(*out, "%" PRIu64 "%s",
+ ctx->sample_time, ctx->value);
+
+ for (j = 0; j < num_channels; j++) {
+ if (ctx->channels[j].ch->type == SR_CHANNEL_ANALOG) {
+ value = ctx->analog_samples[i * ctx->num_analog_channels + j];
+ ctx->channels[j].max =
+ fmax(value, ctx->channels[j].max);
+ ctx->channels[j].min =
+ fmin(value, ctx->channels[j].min);
+ g_string_append_printf(*out, "%g%s",
+ value, ctx->value);
+ } else if (ctx->channels[j].ch->type == SR_CHANNEL_LOGIC) {
+ g_string_append_printf(*out, "%c%s",
+ ctx->logic_samples[i * ctx->num_logic_channels + j] ? '1' : '0', ctx->value);
+ } else {
+ sr_warn("Unexpected channel type: %d",
+ ctx->channels[i].ch->type);
+ }
+ }
+
+ if (ctx->do_trigger) {
+ g_string_append_printf(*out, "%d%s",
+ ctx->trigger, ctx->value);
+ ctx->trigger = FALSE;
+ }
+ g_string_truncate(*out, (*out)->len - 1);
+ g_string_append(*out, ctx->record);