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