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