Add MDF to ASCII converter
authorMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 15 Feb 2011 18:02:02 +0000 (19:02 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 15 Feb 2011 18:02:02 +0000 (19:02 +0100)
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 [new file with mode: 0644]
gw-tests/canalyzer/mdfconv.c [new file with mode: 0644]

diff --git a/gw-tests/canalyzer/Makefile b/gw-tests/canalyzer/Makefile
new file mode 100644 (file)
index 0000000..bccb201
--- /dev/null
@@ -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 (file)
index 0000000..64a32ef
--- /dev/null
@@ -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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <error.h>
+
+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 <mdf_log_file>", 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; i<cnidx; i++) {
+               struct cnblock *c = cn[i];
+               printf("%s ", c->short_signal_name);
+       }
+       printf("\n");
+
+       rec = malloc(cg.size_of_data_record);
+
+       fseek(f, dg.data_block, SEEK_SET);
+       int j;
+       for (j=0; j<cg.num_records; j++) {
+               uint8_t rec_id;
+               switch (dg.num_rec_ids) {
+               case 0: rec_id = 0; break;
+               case 1: fread(&rec_id, sizeof(rec_id), 1, f); break;
+               default: printf("Unsupported num_rec_ids\n");
+               }
+               if (rec_id == cg.record_id) {
+                       fread(rec, cg.size_of_data_record, 1, f);
+                       for (i=0; i<cnidx; i++) {
+                               struct cnblock *c = cn[i];
+                               switch (c->signal_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;
+}