From 24eb07b74687f89f1b55d2653b6fac98599df5f4 Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Tue, 15 Feb 2011 19:02:02 +0100 Subject: [PATCH] Add MDF to ASCII converter CANalyzer from Vector has broken ASCII export. It truncates timestamps to 100 us resolutions, which is not usable for us. Therefore we must use binary MDF files to export traces from CANalyzer and we convert them to ASCII by this simple program. In its current form, the program is not much generic. It works for our so it is sufficient for us. --- gw-tests/canalyzer/Makefile | 3 + gw-tests/canalyzer/mdfconv.c | 175 +++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 gw-tests/canalyzer/Makefile create mode 100644 gw-tests/canalyzer/mdfconv.c diff --git a/gw-tests/canalyzer/Makefile b/gw-tests/canalyzer/Makefile new file mode 100644 index 0000000..bccb201 --- /dev/null +++ b/gw-tests/canalyzer/Makefile @@ -0,0 +1,3 @@ +all: mdfconv + +CFLAGS=-g -Wall -O0 diff --git a/gw-tests/canalyzer/mdfconv.c b/gw-tests/canalyzer/mdfconv.c new file mode 100644 index 0000000..64a32ef --- /dev/null +++ b/gw-tests/canalyzer/mdfconv.c @@ -0,0 +1,175 @@ +/* Quick-and-dirt MDF file parser + * (c) 2011 Michal Sojka + * License: GPLv2+ + * + * MDF Specification: http://www.vector.com/vi_mdf_en.html or + * https://www.vector.com/vi_downloadcenter_en.html?busprot=MDF&formular_treffer_submit=1&sprachumschaltung=1 + */ + +#include +#include +#include +#include + +typedef uint32_t link; + +struct idblock { + char file_identifier[8]; + char format_identifier[8]; + char program_identifier[8]; + uint16_t default_byte_order; + uint16_t version_number; + uint16_t code_page_number; + char res1[2]; + char res2[30]; +} __attribute__((packed)); + +struct hdblock { + char hd[2]; + uint16_t block_size; + link data_group_block; + link file_comment; + link program_block; + uint16_t number_of_data_groups; + char date[10]; + char time[8]; + char author[32]; + char organization[32]; + char project[32]; + char subject[32]; + uint64_t timestamp; + int16_t utc_time_offset; + uint16_t time_quality_class; + char timer_ident[32]; +} __attribute__((packed)); + +struct dgblock { + char dg[2]; + uint16_t block_size; + link next_dgblock; + link first_channel_group_block; + link trigger_block; + link data_block; + uint16_t num_chn_groups; + uint16_t num_rec_ids; + uint32_t res; +} __attribute__((packed)); + +struct cgblock { + char cg[2]; + uint16_t block_size; + link next_channel_group_block; + link first_channel_block; + link comment; + uint16_t record_id; + uint16_t num_channels; + uint16_t size_of_data_record; + uint32_t num_records; + link first_sample_reduction_block; +} __attribute__((packed)); + +struct cnblock { + char cn[2]; + uint16_t block_size; + link next_channel_block; + link conversion_formula; + link source_dep_ext; + link dependency_block; + link comment; + uint16_t channel_type; + char short_signal_name[32]; + char signal_description[128]; + uint16_t start_offset_in_bits; + uint16_t number_of_bits; + uint16_t signal_data_type; +} __attribute__((packed)); + +int main(int argc, char *argv[]) +{ + FILE *f; + struct idblock id; + struct hdblock hd; + struct dgblock dg; + struct cgblock cg; + unsigned i, cnidx; + struct cnblock *cn[20]; + link cglink; + char *rec; + + if (argc != 2) { + error(1, 0, "Usage: %s ", argv[0]); + } + f = fopen(argv[1], "r"); + fread(&id, sizeof(id), 1, f); + fseek(f, 64, SEEK_SET); + fread(&hd, sizeof(hd), 1, f); + fseek(f, hd.data_group_block, SEEK_SET); + fread(&dg, sizeof(dg), 1, f); + + cglink = dg.first_channel_group_block; + while (cglink) { + link cnlink; + fseek(f, cglink, SEEK_SET); + fread(&cg, sizeof(cg), 1, f); + cnlink = cg.first_channel_block; + cnidx = 0; + while (cnlink) { + fseek(f, cnlink, SEEK_SET); + cn[cnidx] = malloc(sizeof(struct cnblock)); + fread(cn[cnidx], sizeof(struct cnblock), 1, f); + cnlink = cn[cnidx]->next_channel_block; + cnidx++; + } + cglink = cg.next_channel_group_block; + } + + printf("#"); + for (i=0; ishort_signal_name); + } + printf("\n"); + + rec = malloc(cg.size_of_data_record); + + fseek(f, dg.data_block, SEEK_SET); + int j; + for (j=0; jsignal_data_type) { + case 0: + switch(c->number_of_bits) { + case 8: printf("%hhu", rec[c->start_offset_in_bits/8]); break; + case 16: printf("%hu", *(uint16_t*)&rec[c->start_offset_in_bits/8]); break; + case 32: printf("%u", *(uint32_t*)&rec[c->start_offset_in_bits/8]); break; + default: printf("?size%d", c->number_of_bits); + } + break; + case 1: + switch(c->number_of_bits) { + case 8: printf("%hhd", rec[c->start_offset_in_bits/8]); break; + case 16: printf("%hd", *(int16_t*)&rec[c->start_offset_in_bits/8]); break; + case 32: printf("%d", *(int32_t*)&rec[c->start_offset_in_bits/8]); break; + default: printf("?size%d", c->number_of_bits); + } + break; + default: + printf("?type%d", c->signal_data_type); + } + printf(" "); + } + printf("\n"); + } else + error(1, 0, "Unknown record id %d\n", rec_id); + } + return 0; +} -- 2.39.2