]> sigrok.org Git - libsigrok.git/blame - src/input/trace32_ad.c
input/trace32_ad: silence format errors during input format match
[libsigrok.git] / src / input / trace32_ad.c
CommitLineData
6d2897e3
SA
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2015 Soeren Apel <soeren@apelpie.net>
5 * Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/*
22 * Usage notes:
23 * This input module reads .ad files created using the
24 * following practice commands:
25 *
26 * I.SAVE <file> /NoCompress
27 * IPROBE.SAVE <file> /NoCompress
28 *
29 * It currently cannot make use of files that have been
30 * saved using /QuickCompress, /Compress or /ZIP.
31 * As a workaround you may load the file in PowerView
32 * using I.LOAD / IPROBE.LOAD and re-save using /NoCompress.
33 */
34
35#include <config.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <sys/time.h>
43#include <libsigrok/libsigrok.h>
44#include "libsigrok-internal.h"
45
46#define LOG_PREFIX "input/trace32_ad"
47
9a4fd01a 48#define CHUNK_SIZE (4 * 1024 * 1024)
6d2897e3
SA
49#define MAX_POD_COUNT 12
50#define HEADER_SIZE 80
51
d9251a2c 52#define TIMESTAMP_RESOLUTION ((double)0.000000000078125) /* 0.078125 ns */
6d2897e3
SA
53
54/*
55 * The resolution equals a sampling freq of 12.8 GHz. That's a bit high
56 * for inter-record sample generation, so we scale it down to 200 MHz
57 * for now. That way, the scaling factor becomes 32.
58 */
6266deb8 59#define DEFAULT_SAMPLERATE 200
6d2897e3
SA
60
61enum {
62 AD_FORMAT_BINHDR = 1, /* Binary header, binary data, textual setup info */
63 AD_FORMAT_TXTHDR /* Textual header, binary data */
64};
65
66enum {
67 AD_DEVICE_PI = 1, /* Data recorded by LA-7940 PowerIntegrator or */
68 /* LA-394x PowerIntegrator II. */
69 AD_DEVICE_IPROBE /* Data recorded by LA-769x PowerTrace II IProbe. */
70 /* Missing file format info for LA-793x ICD PowerProbe */
71 /* Missing file format info for LA-4530 uTrace analog probe */
72};
73
74enum {
75 AD_MODE_250MHZ = 0,
76 AD_MODE_500MHZ = 1
77};
78
79enum {
80 AD_COMPR_NONE = 0, /* File created with /NOCOMPRESS */
d9251a2c 81 AD_COMPR_QCOMP = 6, /* File created with /COMPRESS or /QUICKCOMPRESS */
6d2897e3
SA
82};
83
84struct context {
85 gboolean meta_sent;
a5be5d5b 86 gboolean header_read, records_read, trigger_sent;
6d2897e3
SA
87 char format, device, record_mode, compression;
88 char pod_status[MAX_POD_COUNT];
89 struct sr_channel *channels[MAX_POD_COUNT][17]; /* 16 + CLK */
90 uint64_t trigger_timestamp;
91 uint32_t record_size, record_count, cur_record;
92 int32_t last_record;
6266deb8
SA
93 uint64_t samplerate;
94 double timestamp_scale;
6d2897e3
SA
95 GString *out_buf;
96};
97
98static int process_header(GString *buf, struct context *inc);
99static void create_channels(struct sr_input *in);
100
101static char get_pod_name_from_id(int id)
102{
103 switch (id) {
104 case 0: return 'A';
105 case 1: return 'B';
106 case 2: return 'C';
107 case 3: return 'D';
108 case 4: return 'E';
109 case 5: return 'F';
110 case 6: return 'J';
111 case 7: return 'K';
112 case 8: return 'L';
113 case 9: return 'M';
114 case 10: return 'N';
115 case 11: return 'O';
116 default:
117 sr_err("get_pod_name_from_id() called with invalid ID %d!", id);
118 }
119 return 'X';
120}
121
122static int init(struct sr_input *in, GHashTable *options)
123{
124 struct context *inc;
125 int pod;
126 char id[17];
127
128 in->sdi = g_malloc0(sizeof(struct sr_dev_inst));
129 in->priv = g_malloc0(sizeof(struct context));
130
131 inc = in->priv;
132
6266deb8
SA
133 /* Calculate the desired timestamp scaling factor. */
134 inc->samplerate = 1000000 *
135 g_variant_get_uint32(g_hash_table_lookup(options, "samplerate"));
136
137 inc->timestamp_scale = ((1 / TIMESTAMP_RESOLUTION) / (double)inc->samplerate);
138
6d2897e3
SA
139 /* Enable the pods the user chose to see. */
140 for (pod = 0; pod < MAX_POD_COUNT; pod++) {
141 g_snprintf(id, sizeof(id), "pod%c", get_pod_name_from_id(pod));
142 if (g_variant_get_boolean(g_hash_table_lookup(options, id)))
143 inc->pod_status[pod] = 1;
144 }
145
146 create_channels(in);
147 if (g_slist_length(in->sdi->channels) == 0) {
148 sr_err("No pods were selected and thus no channels created, aborting.");
149 g_free(in->priv);
150 g_free(in->sdi);
151 return SR_ERR;
152 }
153
8bc2fa6d 154 inc->out_buf = g_string_sized_new(CHUNK_SIZE);
6d2897e3
SA
155
156 return SR_OK;
157}
158
159static int format_match(GHashTable *metadata)
160{
161 GString *buf;
162
163 buf = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_HEADER));
164
165 return process_header(buf, NULL);
166}
167
168static int process_header(GString *buf, struct context *inc)
169{
170 char *format_name, *format_name_sig;
171 int i, record_size, device_id;
172
173 /*
174 * 00-31 (0x00-1F) file format name
175 * 32-39 (0x20-27) trigger timestamp u64
176 * 40-47 (0x28-2F) unused
177 * 48 (0x30) compression
178 * 49-53 (0x31-35) ??
179 * 50 (0x32) 0x00 (PI), 0x01 (iprobe)
180 * 54 (0x36) 0x08 (PI 250/500), 0x0A (iprobe 250)
181 * 55 (0x37) 0x00 (250), 0x01 (500)
182 * 56 (0x38) record size u8
183 * 57-59 (0x39-3B) const 0x00
184 * 60-63 (0x3C-3F) number of records u32
185 * 64-67 (0x40-43) id of last record s32
186 * 68-77 (0x44-4D) ??
187 * 71 (0x47) const 0x80=128
188 * 72 (0x48) const 0x01
189 * 78-79 (0x4E-4F) ??
190 */
191
192 /* Note: inc is off-limits until we check whether it's a valid pointer. */
193
194 format_name = g_strndup(buf->str, 32);
195
196 /* File format name ends on 0x20/0x1A, let's remove both. */
197 for (i = 1; i < 31; i++) {
198 if (format_name[i] == 0x1A) {
199 format_name[i - 1] = 0;
200 format_name[i] = 0;
201 }
202 }
203 g_strchomp(format_name); /* This is for additional padding spaces. */
204
205 format_name_sig = g_strndup(format_name, 5);
206
207 /* Desired file formats either start with digit+space or "trace32". */
208 if (g_strcmp0(format_name_sig, "trace32")) {
209 if (inc)
210 inc->format = AD_FORMAT_BINHDR;
211 } else if (g_ascii_isdigit(format_name[0]) && (format_name[1] == 0x20)) {
212 if (inc)
213 inc->format = AD_FORMAT_TXTHDR;
214 g_free(format_name_sig);
215 g_free(format_name);
cdb134eb
GS
216 if (inc)
217 sr_err("This format isn't implemented yet, aborting.");
218 else
219 sr_dbg("Not a supported trace32 input file.");
6d2897e3
SA
220 return SR_ERR;
221 } else {
222 g_free(format_name_sig);
223 g_free(format_name);
cdb134eb
GS
224 if (inc)
225 sr_err("Don't know this file format, aborting.");
226 else
227 sr_dbg("Not a trace32 input file.");
6d2897e3
SA
228 return SR_ERR;
229 }
230
231 sr_dbg("File says it's \"%s\"", format_name);
232
233 record_size = R8(buf->str + 56);
234 device_id = 0;
235
236 if (g_strcmp0(format_name, "trace32 power integrator data") == 0) {
237 if (record_size == 28 || record_size == 45)
238 device_id = AD_DEVICE_PI;
239 } else if (g_strcmp0(format_name, "trace32 iprobe data") == 0) {
240 if (record_size == 11)
241 device_id = AD_DEVICE_IPROBE;
242 }
243
244 if (!device_id) {
245 g_free(format_name_sig);
246 g_free(format_name);
247 sr_err("Don't know how to handle this file with record size %d.",
248 record_size);
249 return SR_ERR;
250 }
251
252 g_free(format_name_sig);
253 g_free(format_name);
254
255 /* Stop processing the header if we just want to identify the file. */
256 if (!inc)
257 return SR_OK;
258
259 inc->device = device_id;
260 inc->trigger_timestamp = RL64(buf->str + 32);
d9251a2c
UH
261 inc->compression = R8(buf->str + 48); /* Maps to the enum. */
262 inc->record_mode = R8(buf->str + 55); /* Maps to the enum. */
6d2897e3
SA
263 inc->record_size = record_size;
264 inc->record_count = RL32(buf->str + 60);
265 inc->last_record = RL32S(buf->str + 64);
266
267 sr_dbg("Trigger occured at %lf s.",
268 inc->trigger_timestamp * TIMESTAMP_RESOLUTION);
269 sr_dbg("File contains %d records: first one is %d, last one is %d.",
270 inc->record_count, (inc->last_record - inc->record_count + 1),
271 inc->last_record);
272
273 /* Check if we can work with this compression. */
274 if (inc->compression != AD_COMPR_NONE) {
275 sr_err("File uses unsupported compression (0x%02X), can't continue.",
276 inc->compression);
277 return SR_ERR;
278 }
279
280 inc->header_read = TRUE;
281
282 return SR_OK;
283}
284
285static void create_channels(struct sr_input *in)
286{
287 struct context *inc;
288 int pod, channel, chan_id;
289 char name[8];
290
291 inc = in->priv;
292 chan_id = 0;
293
294 for (pod = 0; pod < MAX_POD_COUNT; pod++) {
295 if (!inc->pod_status[pod])
296 continue;
297
298 for (channel = 0; channel < 16; channel++) {
00ed77f2 299 snprintf(name, sizeof(name), "%c%d", get_pod_name_from_id(pod), channel);
6d2897e3
SA
300 inc->channels[pod][channel] =
301 sr_channel_new(in->sdi, chan_id, SR_CHANNEL_LOGIC, TRUE, name);
302 chan_id++;
303 }
304
00ed77f2 305 snprintf(name, sizeof(name), "CLK%c", get_pod_name_from_id(pod));
6d2897e3
SA
306 inc->channels[pod][16] =
307 sr_channel_new(in->sdi, chan_id, SR_CHANNEL_LOGIC, TRUE, name);
308 chan_id++;
309 }
310}
311
312static void send_metadata(struct sr_input *in)
313{
314 struct sr_datafeed_packet packet;
315 struct sr_datafeed_meta meta;
316 struct sr_config *src;
317 struct context *inc;
318
6266deb8
SA
319 inc = in->priv;
320
6d2897e3
SA
321 packet.type = SR_DF_META;
322 packet.payload = &meta;
6266deb8 323 src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(inc->samplerate));
6d2897e3
SA
324 meta.config = g_slist_append(NULL, src);
325 sr_session_send(in->sdi, &packet);
326 g_slist_free(meta.config);
327 sr_config_free(src);
328
6d2897e3
SA
329 inc->meta_sent = TRUE;
330}
331
332static void flush_output_buffer(struct sr_input *in)
333{
334 struct context *inc;
335 struct sr_datafeed_packet packet;
336 struct sr_datafeed_logic logic;
337
338 inc = in->priv;
339
340 if (inc->out_buf->len) {
341 packet.type = SR_DF_LOGIC;
342 packet.payload = &logic;
343 logic.unitsize = (g_slist_length(in->sdi->channels) + 7) / 8;
344 logic.data = inc->out_buf->str;
345 logic.length = inc->out_buf->len;
346 sr_session_send(in->sdi, &packet);
347
348 g_string_truncate(inc->out_buf, 0);
349 }
350}
351
352static void process_record_pi(struct sr_input *in, gsize start)
353{
354 struct sr_datafeed_packet packet;
355 struct context *inc;
356 uint64_t timestamp, next_timestamp;
357 uint32_t pod_data;
358 char single_payload[12 * 3];
359 GString *buf;
360 int i, pod_count, clk_offset, packet_count, pod;
361 int payload_bit, payload_len, value;
362
363 inc = in->priv;
364 buf = in->buf;
365
366 /*
367 * 00-07 timestamp
368 * 08-09 A15..0
369 * 10-11 B15..0
370 * 12-13 C15..0
371 * 14-15 D15..0
372 * 16-17 E15..0
373 * 18-19 F15..0
374 * 20-23 ??
375 * 24-25 J15..0 Not present in 500MHz mode
376 * 26-27 K15..0 Not present in 500MHz mode
377 * 28-29 L15..0 Not present in 500MHz mode
378 * 30-31 M15..0 Not present in 500MHz mode
379 * 32-33 N15..0 Not present in 500MHz mode
380 * 34-35 O15..0 Not present in 500MHz mode
381 * 36-39 ?? Not present in 500MHz mode
382 * 40/24 CLKF..A (32=CLKF, .., 1=CLKA)
383 * 41 CLKO..J (32=CLKO, .., 1=CLKJ) Not present in 500MHz mode
384 * 42/25 ??
385 * 43/26 ??
386 * 44/27 ??
387 */
388
389 timestamp = RL64(buf->str + start);
390
391 if (inc->record_mode == AD_MODE_500MHZ) {
392 pod_count = 6;
393 clk_offset = 24;
394 } else {
395 pod_count = 12;
396 clk_offset = 40;
397 }
398
399 payload_bit = 0;
400 payload_len = 0;
401 single_payload[0] = 0;
402
403 for (pod = 0; pod < pod_count; pod++) {
404 if (!inc->pod_status[pod])
405 continue;
406
407 switch (pod) {
408 case 0: /* A */
409 pod_data = RL16(buf->str + start + 8);
410 pod_data |= (RL16(buf->str + start + clk_offset) & 1) << 16;
411 break;
412 case 1: /* B */
413 pod_data = RL16(buf->str + start + 10);
414 pod_data |= (RL16(buf->str + start + clk_offset) & 2) << 15;
415 break;
416 case 2: /* C */
417 pod_data = RL16(buf->str + start + 12);
418 pod_data |= (RL16(buf->str + start + clk_offset) & 4) << 14;
419 break;
420 case 3: /* D */
421 pod_data = RL16(buf->str + start + 14);
422 pod_data |= (RL16(buf->str + start + clk_offset) & 8) << 13;
423 break;
424 case 4: /* E */
425 pod_data = RL16(buf->str + start + 16);
426 pod_data |= (RL16(buf->str + start + clk_offset) & 16) << 12;
427 break;
428 case 5: /* F */
429 pod_data = RL16(buf->str + start + 18);
430 pod_data |= (RL16(buf->str + start + clk_offset) & 32) << 11;
431 break;
432 case 6: /* J */
433 pod_data = RL16(buf->str + start + 24);
434 pod_data |= (RL16(buf->str + start + 41) & 1) << 16;
435 break;
436 case 7: /* K */
437 pod_data = RL16(buf->str + start + 26);
438 pod_data |= (RL16(buf->str + start + 41) & 2) << 15;
439 break;
440 case 8: /* L */
441 pod_data = RL16(buf->str + start + 28);
442 pod_data |= (RL16(buf->str + start + 41) & 4) << 14;
443 break;
444 case 9: /* M */
445 pod_data = RL16(buf->str + start + 30);
446 pod_data |= (RL16(buf->str + start + 41) & 8) << 13;
447 break;
448 case 10: /* N */
449 pod_data = RL16(buf->str + start + 32);
450 pod_data |= (RL16(buf->str + start + 41) & 16) << 12;
451 break;
452 case 11: /* O */
453 pod_data = RL16(buf->str + start + 34);
454 pod_data |= (RL16(buf->str + start + 41) & 32) << 11;
455 break;
456 default:
457 sr_err("Don't know how to obtain data for pod %d.", pod);
458 }
459
460 for (i = 0; i < 17; i++) {
461 value = (pod_data >> i) & 1;
462 single_payload[payload_len] |= value << payload_bit;
463
464 payload_bit++;
465 if (payload_bit > 7) {
466 payload_bit = 0;
467 payload_len++;
468 single_payload[payload_len] = 0;
469 }
470 }
471 }
472
473 /* Make sure that payload_len accounts for any incomplete bytes used. */
474 if (payload_bit)
475 payload_len++;
476
477 i = (g_slist_length(in->sdi->channels) + 7) / 8;
478 if (payload_len != i) {
479 sr_err("Payload unit size is %d but should be %d!", payload_len, i);
480 return;
481 }
482
a5be5d5b 483 if (timestamp == inc->trigger_timestamp && !inc->trigger_sent) {
6d2897e3
SA
484 sr_dbg("Trigger @%lf s, record #%d.",
485 timestamp * TIMESTAMP_RESOLUTION, inc->cur_record);
486
487 packet.type = SR_DF_TRIGGER;
488 packet.payload = NULL;
489 sr_session_send(in->sdi, &packet);
a5be5d5b 490 inc->trigger_sent = TRUE;
6d2897e3
SA
491 }
492
493 /* Is this the last record in the file? */
494 if (inc->cur_record == inc->record_count - 1) {
495 /* It is, so send the last sample data only once. */
496 g_string_append_len(inc->out_buf, single_payload, payload_len);
497 } else {
498 /* It's not, so fill the time gap by sending lots of data. */
499 next_timestamp = RL64(buf->str + start + inc->record_size);
6266deb8 500 packet_count = (int)(next_timestamp - timestamp) / inc->timestamp_scale;
6d2897e3
SA
501
502 /* Make sure we send at least one data set. */
503 if (packet_count == 0)
504 packet_count = 1;
505
506 for (i = 0; i < packet_count; i++)
507 g_string_append_len(inc->out_buf, single_payload, payload_len);
508 }
509
8bc2fa6d 510 if (inc->out_buf->len >= CHUNK_SIZE)
6d2897e3
SA
511 flush_output_buffer(in);
512}
513
514static void process_record_iprobe(struct sr_input *in, gsize start)
515{
516 struct sr_datafeed_packet packet;
517 struct context *inc;
518 uint64_t timestamp, next_timestamp;
519 char single_payload[3];
520 int i, payload_len, packet_count;
521
522 inc = in->priv;
523
524 /*
525 * 00-07 timestamp
526 * 08-09 IP15..0
527 * 10 CLK
528 */
529
530 timestamp = RL64(in->buf->str + start);
531 single_payload[0] = R8(in->buf->str + start + 8);
532 single_payload[1] = R8(in->buf->str + start + 9);
533 single_payload[2] = R8(in->buf->str + start + 10) & 1;
534 payload_len = 3;
535
a5be5d5b 536 if (timestamp == inc->trigger_timestamp && !inc->trigger_sent) {
6d2897e3
SA
537 sr_dbg("Trigger @%lf s, record #%d.",
538 timestamp * TIMESTAMP_RESOLUTION, inc->cur_record);
539
540 packet.type = SR_DF_TRIGGER;
541 packet.payload = NULL;
542 sr_session_send(in->sdi, &packet);
a5be5d5b 543 inc->trigger_sent = TRUE;
6d2897e3
SA
544 }
545
546 /* Is this the last record in the file? */
547 if (inc->cur_record == inc->record_count - 1) {
548 /* It is, so send the last sample data only once. */
549 g_string_append_len(inc->out_buf, single_payload, payload_len);
550 } else {
551 /* It's not, so fill the time gap by sending lots of data. */
552 next_timestamp = RL64(in->buf->str + start + inc->record_size);
6266deb8 553 packet_count = (int)(next_timestamp - timestamp) / inc->timestamp_scale;
6d2897e3
SA
554
555 /* Make sure we send at least one data set. */
556 if (packet_count == 0)
557 packet_count = 1;
558
559 for (i = 0; i < packet_count; i++)
560 g_string_append_len(inc->out_buf, single_payload, payload_len);
561 }
562
8bc2fa6d 563 if (inc->out_buf->len >= CHUNK_SIZE)
6d2897e3
SA
564 flush_output_buffer(in);
565}
566
567static void process_practice_token(struct sr_input *in, char *cmd_token)
568{
569 struct context *inc;
570 char **tokens;
571 char chan_suffix[2], chan_name[33];
572 char *s1, *s2;
573 int pod, ch;
574 struct sr_channel *channel;
575
576 inc = in->priv;
577
578 /*
579 * Commands of interest (I may also be IPROBE):
580 *
581 * I.TWIDTH
582 * I.TPREDELAY
583 * I.TDELAY
584 * I.TYSNC.SELECT I.A0 HIGH
585 * NAME.SET <port.chan> <name> <+/-> ...
586 */
587
588 if (!cmd_token)
589 return;
590
591 if (cmd_token[0] == 0)
592 return;
593
594 tokens = g_strsplit(cmd_token, " ", 0);
595
596 if (!tokens)
597 return;
598
599 if (g_strcmp0(tokens[0], "NAME.SET") == 0) {
600 /* Let the user know when the channel has been inverted. */
601 /* This *should* be token #3 but there's an additonal space, making it #4. */
602 chan_suffix[0] = 0;
603 chan_suffix[1] = 0;
604 if (tokens[4]) {
605 if (tokens[4][0] == '-')
606 chan_suffix[0] = '-'; /* This is the way PowerView shows it. */
607 }
608
609 /*
610 * Command is using structure "NAME.SET I.A00 I.XYZ" or
611 * "NAME.SET IP.00 IP.XYZ", depending on the device used.
612 * Let's get strings with the I./IP. from both tokens removed.
613 */
614 s1 = g_strstr_len(tokens[1], -1, ".") + 1;
615 s2 = g_strstr_len(tokens[2], -1, ".") + 1;
616
617 if (g_strcmp0(s1, "CLK") == 0) {
618 /* CLK for iprobe */
619 pod = 0;
620 ch = 16;
621 } else if ((strlen(s1) == 4) && g_ascii_isupper(s1[3])) {
622 /* CLKA/B/J/K for PowerIntegrator */
623 pod = s1[3] - (char)'A';
624 ch = 16;
625 } else if (g_ascii_isupper(s1[0])) {
626 /* A00 for PowerIntegrator */
627 pod = s1[0] - (char)'A';
628 ch = atoi(s1 + 1);
629 } else {
630 /* 00 for iprobe */
631 pod = 0;
632 ch = atoi(s1);
633 }
634
635 channel = inc->channels[pod][ch];
636 g_snprintf(chan_name, sizeof(chan_name), "%s%s", s2, chan_suffix);
637
638 sr_dbg("Changing channel name for %s to %s.", s1, chan_name);
639 sr_dev_channel_name_set(channel, chan_name);
640 }
641
642 g_strfreev(tokens);
643}
644
645static void process_practice(struct sr_input *in)
646{
647 char delimiter[3];
648 char **tokens, *token;
649 int i;
650
651 /* Gather all input data until we see the end marker. */
652 if (in->buf->str[in->buf->len - 1] != 0x29)
653 return;
654
655 delimiter[0] = 0x0A;
656 delimiter[1] = ' ';
657 delimiter[2] = 0;
658
659 tokens = g_strsplit(in->buf->str, delimiter, 0);
660
661 /* Special case: first token contains the start marker, too. Skip it. */
662 token = tokens[0];
663 for (i = 0; token[i]; i++) {
664 if (token[i] == ' ')
665 process_practice_token(in, token + i + 1);
666 }
667
668 for (i = 1; tokens[i]; i++)
669 process_practice_token(in, tokens[i]);
670
671 g_strfreev(tokens);
672
673 g_string_erase(in->buf, 0, in->buf->len);
674}
675
676static int process_buffer(struct sr_input *in)
677{
678 struct context *inc;
679 int i, chunk_size, res;
680
681 inc = in->priv;
682
683 if (!inc->header_read) {
684 res = process_header(in->buf, inc);
685 g_string_erase(in->buf, 0, HEADER_SIZE);
686 if (res != SR_OK)
687 return res;
688 }
689
690 if (!inc->meta_sent) {
bee2b016 691 std_session_send_df_header(in->sdi);
6d2897e3
SA
692 send_metadata(in);
693 }
694
695 if (!inc->records_read) {
696 /* Cut off at a multiple of the record size. */
697 chunk_size = ((in->buf->len) / inc->record_size) * inc->record_size;
698
699 /* There needs to be at least one more record process_record() can peek into. */
700 chunk_size -= inc->record_size;
701
702 for (i = 0; (i < chunk_size) && (!inc->records_read); i += inc->record_size) {
703 switch (inc->device) {
704 case AD_DEVICE_PI:
705 process_record_pi(in, i);
706 break;
707 case AD_DEVICE_IPROBE:
708 process_record_iprobe(in, i);
709 break;
710 default:
711 sr_err("Trying to process records for unknown device!");
712 return SR_ERR;
713 }
714
715 inc->cur_record++;
716 if (inc->cur_record == inc->record_count)
717 inc->records_read = TRUE;
718 }
719
720 g_string_erase(in->buf, 0, i);
721 }
722
723 if (inc->records_read) {
724 /* Read practice commands that configure the setup. */
725 process_practice(in);
726 }
727
728 return SR_OK;
729}
730
731static int receive(struct sr_input *in, GString *buf)
732{
733 g_string_append_len(in->buf, buf->str, buf->len);
734
735 if (!in->sdi_ready) {
736 /* sdi is ready, notify frontend. */
737 in->sdi_ready = TRUE;
738 return SR_OK;
739 }
740
741 return process_buffer(in);
742}
743
744static int end(struct sr_input *in)
745{
746 struct context *inc;
6d2897e3
SA
747 int ret;
748
749 inc = in->priv;
750
751 if (in->sdi_ready)
752 ret = process_buffer(in);
753 else
754 ret = SR_OK;
755
756 flush_output_buffer(in);
757
3be42bc2 758 if (inc->meta_sent)
bee2b016 759 std_session_send_df_end(in->sdi);
6d2897e3
SA
760
761 return ret;
762}
763
87616181
SA
764static int reset(struct sr_input *in)
765{
766 struct context *inc = in->priv;
767
768 inc->meta_sent = FALSE;
769 inc->header_read = FALSE;
770 inc->records_read = FALSE;
771 inc->trigger_sent = FALSE;
772 inc->cur_record = 0;
773
774 g_string_truncate(in->buf, 0);
775
776 return SR_OK;
777}
778
6d2897e3
SA
779static struct sr_option options[] = {
780 { "podA", "Import pod A / iprobe",
781 "Create channels and data for pod A / iprobe", NULL, NULL },
782
783 { "podB", "Import pod B", "Create channels and data for pod B", NULL, NULL },
784 { "podC", "Import pod C", "Create channels and data for pod C", NULL, NULL },
785 { "podD", "Import pod D", "Create channels and data for pod D", NULL, NULL },
786 { "podE", "Import pod E", "Create channels and data for pod E", NULL, NULL },
787 { "podF", "Import pod F", "Create channels and data for pod F", NULL, NULL },
788 { "podJ", "Import pod J", "Create channels and data for pod J", NULL, NULL },
789 { "podK", "Import pod K", "Create channels and data for pod K", NULL, NULL },
790 { "podL", "Import pod L", "Create channels and data for pod L", NULL, NULL },
791 { "podM", "Import pod M", "Create channels and data for pod M", NULL, NULL },
792 { "podN", "Import pod N", "Create channels and data for pod N", NULL, NULL },
793 { "podO", "Import pod O", "Create channels and data for pod O", NULL, NULL },
6266deb8 794
867293a1 795 { "samplerate", "Reduced sample rate (MHz)", "Reduce the original sample rate of 12.8 GHz to the specified sample rate in MHz", NULL, NULL },
6266deb8 796
6d2897e3
SA
797 ALL_ZERO
798};
799
800static const struct sr_option *get_options(void)
801{
802 if (!options[0].def) {
803 options[0].def = g_variant_ref_sink(g_variant_new_boolean(TRUE));
804 options[1].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
805 options[2].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
806 options[3].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
807 options[4].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
808 options[5].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
809 options[6].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
810 options[7].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
811 options[8].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
812 options[9].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
813 options[10].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
814 options[11].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
6266deb8 815 options[12].def = g_variant_ref_sink(g_variant_new_uint32(DEFAULT_SAMPLERATE));
6d2897e3
SA
816 }
817
818 return options;
819}
820
821SR_PRIV struct sr_input_module input_trace32_ad = {
822 .id = "trace32_ad",
823 .name = "Trace32_ad",
824 .desc = "Lauterbach Trace32 logic analyzer data",
825 .exts = (const char*[]){"ad", NULL},
826 .options = get_options,
827 .metadata = { SR_INPUT_META_HEADER | SR_INPUT_META_REQUIRED },
828 .format_match = format_match,
829 .init = init,
830 .receive = receive,
831 .end = end,
87616181 832 .reset = reset,
6d2897e3 833};