X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Finput%2Ftrace32_ad.c;h=f34a166db5fd48265a5a7381eaef0669902c5b93;hb=80430d4d202799a2a732e086a55ba1a058c4725b;hp=4c991a987ca74e094d255d34d0f0a799260d3da9;hpb=6266deb84d6b5d8ca61b685edae339c24184f157;p=libsigrok.git diff --git a/src/input/trace32_ad.c b/src/input/trace32_ad.c index 4c991a98..f34a166d 100644 --- a/src/input/trace32_ad.c +++ b/src/input/trace32_ad.c @@ -45,12 +45,15 @@ #define LOG_PREFIX "input/trace32_ad" -#define MAX_CHUNK_SIZE 4096 -#define OUTBUF_FLUSH_SIZE 10240 +#define CHUNK_SIZE (4 * 1024 * 1024) #define MAX_POD_COUNT 12 #define HEADER_SIZE 80 -#define TIMESTAMP_RESOLUTION ((double)0.000000000078125) /* 0.078125 ns */ +#define SPACE ' ' +#define CTRLZ '\x1a' +#define TRACE32 "trace32" + +#define TIMESTAMP_RESOLUTION ((double)0.000000000078125) /* 0.078125 ns */ /* * The resolution equals a sampling freq of 12.8 GHz. That's a bit high @@ -79,7 +82,7 @@ enum { enum { AD_COMPR_NONE = 0, /* File created with /NOCOMPRESS */ - AD_COMPR_QCOMP = 6 /* File created with /COMPRESS or /QUICKCOMPRESS */ + AD_COMPR_QCOMP = 6, /* File created with /COMPRESS or /QUICKCOMPRESS */ }; struct context { @@ -99,6 +102,29 @@ struct context { static int process_header(GString *buf, struct context *inc); static void create_channels(struct sr_input *in); +/* Transform non-printable chars to '\xNN' presentation. */ +static char *printable_name(const char *name) +{ + size_t l, i; + char *s, *p; + + if (!name) + return NULL; + l = strlen(name); + s = g_malloc0(l * strlen("\\x00") + 1); + for (p = s, i = 0; i < l; i++) { + if (g_ascii_isprint(name[i])) { + *p++ = name[i]; + } else { + snprintf(p, 5, "\\x%05x", name[i]); + p += strlen("\\x00"); + } + } + *p = '\0'; + + return s; +} + static char get_pod_name_from_id(int id) { switch (id) { @@ -152,24 +178,32 @@ static int init(struct sr_input *in, GHashTable *options) return SR_ERR; } - inc->out_buf = g_string_sized_new(OUTBUF_FLUSH_SIZE); + inc->out_buf = g_string_sized_new(CHUNK_SIZE); return SR_OK; } -static int format_match(GHashTable *metadata) +static int format_match(GHashTable *metadata, unsigned int *confidence) { GString *buf; + int rc; buf = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_HEADER)); + rc = process_header(buf, NULL); + + if (rc != SR_OK) + return rc; + *confidence = 10; - return process_header(buf, NULL); + return SR_OK; } static int process_header(GString *buf, struct context *inc) { char *format_name, *format_name_sig; - int i, record_size, device_id; + char *p; + int has_trace32; + int record_size, device_id; /* * 00-31 (0x00-1F) file format name @@ -190,40 +224,56 @@ static int process_header(GString *buf, struct context *inc) * 78-79 (0x4E-4F) ?? */ - /* Note: inc is off-limits until we check whether it's a valid pointer. */ + /* + * Note: The routine is called from different contexts. Either + * to auto-detect the file format (format_match(), 'inc' is NULL), + * or to process the data during acquisition (receive(), 'inc' + * is a valid pointer). This header parse routine shall gracefully + * deal with unexpected or incorrect input data. + */ + /* + * Get up to the first 32 bytes of the file content. File format + * names end on SPACE or CTRL-Z (or NUL). Trim trailing SPACE + * before further processing. + */ format_name = g_strndup(buf->str, 32); + p = strchr(format_name, CTRLZ); + if (p) + *p = '\0'; + g_strchomp(format_name); - /* File format name ends on 0x20/0x1A, let's remove both. */ - for (i = 1; i < 31; i++) { - if (format_name[i] == 0x1A) { - format_name[i - 1] = 0; - format_name[i] = 0; - } - } - g_strchomp(format_name); /* This is for additional padding spaces. */ - - format_name_sig = g_strndup(format_name, 5); + /* + * File format names either start with the "trace32" literal, + * or with a digit and SPACE. + */ + format_name_sig = g_strndup(format_name, strlen(TRACE32)); + has_trace32 = g_strcmp0(format_name_sig, TRACE32) == 0; + g_free(format_name_sig); - /* Desired file formats either start with digit+space or "trace32". */ - if (g_strcmp0(format_name_sig, "trace32")) { + if (has_trace32) { + /* Literal "trace32" leader, binary header follows. */ if (inc) inc->format = AD_FORMAT_BINHDR; - } else if (g_ascii_isdigit(format_name[0]) && (format_name[1] == 0x20)) { + } else if (g_ascii_isdigit(format_name[0]) && (format_name[1] == SPACE)) { + /* Digit and SPACE leader, currently unsupported text header. */ if (inc) inc->format = AD_FORMAT_TXTHDR; - g_free(format_name_sig); g_free(format_name); - sr_err("This format isn't implemented yet, aborting."); + if (inc) + sr_err("This format isn't implemented yet, aborting."); return SR_ERR; } else { - g_free(format_name_sig); + /* Unknown kind of format name. Unsupported. */ g_free(format_name); - sr_err("Don't know this file format, aborting."); + if (inc) + sr_err("Don't know this file format, aborting."); return SR_ERR; } - sr_dbg("File says it's \"%s\"", format_name); + p = printable_name(format_name); + sr_dbg("File says it's \"%s\"", p); + g_free(p); record_size = R8(buf->str + 56); device_id = 0; @@ -237,14 +287,12 @@ static int process_header(GString *buf, struct context *inc) } if (!device_id) { - g_free(format_name_sig); g_free(format_name); sr_err("Don't know how to handle this file with record size %d.", record_size); return SR_ERR; } - g_free(format_name_sig); g_free(format_name); /* Stop processing the header if we just want to identify the file. */ @@ -253,8 +301,8 @@ static int process_header(GString *buf, struct context *inc) inc->device = device_id; inc->trigger_timestamp = RL64(buf->str + 32); - inc->compression = R8(buf->str + 48); /* Maps to the enum. */ - inc->record_mode = R8(buf->str + 55); /* Maps to the enum. */ + inc->compression = R8(buf->str + 48); /* Maps to the enum. */ + inc->record_mode = R8(buf->str + 55); /* Maps to the enum. */ inc->record_size = record_size; inc->record_count = RL32(buf->str + 60); inc->last_record = RL32S(buf->str + 64); @@ -291,13 +339,13 @@ static void create_channels(struct sr_input *in) continue; for (channel = 0; channel < 16; channel++) { - snprintf(name, 8, "%c%d", get_pod_name_from_id(pod), channel); + snprintf(name, sizeof(name), "%c%d", get_pod_name_from_id(pod), channel); inc->channels[pod][channel] = sr_channel_new(in->sdi, chan_id, SR_CHANNEL_LOGIC, TRUE, name); chan_id++; } - snprintf(name, 8, "CLK%c", get_pod_name_from_id(pod)); + snprintf(name, sizeof(name), "CLK%c", get_pod_name_from_id(pod)); inc->channels[pod][16] = sr_channel_new(in->sdi, chan_id, SR_CHANNEL_LOGIC, TRUE, name); chan_id++; @@ -502,7 +550,7 @@ static void process_record_pi(struct sr_input *in, gsize start) g_string_append_len(inc->out_buf, single_payload, payload_len); } - if (inc->out_buf->len >= OUTBUF_FLUSH_SIZE) + if (inc->out_buf->len >= CHUNK_SIZE) flush_output_buffer(in); } @@ -555,7 +603,7 @@ static void process_record_iprobe(struct sr_input *in, gsize start) g_string_append_len(inc->out_buf, single_payload, payload_len); } - if (inc->out_buf->len >= OUTBUF_FLUSH_SIZE) + if (inc->out_buf->len >= CHUNK_SIZE) flush_output_buffer(in); } @@ -683,7 +731,7 @@ static int process_buffer(struct sr_input *in) } if (!inc->meta_sent) { - std_session_send_df_header(in->sdi, LOG_PREFIX); + std_session_send_df_header(in->sdi); send_metadata(in); } @@ -751,7 +799,7 @@ static int end(struct sr_input *in) flush_output_buffer(in); if (inc->meta_sent) - std_session_send_df_end(in->sdi, LOG_PREFIX); + std_session_send_df_end(in->sdi); return ret; } @@ -787,7 +835,7 @@ static struct sr_option options[] = { { "podN", "Import pod N", "Create channels and data for pod N", NULL, NULL }, { "podO", "Import pod O", "Create channels and data for pod O", NULL, NULL }, - { "samplerate", "Reduced sample rate in MHz", "Reduced sample rate in MHz", NULL, NULL }, + { "samplerate", "Reduced sample rate (MHz)", "Reduce the original sample rate of 12.8 GHz to the specified sample rate in MHz", NULL, NULL }, ALL_ZERO };