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