SDDSlib
Loading...
Searching...
No Matches
tdms2sdds.c
1/*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * This file is distributed subject to a Software License Agreement found
7 * in the file LICENSE that is included with this distribution.
8\*************************************************************************/
9
10/* Read http://www.ni.com/white-paper/5696/en/ for definitions for the header elements */
11
12#include "mdb.h"
13#include "SDDS.h"
14#include "scan.h"
15#if defined(_WIN32)
16# include <io.h>
17# include <fcntl.h>
18typedef signed __int16 int16_t;
19typedef signed __int8 int8_t;
20typedef unsigned __int16 uint16_t;
21typedef signed __int64 int64_t;
22#endif
23
24typedef struct
25{
26 int32_t toc;
27 uint32_t version;
28 uint64_t next_segment_offset;
29 uint64_t raw_data_offset;
31
32typedef struct
33{
34 char *name;
35 int32_t datatype;
36 void *value;
38
39typedef struct
40{
41 char *path;
42 uint32_t raw_data_index;
43 int32_t raw_data_datatype;
44 uint32_t raw_data_dimensions;
45 uint64_t raw_data_count;
46 uint64_t raw_data_total_size;
47 uint32_t n_properties;
50
51typedef struct
52{
53 uint32_t n_objects;
56
57typedef struct
58{
59 uint32_t n_values;
60 double *values;
61 char *name;
62 int32_t datatype;
64
65typedef struct
66{
67 uint32_t n_channels;
68 TDMS_RAW_DATA_CHANNEL *channel;
70
71typedef struct
72{
73 char *name;
74 char *unit;
75 long double start_time;
76 long double start_offset;
77 long double increment;
78 int32_t samples;
79 char *time_pref;
80 long double range;
82
83typedef struct
84{
85 TDMS_LEAD_IN lead_in;
86 TDMS_META_DATA meta_data;
87 TDMS_RAW_DATA raw_data;
88 TDMS_XPART xpart;
90
91typedef struct
92{
93 uint32_t n_segments;
94 TDMS_SEGMENT *segment; /* segments are like SDDS pages */
95 long filesize;
96} TDMS_FILE;
97
98void TDMS_ReadLeadIn(FILE *fd, TDMS_SEGMENT *segment);
99void TDMS_ReadMetaData(FILE *fd, TDMS_SEGMENT *segment);
100void TDMS_ReadRawData(FILE *fd, TDMS_FILE *tdms, uint32_t n_segment, long filesize);
101void TDMS_GetValue(FILE *fd, void **value, int32_t datatype);
102
103#define kTocMetaData (1L << 1)
104#define kTocNewObjList (1L << 2)
105#define kTocRawData (1L << 3)
106#define kTocInterleavedData (1L << 5)
107#define kTocBigEndian (1L << 6)
108#define kTocDAQmxRawData (1L << 7)
109
110#define tdsTypeVoid 0x00000000
111#define tdsTypeI8 0x00000001
112#define tdsTypeI16 0x00000002
113#define tdsTypeI32 0x00000003
114#define tdsTypeI64 0x00000004
115#define tdsTypeU8 0x00000005
116#define tdsTypeU16 0x00000006
117#define tdsTypeU32 0x00000007
118#define tdsTypeU64 0x00000008
119#define tdsTypeSingleFloat 0x00000009
120#define tdsTypeDoubleFloat 0x0000000A
121#define tdsTypeExtendedFloat 0x0000000B
122#define tdsTypeSingleFloatWithUnit 0x00000019
123#define tdsTypeDoubleFloatWithUnit 0x0000001A
124#define tdsTypeExtendedFloatWithUnit 0x0000001B
125#define tdsTypeString 0x00000020
126#define tdsTypeBoolean 0x00000021
127#define tdsTypeTimeStamp 0x00000044
128#define tdsTypeDAQmxRawData 0xFFFFFFFF
129
130#define SET_ASCII 0
131#define SET_BINARY 1
132#define SET_PIPE 2
133#define SET_SEGMENT 3
134#define SET_NUMOFSEGMENTS 4
135#define N_OPTIONS 5
136
137char *option[N_OPTIONS] = {
138 "ascii", "binary", "pipe", "segment", "numofsegments"};
139
140char *USAGE = "tdms2sdds [<inputFile>] [<outputFile>] [-pipe=out]\n\
141[-ascii | -binary] [-numOfSegments] [-segment=<integer>]\n\n\
142pipe SDDS toolkit pipe option.\n\
143ascii Requests SDDS ASCII output. Default is binary.\n\
144binary Requests SDDS BINARY output.\n\
145numofsegments Print out number of TDMS segments.\n\
146segment Some TDMS files have different types of data in different segments. \n\
147 SDDS can't handle this unless you split it up into multiple SDDS \n\
148 files, one for each segment.\n\n\
149Converts National Instruments TDMS files to SDDS.\n\
150Program by Robert Soliday. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
151
152int main(int argc, char **argv) {
153 FILE *fd;
154 char *input = NULL, *output = NULL;
155 SDDS_DATASET SDDSout;
156 SCANNED_ARG *scanned;
157 long iArg;
158 long ascii = 0;
159 unsigned long pipeFlags = 0;
160 int i = 0, n, found, ii, jj, kk, segment = 0, querySegments = 0;
161 long double timeValue;
162 short timeDefined = 0;
163 char buffer[1024];
164
165 TDMS_FILE tdms;
166 uint64_t rows = 0, j = 0, k;
167
169 argc = scanargs(&scanned, argc, argv);
170 if (argc < 2) {
171 fprintf(stderr, "%s", USAGE);
172 return (1);
173 }
174
175 for (iArg = 1; iArg < argc; iArg++) {
176 if (scanned[iArg].arg_type == OPTION) {
177 switch (match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
178 case SET_ASCII:
179 ascii = 1;
180 break;
181 case SET_BINARY:
182 ascii = 0;
183 break;
184 case SET_SEGMENT:
185 if (scanned[iArg].n_items < 2) {
186 fprintf(stderr, "Error (%s): invalid -segment syntax\n", argv[0]);
187 return (1);
188 }
189 if (sscanf(scanned[iArg].list[1], "%d", &segment) != 1 || segment <= 0) {
190 fprintf(stderr, "Error (%s): invalid -segment syntax or value\n", argv[0]);
191 return (1);
192 }
193 break;
194 case SET_NUMOFSEGMENTS:
195 querySegments = 1;
196 break;
197 case SET_PIPE:
198 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
199 fprintf(stderr, "invalid -pipe syntax\n");
200 return (1);
201 }
202 break;
203 default:
204 fprintf(stderr, "invalid option seen\n");
205 fprintf(stderr, "%s", USAGE);
206 return (1);
207 }
208 } else {
209 if (!input)
210 input = scanned[iArg].list[0];
211 else if (!output)
212 output = scanned[iArg].list[0];
213 else {
214 fprintf(stderr, "too many filenames\n");
215 fprintf(stderr, "%s", USAGE);
216 return (1);
217 }
218 }
219 }
220 if (!querySegments) {
221 processFilenames("tdms2sdds", &input, &output, pipeFlags, 0, NULL);
222 }
223
224 if (input) {
225 if (!fexists(input)) {
226 fprintf(stderr, "input file not found\n");
227 return (1);
228 }
229 if (!(fd = fopen(input, "rb"))) {
230 fprintf(stderr, "problem opening input file\n");
231 return (1);
232 }
233 } else {
234 fprintf(stderr, "tdms2sdds cannot -pipe=in tdms files\n");
235 return (1);
236 }
237
238 fseek(fd, 0L, SEEK_END);
239 tdms.filesize = ftell(fd);
240 fseek(fd, 0L, SEEK_SET);
241
242 tdms.n_segments = 0;
243 while (ftell(fd) < tdms.filesize) {
244 tdms.n_segments++;
245 if (tdms.n_segments == 1) {
246 tdms.segment = malloc(sizeof(TDMS_SEGMENT));
247 } else {
248 tdms.segment = realloc(tdms.segment, sizeof(TDMS_SEGMENT) * tdms.n_segments);
249 }
250 /* Read Lead In */
251 TDMS_ReadLeadIn(fd, &(tdms.segment[tdms.n_segments - 1]));
252 if (tdms.segment[tdms.n_segments - 1].lead_in.toc & kTocBigEndian) {
254 fprintf(stderr, "tdms2sdds does not yet support reading from non-native endian TDMS files.\n");
255 return (1);
256 }
257 } else {
259 fprintf(stderr, "tdms2sdds does not yet support reading from non-native endian TDMS files.\n");
260 return (1);
261 }
262 }
263 /* Read Meta Data */
264 if (tdms.segment[tdms.n_segments - 1].lead_in.toc & kTocMetaData) {
265 TDMS_ReadMetaData(fd, &(tdms.segment[tdms.n_segments - 1]));
266 }
267 /* Read Raw Data */
268 if (tdms.segment[tdms.n_segments - 1].lead_in.toc & kTocRawData) {
269 TDMS_ReadRawData(fd, &tdms, tdms.n_segments - 1, tdms.filesize);
270 }
271 }
272 fclose(fd);
273
274 if (querySegments) {
275 fprintf(stdout, "Number of segments: %u\n", tdms.n_segments);
276 return (0);
277 }
278 if (!SDDS_InitializeOutput(&SDDSout, ascii ? SDDS_ASCII : SDDS_BINARY, 1, NULL, NULL, output)) {
279 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
280 return (1);
281 }
282 if (input) {
283 if (SDDS_DefineParameter(&SDDSout, "TDMSfile", NULL, NULL, NULL, NULL, SDDS_STRING, input) == -1) {
284 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
285 return (1);
286 }
287 }
288 if (segment > tdms.n_segments) {
289 fprintf(stderr, "tdms2sdds: Error: segment selected does not exist\n");
290 return (1);
291 } else {
292 segment--;
293 }
294 for (i = 0; i < tdms.n_segments; i++) {
295 if ((segment != -1) && (segment != i)) {
296 continue;
297 }
298 for (j = 0; j < tdms.segment[i].raw_data.n_channels; j++) {
299 if (j == 0) {
300 rows = tdms.segment[i].raw_data.channel[j].n_values;
301 } else {
302 if (rows != tdms.segment[i].raw_data.channel[j].n_values) {
303 fprintf(stderr, "tdms2sdds: Error: channels in the same TDMS segment have different lengths which is not allowed in SDDS\n");
304 return (1);
305 }
306 }
307 }
308 k = 0;
309 for (j = 0; j < tdms.segment[i].meta_data.n_objects; j++) {
310 found = 0;
311 for (n = 0; n < tdms.segment[i].meta_data.object[j].n_properties; n++) {
312 if (strcmp(tdms.segment[i].meta_data.object[j].property[n].name, "NI_ChannelName") == 0) {
313 found = 1;
314 strcpy(buffer, tdms.segment[i].meta_data.object[j].property[n].value);
315 break;
316 }
317 }
318 if (!found) {
319 strcpy(buffer, tdms.segment[i].meta_data.object[j].path);
320 }
321 if (!edit_string(buffer, "1Z/%g/ /_/%ga/a_a%g/\'//%g/(/[/%g/)/]/%g/=/_eq_/")) {
322 fprintf(stderr, "tdms2sdds: Error: problem editing column label\n");
323 return (1);
324 }
325 /* Check for channel name that starts with a number and prepend a semicolon */
326 if (!(isalpha(*buffer) || strchr(".:", *buffer))) {
327 if (!edit_string(buffer, "i/:/")) {
328 fprintf(stderr, "tdms2sdds: Error: problem editing column label\n");
329 return (1);
330 }
331 }
332 strcpy(tdms.segment[i].meta_data.object[j].path, buffer);
333 if (tdms.segment[i].meta_data.object[j].raw_data_index != 0xFFFFFFFF) {
334 tdms.segment[i].raw_data.channel[k].name = tdms.segment[i].meta_data.object[j].path;
335 tdms.segment[i].raw_data.channel[k].datatype = tdms.segment[i].meta_data.object[j].raw_data_datatype;
336 }
337 if (((segment == -1) && (i == 0)) || (segment != -1)) {
338 if (tdms.segment[i].meta_data.object[j].raw_data_index != 0xFFFFFFFF) {
339 if (timeDefined == 0) {
340 if (tdms.segment[i].xpart.samples > 0) {
341 if (tdms.segment[i].xpart.name == NULL) {
342 tdms.segment[i].xpart.name = malloc(5);
343 sprintf(tdms.segment[i].xpart.name, "Time");
344 }
345 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].xpart.name, tdms.segment[i].xpart.unit, SDDS_DOUBLE)) {
346 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
347 return (1);
348 }
349 timeDefined = 1;
350 }
351 }
352 if ((tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeBoolean) ||
353 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeU8) ||
354 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeU16)) {
355 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_USHORT)) {
356 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
357 return (1);
358 }
359 } else if ((tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeI8) ||
360 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeI16)) {
361 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_SHORT)) {
362 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
363 return (1);
364 }
365 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeI32) {
366 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_LONG)) {
367 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
368 return (1);
369 }
370 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeU32) {
371 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_ULONG)) {
372 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
373 return (1);
374 }
375 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeI64) {
376 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_LONG64)) {
377 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
378 return (1);
379 }
380 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeU64) {
381 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_ULONG64)) {
382 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
383 return (1);
384 }
385 } else if ((tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeSingleFloat) ||
386 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeSingleFloatWithUnit)) {
387 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_FLOAT)) {
388 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
389 return (1);
390 }
391 } else if ((tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeDoubleFloat) ||
392 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeDoubleFloatWithUnit) ||
393 (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeTimeStamp)) {
394 if (!SDDS_DefineSimpleColumn(&SDDSout, tdms.segment[i].meta_data.object[j].path, NULL, SDDS_DOUBLE)) {
395 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
396 return (1);
397 }
398 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeString) {
399 fprintf(stderr, "tdms2sdds: string type channels are not yet supported in tdms2sdds\n");
400 return (1);
401 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeVoid) {
402 fprintf(stderr, "tdms2sdds: void type channels are not yet supported in tdms2sdds\n");
403 return (1);
404 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeExtendedFloat) {
405 fprintf(stderr, "tdms2sdds: extended float type channels are not yet supported in tdms2sdds\n");
406 return (1);
407 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeExtendedFloatWithUnit) {
408 fprintf(stderr, "tdms2sdds: extended float with unit type channels are not yet supported in tdms2sdds\n");
409 return (1);
410 } else if (tdms.segment[i].meta_data.object[j].raw_data_datatype == tdsTypeDAQmxRawData) {
411 fprintf(stderr, "tdms2sdds: DAW mx ra data channels are not yet supported in tdms2sdds\n");
412 return (1);
413 } else {
414 fprintf(stderr, "tdms2sdds: unknown data type\n");
415 return (1);
416 }
417 }
418 for (n = 0; n < tdms.segment[i].meta_data.object[j].n_properties; n++) {
419 if (strcmp(tdms.segment[i].meta_data.object[j].property[n].name, "name") == 0) {
420 continue;
421 }
422 strcpy(buffer, tdms.segment[i].meta_data.object[j].property[n].name);
423 if (!edit_string(buffer, "%g/ /_/%g/\'//%g/(/[/%g/)/]/%g/=/_eq_/")) {
424 fprintf(stderr, "tdms2sdds: Error: problem editing column label\n");
425 return (1);
426 }
427 /* Check for channel name that starts with a number and prepend a semicolon */
428 if (!(isalpha(*buffer) || strchr(".:", *buffer))) {
429 if (!edit_string(buffer, "i/:/")) {
430 fprintf(stderr, "tdms2sdds: Error: problem editing column label\n");
431 return (1);
432 }
433 }
434 strcpy(tdms.segment[i].meta_data.object[j].property[n].name, buffer);
435
436 /* Check if additional channels have the same property names. Only include the first */
437 if (SDDS_GetParameterIndex(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name) != -1) {
439 continue;
440 }
441 if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeBoolean) ||
442 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU8) ||
443 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU16)) {
444 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_USHORT)) {
445 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
446 return (1);
447 }
448 } else if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI8) ||
449 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI16)) {
450 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_SHORT)) {
451 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
452 return (1);
453 }
454 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI32) {
455 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_LONG)) {
456 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
457 return (1);
458 }
459 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU32) {
460 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_ULONG)) {
461 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
462 return (1);
463 }
464 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI64) {
465 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_LONG64)) {
466 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
467 return (1);
468 }
469 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU64) {
470 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_ULONG64)) {
471 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
472 return (1);
473 }
474 } else if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeSingleFloat) ||
475 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeSingleFloatWithUnit)) {
476 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_FLOAT)) {
477 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
478 return (1);
479 }
480 } else if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDoubleFloat) ||
481 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDoubleFloatWithUnit) ||
482 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeTimeStamp)) {
483 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_DOUBLE)) {
484 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
485 return (1);
486 }
487 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeString) {
488 if (!SDDS_DefineSimpleParameter(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name, NULL, SDDS_STRING)) {
489 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
490 return (1);
491 }
492 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeVoid) {
493 fprintf(stderr, "tdms2sdds: void type parameters are not yet supported in tdms2sdds\n");
494 return (1);
495 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeExtendedFloat) {
496 fprintf(stderr, "tdms2sdds: extended float type parameters are not yet supported in tdms2sdds\n");
497 return (1);
498 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeExtendedFloatWithUnit) {
499 fprintf(stderr, "tdms2sdds: extended float with unit type parameters are not yet supported in tdms2sdds\n");
500 return (1);
501 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDAQmxRawData) {
502 fprintf(stderr, "tdms2sdds: DAW mx ra data parameters are not yet supported in tdms2sdds\n");
503 return (1);
504 } else {
505 fprintf(stderr, "tdms2sdds: unknown data type\n");
506 return (1);
507 }
508 }
509 }
510 if (tdms.segment[i].meta_data.object[j].raw_data_index != 0xFFFFFFFF) {
511 k++;
512 }
513 }
514 if (((segment == -1) && (i == 0)) || (segment != -1)) {
515 if (!SDDS_WriteLayout(&SDDSout)) {
516 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
517 return (1);
518 }
519 }
520 if (!SDDS_StartTable(&SDDSout, rows)) {
521 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
522 return (1);
523 }
524
525 if ((tdms.segment[i].xpart.name != NULL) &&
526 (tdms.segment[i].xpart.samples > 0) &&
527 (tdms.segment[i].raw_data.n_channels > 0)) {
528 timeValue = tdms.segment[i].xpart.start_time + tdms.segment[i].xpart.start_offset;
529 for (j = 0; j < rows; j++) {
530 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, j, tdms.segment[i].xpart.name, (double)timeValue, NULL)) {
531 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
532 return (1);
533 }
534 timeValue += tdms.segment[i].xpart.increment;
535 }
536 }
537 for (j = 0; j < tdms.segment[i].raw_data.n_channels; j++) {
538 if ((tdms.segment[i].raw_data.channel[j].datatype == tdsTypeI16) ||
539 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeU16) ||
540 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeI32) ||
541 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeU32) ||
542 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeI64) ||
543 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeU64) ||
544 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeSingleFloat) ||
545 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeSingleFloatWithUnit) ||
546 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeDoubleFloat) ||
547 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeDoubleFloatWithUnit) ||
548 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeTimeStamp)) {
549 if (!SDDS_SetColumn(&SDDSout, SDDS_SET_BY_NAME, tdms.segment[i].raw_data.channel[j].values,
550 tdms.segment[i].raw_data.channel[j].n_values, tdms.segment[i].raw_data.channel[j].name)) {
551 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
552 return (1);
553 }
554 } else if ((tdms.segment[i].raw_data.channel[j].datatype == tdsTypeBoolean) ||
555 (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeI8)) {
556 for (k = 0; k < rows; k++) {
557 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, k,
558 tdms.segment[i].raw_data.channel[j].name,
559 (int16_t)(((int8_t *)(tdms.segment[i].raw_data.channel[j].values))[k]), NULL)) {
560 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
561 return (1);
562 }
563 }
564 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeU8) {
565 for (k = 0; k < rows; k++) {
566 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, k,
567 tdms.segment[i].raw_data.channel[j].name,
568 (uint16_t)(((uint8_t *)(tdms.segment[i].raw_data.channel[j].values))[k]), NULL)) {
569 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
570 return (1);
571 }
572 }
573 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeString) {
574 fprintf(stderr, "tdms2sdds: string type channels are not yet supported in tdms2sdds\n");
575 return (1);
576 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeVoid) {
577 fprintf(stderr, "tdms2sdds: void type channels are not yet supported in tdms2sdds\n");
578 return (1);
579 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeExtendedFloat) {
580 fprintf(stderr, "tdms2sdds: extended float type channels are not yet supported in tdms2sdds\n");
581 return (1);
582 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeExtendedFloatWithUnit) {
583 fprintf(stderr, "tdms2sdds: extended float with unit type channels are not yet supported in tdms2sdds\n");
584 return (1);
585 } else if (tdms.segment[i].raw_data.channel[j].datatype == tdsTypeDAQmxRawData) {
586 fprintf(stderr, "tdms2sdds: DAW mx ra data channels are not yet supported in tdms2sdds\n");
587 return (1);
588 } else {
589 fprintf(stderr, "tdms2sdds: unknown data type\n");
590 return (1);
591 }
592 }
593
594 for (j = 0; j < tdms.segment[i].meta_data.n_objects; j++) {
595 for (n = 0; n < tdms.segment[i].meta_data.object[j].n_properties; n++) {
596 /* Do not write parameter if it wasn't defined in the first segment */
597 if (SDDS_GetParameterIndex(&SDDSout, tdms.segment[i].meta_data.object[j].property[n].name) == -1) {
599 continue;
600 }
601 if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI16) ||
602 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU16) ||
603 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI32) ||
604 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU32) ||
605 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI64) ||
606 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU64) ||
607 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeSingleFloat) ||
608 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeSingleFloatWithUnit) ||
609 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDoubleFloat) ||
610 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDoubleFloatWithUnit) ||
611 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeTimeStamp)) {
612 if (!SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, tdms.segment[i].meta_data.object[j].property[n].name, tdms.segment[i].meta_data.object[j].property[n].value, NULL)) {
613 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
614 return (1);
615 }
616 } else if ((tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeBoolean) ||
617 (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeI8)) {
618 if (!SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, tdms.segment[i].meta_data.object[j].property[n].name, (int16_t)(*(int8_t *)(tdms.segment[i].meta_data.object[j].property[n].value)), NULL)) {
619 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
620 return (1);
621 }
622 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeU8) {
623 if (!SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, tdms.segment[i].meta_data.object[j].property[n].name, (uint16_t)(*(uint8_t *)(tdms.segment[i].meta_data.object[j].property[n].value)), NULL)) {
624 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
625 return (1);
626 }
627 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeString) {
628 if (!SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, tdms.segment[i].meta_data.object[j].property[n].name, tdms.segment[i].meta_data.object[j].property[n].value, NULL)) {
629 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
630 return (1);
631 }
632 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeVoid) {
633 fprintf(stderr, "tdms2sdds: void type parameters are not yet supported in tdms2sdds\n");
634 return (1);
635 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeExtendedFloat) {
636 fprintf(stderr, "tdms2sdds: extended float type parameters are not yet supported in tdms2sdds\n");
637 return (1);
638 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeExtendedFloatWithUnit) {
639 fprintf(stderr, "tdms2sdds: extended float with unit type parameters are not yet supported in tdms2sdds\n");
640 return (1);
641 } else if (tdms.segment[i].meta_data.object[j].property[n].datatype == tdsTypeDAQmxRawData) {
642 fprintf(stderr, "tdms2sdds: DAW mx ra data parameters are not yet supported in tdms2sdds\n");
643 return (1);
644 } else {
645 fprintf(stderr, "tdms2sdds: unknown data type\n");
646 return (1);
647 }
648 }
649 }
650 if (!SDDS_WriteTable(&SDDSout)) {
651 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
652 return (1);
653 }
654 }
655 if (!SDDS_Terminate(&SDDSout)) {
656 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
657 return (1);
658 }
659
660 if (tdms.n_segments > 0) {
661 for (i = 0; i < tdms.n_segments; i++) {
662 if (tdms.segment[i].raw_data.n_channels > 0) {
663 for (j = 0; j < tdms.segment[i].raw_data.n_channels; j++) {
664 if (tdms.segment[i].raw_data.channel[j].n_values > 0) {
665 free(tdms.segment[i].raw_data.channel[j].values);
666 }
667 }
668 free(tdms.segment[i].raw_data.channel);
669 }
670 if (tdms.segment[i].meta_data.n_objects > 0) {
671 for (j = 0; j < tdms.segment[i].meta_data.n_objects; j++) {
672 if (tdms.segment[i].meta_data.object[j].path) {
673 free(tdms.segment[i].meta_data.object[j].path);
674 }
675 if (tdms.segment[i].meta_data.object[j].n_properties > 0) {
676 for (k = 0; k < tdms.segment[i].meta_data.object[j].n_properties; k++) {
677 if (tdms.segment[i].meta_data.object[j].property[k].name) {
678 for (ii = i + 1; ii < tdms.n_segments; ii++) {
679 for (jj = 0; jj < tdms.segment[ii].meta_data.n_objects; jj++) {
680 for (kk = 0; kk < tdms.segment[ii].meta_data.object[jj].n_properties; kk++) {
681 if (tdms.segment[i].meta_data.object[j].property[k].name == tdms.segment[ii].meta_data.object[jj].property[kk].name) {
682 tdms.segment[ii].meta_data.object[jj].property[kk].name = NULL;
683 tdms.segment[ii].meta_data.object[jj].property[kk].value = NULL;
684 }
685 }
686 }
687 }
688 free(tdms.segment[i].meta_data.object[j].property[k].name);
689 tdms.segment[i].meta_data.object[j].property[k].name = NULL;
690 }
691 if (tdms.segment[i].meta_data.object[j].property[k].value) {
692 free(tdms.segment[i].meta_data.object[j].property[k].value);
693 tdms.segment[i].meta_data.object[j].property[k].value = NULL;
694 }
695 }
696 free(tdms.segment[i].meta_data.object[j].property);
697 }
698 }
699 free(tdms.segment[i].meta_data.object);
700 }
701 }
702 free(tdms.segment);
703 }
704
705 free_scanargs(&scanned, argc);
706
707 return (0);
708}
709
710void TDMS_ReadLeadIn(FILE *fd, TDMS_SEGMENT *segment) {
711 char buffer[50];
712
713 fread(buffer, 1, 4, fd);
714 buffer[4] = '\0';
715 if (strcmp(buffer, "TDSm") != 0) {
716 fprintf(stderr, "tdms2sdds: Error: File does not start with TDSm\n");
717 exit(1);
718 }
719 fread(&(segment->lead_in.toc), 1, 4, fd); /* TOC */
720 fread(&(segment->lead_in.version), 1, 4, fd); /* Version */
721 if (segment->lead_in.version == 4712) {
722 fprintf(stderr, "tdms2sdds: Error: TDMS version 1.0 files unsupported\n");
723 exit(1);
724 }
725 if (segment->lead_in.version != 4713) {
726 fprintf(stderr, "tdms2sdds: Error: Unknown TDMS version\n");
727 exit(1);
728 }
729 fread(&(segment->lead_in.next_segment_offset), 1, 8, fd); /* Next segment offset */
730 fread(&(segment->lead_in.raw_data_offset), 1, 8, fd); /* Raw data offset */
731}
732
733void TDMS_ReadMetaData(FILE *fd, TDMS_SEGMENT *segment) {
734 uint32_t uLong, i, j;
735
736 segment->xpart.name = NULL;
737 segment->xpart.unit = NULL;
738 segment->xpart.start_time = 0;
739 segment->xpart.start_offset = 0;
740 segment->xpart.increment = 0;
741 segment->xpart.samples = 0;
742 segment->xpart.time_pref = NULL;
743 segment->xpart.range = 0;
744
745 fread(&(segment->meta_data.n_objects), 1, 4, fd);
746
747 segment->meta_data.object = malloc(sizeof(TDMS_META_DATA_OBJECT) * segment->meta_data.n_objects);
748 for (i = 0; i < segment->meta_data.n_objects; i++) {
749 fread(&uLong, 1, 4, fd);
750 segment->meta_data.object[i].path = malloc(sizeof(char) * (uLong + 1));
751 fread(segment->meta_data.object[i].path, 1, uLong, fd);
752 segment->meta_data.object[i].path[uLong] = '\0';
753 fread(&(segment->meta_data.object[i].raw_data_index), 1, 4, fd);
754 if ((segment->meta_data.object[i].raw_data_index != 0xFFFFFFFF) && (segment->meta_data.object[i].raw_data_index != 0x00000000)) {
755 fread(&(segment->meta_data.object[i].raw_data_datatype), 1, 4, fd);
756 fread(&(segment->meta_data.object[i].raw_data_dimensions), 1, 4, fd);
757 fread(&(segment->meta_data.object[i].raw_data_count), 1, 8, fd);
758 if (segment->meta_data.object[i].raw_data_datatype == tdsTypeString) {
759 fread(&(segment->meta_data.object[i].raw_data_total_size), 1, 8, fd);
760 }
761 }
762 fread(&(segment->meta_data.object[i].n_properties), 1, 4, fd);
763 segment->meta_data.object[i].property = malloc(sizeof(TDMS_META_DATA_OBJECT_PROPERTY) * segment->meta_data.object[i].n_properties);
764 for (j = 0; j < segment->meta_data.object[i].n_properties; j++) {
765 fread(&uLong, 1, 4, fd);
766 segment->meta_data.object[i].property[j].name = malloc(sizeof(char) * (uLong + 1));
767 fread(segment->meta_data.object[i].property[j].name, 1, uLong, fd);
768 segment->meta_data.object[i].property[j].name[uLong] = '\0';
769 fread(&(segment->meta_data.object[i].property[j].datatype), 1, 4, fd);
770 if (segment->meta_data.object[i].property[j].datatype == tdsTypeString) {
771 fread(&uLong, 1, 4, fd);
772 segment->meta_data.object[i].property[j].value = malloc(sizeof(char) * (uLong + 1));
773 fread(segment->meta_data.object[i].property[j].value, 1, uLong, fd);
774 ((char *)(segment->meta_data.object[i].property[j].value))[uLong] = '\0';
775 } else {
776 TDMS_GetValue(fd, &(segment->meta_data.object[i].property[j].value), segment->meta_data.object[i].property[j].datatype);
777 }
778 /* check for waveform channel properties */
779 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_xname") == 0) {
780 segment->xpart.name = segment->meta_data.object[i].property[j].value;
781 }
782 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_xunit_string") == 0) {
783 segment->xpart.unit = segment->meta_data.object[i].property[j].value;
784 }
785 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_start_time") == 0) {
786 segment->xpart.start_time = *(double *)(segment->meta_data.object[i].property[j].value);
787 }
788 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_start_offset") == 0) {
789 segment->xpart.start_offset = *(double *)(segment->meta_data.object[i].property[j].value);
790 }
791 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_increment") == 0) {
792 segment->xpart.increment = *(double *)(segment->meta_data.object[i].property[j].value);
793 }
794 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_samples") == 0) {
795 segment->xpart.samples = *(int32_t *)(segment->meta_data.object[i].property[j].value);
796 }
797 if (strcmp(segment->meta_data.object[i].property[j].name, "wf_time_pref") == 0) {
798 segment->xpart.time_pref = segment->meta_data.object[i].property[j].value;
799 }
800 }
801 }
802}
803
804void TDMS_ReadRawData(FILE *fd, TDMS_FILE *tdms, uint32_t n_segment, long filesize) {
805 uint32_t i, j, k, n, p, a;
806 uint32_t channel_size;
807 uint32_t chunk_size = 0;
808 uint32_t total_chunks;
809 uint32_t n_chunks;
810 uint32_t chunk;
811 int64_t LLong;
812 uint64_t uLLong;
813 int prevFound = 0;
814 TDMS_SEGMENT *segment = &((*tdms).segment[n_segment]);
815
816 segment->raw_data.n_channels = 0;
817 for (i = 0; i < segment->meta_data.n_objects; i++) {
818 if (segment->meta_data.object[i].raw_data_index != 0xFFFFFFFF) {
819 if (segment->meta_data.object[i].raw_data_index == 0x00000000) {
820 /* An object with this name already exists in the previous segment.
821 Copy over meta data */
822 prevFound = 0;
823 a = 0;
824 while (prevFound == 0) {
825 a++;
826 if (a > n_segment) {
827 fprintf(stderr, "tdms2sdds: Error: unable to find %s in a previous segment.\n", segment->meta_data.object[i].path);
828 exit(1);
829 }
830 for (n = 0; n < (*tdms).segment[n_segment - a].meta_data.n_objects; n++) {
831 if (strcmp((*tdms).segment[n_segment - a].meta_data.object[n].path, segment->meta_data.object[i].path) == 0) {
832 prevFound = 1;
833 segment->meta_data.object[i].raw_data_datatype = (*tdms).segment[n_segment - a].meta_data.object[n].raw_data_datatype;
834 segment->meta_data.object[i].raw_data_dimensions = (*tdms).segment[n_segment - a].meta_data.object[n].raw_data_dimensions;
835 segment->meta_data.object[i].raw_data_count = (*tdms).segment[n_segment - a].meta_data.object[n].raw_data_count;
836 if (segment->meta_data.object[i].raw_data_datatype == tdsTypeString) {
837 segment->meta_data.object[i].raw_data_total_size = (*tdms).segment[n_segment - a].meta_data.object[n].raw_data_total_size;
838 }
839
840 /* Copy over previous properties excluding any that were overwritten */
841 /* There will be errors if new properties are inserted after the first segment in the TDMS file */
842 for (j = 0; j < (*tdms).segment[n_segment - a].meta_data.object[n].n_properties; j++) {
843 for (k = 0; k < segment->meta_data.object[i].n_properties; k++) {
844 if (strcmp((*tdms).segment[n_segment - a].meta_data.object[n].property[j].name, segment->meta_data.object[i].property[k].name) == 0) {
845 break;
846 }
847 }
848 p = segment->meta_data.object[i].n_properties;
849 segment->meta_data.object[i].n_properties++;
850 segment->meta_data.object[i].property = realloc(segment->meta_data.object[i].property, sizeof(TDMS_META_DATA_OBJECT_PROPERTY) * segment->meta_data.object[i].n_properties);
851 segment->meta_data.object[i].property[p].name = (*tdms).segment[n_segment - a].meta_data.object[n].property[j].name;
852 segment->meta_data.object[i].property[p].datatype = (*tdms).segment[n_segment - a].meta_data.object[n].property[j].datatype;
853 segment->meta_data.object[i].property[p].value = (*tdms).segment[n_segment - a].meta_data.object[n].property[j].value;
854 /* check for waveform channel properties */
855 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_xname") == 0) {
856 segment->xpart.name = segment->meta_data.object[i].property[p].value;
857 }
858 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_xunit_string") == 0) {
859 segment->xpart.unit = segment->meta_data.object[i].property[p].value;
860 }
861 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_start_time") == 0) {
862 segment->xpart.start_time = *(double *)(segment->meta_data.object[i].property[p].value);
863 }
864 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_start_offset") == 0) {
865 segment->xpart.start_offset = *(double *)(segment->meta_data.object[i].property[p].value);
866 segment->xpart.start_offset += (*tdms).segment[n_segment - a].xpart.range;
867 /*put code here */
868 }
869 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_increment") == 0) {
870 segment->xpart.increment = *(double *)(segment->meta_data.object[i].property[p].value);
871 }
872 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_samples") == 0) {
873 segment->xpart.samples = *(int32_t *)(segment->meta_data.object[i].property[p].value);
874 }
875 if (strcmp(segment->meta_data.object[i].property[p].name, "wf_time_pref") == 0) {
876 segment->xpart.time_pref = segment->meta_data.object[i].property[p].value;
877 }
878 }
879 }
880 }
881 }
882 }
883
884 segment->raw_data.n_channels++;
885 if (segment->meta_data.object[i].raw_data_dimensions != 1) {
886 fprintf(stderr, "tdms2sdds: Error: raw data dimension is %d and should have been 1.\n", segment->meta_data.object[i].raw_data_dimensions);
887 exit(1);
888 }
889 if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI8) ||
890 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU8) ||
891 (segment->meta_data.object[i].raw_data_datatype == tdsTypeBoolean)) {
892 channel_size = 1 * segment->meta_data.object[i].raw_data_dimensions * segment->meta_data.object[i].raw_data_count;
893 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI16) ||
894 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU16)) {
895 channel_size = 2 * segment->meta_data.object[i].raw_data_dimensions * segment->meta_data.object[i].raw_data_count;
896 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI32) ||
897 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU32) ||
898 (segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloat) ||
899 (segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloatWithUnit)) {
900 channel_size = 4 * segment->meta_data.object[i].raw_data_dimensions * segment->meta_data.object[i].raw_data_count;
901 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI64) ||
902 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU64) ||
903 (segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloat) ||
904 (segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloatWithUnit)) {
905 channel_size = 8 * segment->meta_data.object[i].raw_data_dimensions * segment->meta_data.object[i].raw_data_count;
906 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeTimeStamp) {
907 channel_size = 16 * segment->meta_data.object[i].raw_data_dimensions * segment->meta_data.object[i].raw_data_count;
908 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeString) {
909 fprintf(stderr, "tdms2sdds: string type channels are not yet supported in tdms2sdds\n");
910 exit(1);
911 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeVoid) {
912 fprintf(stderr, "tdms2sdds: void type channels are not yet supported in tdms2sdds\n");
913 exit(1);
914 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloat) {
915 fprintf(stderr, "tdms2sdds: extended float type channels are not yet supported in tdms2sdds\n");
916 exit(1);
917 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloatWithUnit) {
918 fprintf(stderr, "tdms2sdds: extended float type with unit channels are not yet supported in tdms2sdds\n");
919 exit(1);
920 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeDAQmxRawData) {
921 fprintf(stderr, "tdms2sdds: extended DAQ mx raw data channels are not yet supported in tdms2sdds\n");
922 exit(1);
923 } else {
924 fprintf(stderr, "tdms2sdds: unknown data type\n");
925 exit(1);
926 }
927 chunk_size += channel_size;
928 }
929 }
930
931 if (segment->lead_in.next_segment_offset == -1) {
932 if (filesize == -1) {
933 fprintf(stderr, "tdms2sdds: Error: cannot calculate file size because you are using stdin\n");
934 exit(1);
935 }
936 segment->lead_in.next_segment_offset = filesize;
937 }
938 total_chunks = segment->lead_in.next_segment_offset - segment->lead_in.raw_data_offset;
939 n_chunks = total_chunks / chunk_size;
940
941 segment->raw_data.channel = malloc(sizeof(TDMS_RAW_DATA_CHANNEL) * segment->raw_data.n_channels);
942
943 if (segment->lead_in.toc & kTocInterleavedData) {
944 fprintf(stderr, "tdms2sdds does not yet support interleaved data\n");
945 exit(1);
946 } else {
947 j = 0;
948 for (i = 0; i < segment->meta_data.n_objects; i++) {
949 if (segment->meta_data.object[i].raw_data_index != 0xFFFFFFFF) {
950 segment->xpart.range = segment->xpart.increment * segment->meta_data.object[i].raw_data_count * n_chunks;
951
952 if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI8) ||
953 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU8) ||
954 (segment->meta_data.object[i].raw_data_datatype == tdsTypeBoolean)) {
955 segment->raw_data.channel[j].values = malloc(1 * segment->meta_data.object[i].raw_data_count * n_chunks);
956 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI16) ||
957 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU16)) {
958 segment->raw_data.channel[j].values = malloc(2 * segment->meta_data.object[i].raw_data_count * n_chunks);
959 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI32) ||
960 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU32) ||
961 (segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloat) ||
962 (segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloatWithUnit)) {
963 segment->raw_data.channel[j].values = malloc(4 * segment->meta_data.object[i].raw_data_count * n_chunks);
964 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeI64) ||
965 (segment->meta_data.object[i].raw_data_datatype == tdsTypeU64) ||
966 (segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloat) ||
967 (segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloatWithUnit)) {
968 segment->raw_data.channel[j].values = malloc(8 * segment->meta_data.object[i].raw_data_count * n_chunks);
969 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeTimeStamp) {
970 /* This is converted into a double value */
971 segment->raw_data.channel[j].values = malloc(8 * segment->meta_data.object[i].raw_data_count * n_chunks);
972 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeString) {
973 fprintf(stderr, "tdms2sdds: string type channels are not yet supported in tdms2sdds\n");
974 exit(1);
975 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeVoid) {
976 fprintf(stderr, "tdms2sdds: void type channels are not yet supported in tdms2sdds\n");
977 exit(1);
978 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloat) {
979 fprintf(stderr, "tdms2sdds: extended float type channels are not yet supported in tdms2sdds\n");
980 exit(1);
981 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloatWithUnit) {
982 fprintf(stderr, "tdms2sdds: extended float type with unit channels are not yet supported in tdms2sdds\n");
983 exit(1);
984 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeDAQmxRawData) {
985 fprintf(stderr, "tdms2sdds: extended DAQ mx raw data channels are not yet supported in tdms2sdds\n");
986 exit(1);
987 } else {
988 fprintf(stderr, "tdms2sdds: unknown data type\n");
989 exit(1);
990 }
991 segment->raw_data.channel[j].n_values = segment->meta_data.object[i].raw_data_count * n_chunks;
992 j++;
993 }
994 }
995 for (chunk = 0; chunk < n_chunks; chunk++) {
996 j = 0;
997 for (i = 0; i < segment->meta_data.n_objects; i++) {
998 if (segment->meta_data.object[i].raw_data_index != 0xFFFFFFFF) {
999 if (segment->meta_data.object[i].raw_data_datatype == tdsTypeBoolean) {
1000 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1001 fread(&(((int8_t *)(segment->raw_data.channel[j].values))[k]), 1, 1, fd);
1002 }
1003 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeI8) {
1004 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1005 fread(&(((int8_t *)(segment->raw_data.channel[j].values))[k]), 1, 1, fd);
1006 }
1007 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeU8) {
1008 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1009 fread(&(((uint8_t *)(segment->raw_data.channel[j].values))[k]), 1, 1, fd);
1010 }
1011 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeI16) {
1012 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1013 fread(&(((int16_t *)(segment->raw_data.channel[j].values))[k]), 1, 2, fd);
1014 }
1015 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeU16) {
1016 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1017 fread(&(((uint16_t *)(segment->raw_data.channel[j].values))[k]), 1, 2, fd);
1018 }
1019 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeI32) {
1020 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1021 fread(&(((int32_t *)(segment->raw_data.channel[j].values))[k]), 1, 4, fd);
1022 }
1023 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeU32) {
1024 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1025 fread(&(((uint32_t *)(segment->raw_data.channel[j].values))[k]), 1, 4, fd);
1026 }
1027 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeI64) {
1028 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1029 fread(&(((int64_t *)(segment->raw_data.channel[j].values))[k]), 1, 8, fd);
1030 }
1031 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeU64) {
1032 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1033 fread(&(((uint64_t *)(segment->raw_data.channel[j].values))[k]), 1, 8, fd);
1034 }
1035 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloat) || (segment->meta_data.object[i].raw_data_datatype == tdsTypeSingleFloatWithUnit)) {
1036 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1037 fread(&(((float *)(segment->raw_data.channel[j].values))[k]), 1, 4, fd);
1038 }
1039 } else if ((segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloat) || (segment->meta_data.object[i].raw_data_datatype == tdsTypeDoubleFloatWithUnit)) {
1040 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1041 fread(&(((double *)(segment->raw_data.channel[j].values))[k]), 1, 8, fd);
1042 }
1043 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeTimeStamp) {
1044 for (k = chunk * segment->meta_data.object[i].raw_data_count; k < (chunk + 1) * segment->meta_data.object[i].raw_data_count; k++) {
1045 fread(&uLLong, 1, 8, fd);
1046 fread(&LLong, 1, 8, fd);
1047 /*LLong = LLong - 2082844791LL; */ /* Subtract seconds between 1904 and 1970 */
1048 segment->raw_data.channel[j].values[k] = LLong + (uLLong * 5.42101086242752217e-20);
1049 }
1050 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeString) {
1051 fprintf(stderr, "tdms2sdds: string type channels are not yet supported in tdms2sdds\n");
1052 exit(1);
1053 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeVoid) {
1054 fprintf(stderr, "tdms2sdds: void type channels are not yet supported in tdms2sdds\n");
1055 exit(1);
1056 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloat) {
1057 fprintf(stderr, "tdms2sdds: extended float type channels are not yet supported in tdms2sdds\n");
1058 exit(1);
1059 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeExtendedFloatWithUnit) {
1060 fprintf(stderr, "tdms2sdds: extended float type with unit channels are not yet supported in tdms2sdds\n");
1061 exit(1);
1062 } else if (segment->meta_data.object[i].raw_data_datatype == tdsTypeDAQmxRawData) {
1063 fprintf(stderr, "tdms2sdds: extended DAQ mx raw data channels are not yet supported in tdms2sdds\n");
1064 exit(1);
1065 } else {
1066 fprintf(stderr, "tdms2sdds: unknown data type\n");
1067 exit(1);
1068 }
1069 j++;
1070 }
1071 }
1072 }
1073 }
1074}
1075
1076void TDMS_GetValue(FILE *fd, void **value, int32_t datatype) {
1077 uint64_t uLLong;
1078 int64_t LLong;
1079
1080 if (datatype == tdsTypeI8) {
1081 *value = malloc(sizeof(int8_t));
1082 fread(((int8_t *)(*value)), 1, 1, fd);
1083 } else if (datatype == tdsTypeU8) {
1084 *value = malloc(sizeof(uint8_t));
1085 fread(((uint8_t *)(*value)), 1, 1, fd);
1086 } else if (datatype == tdsTypeI16) {
1087 *value = malloc(sizeof(int16_t));
1088 fread(((int16_t *)(*value)), 1, 2, fd);
1089 } else if (datatype == tdsTypeU16) {
1090 *value = malloc(sizeof(uint16_t));
1091 fread(((uint16_t *)(*value)), 1, 2, fd);
1092 } else if (datatype == tdsTypeI32) {
1093 *value = malloc(sizeof(int32_t));
1094 fread(((int32_t *)(*value)), 1, 4, fd);
1095 } else if (datatype == tdsTypeU32) {
1096 *value = malloc(sizeof(uint32_t));
1097 fread(((uint32_t *)(*value)), 1, 4, fd);
1098 } else if (datatype == tdsTypeI64) {
1099 *value = malloc(sizeof(int64_t));
1100 fread(((int64_t *)(*value)), 1, 8, fd);
1101 } else if (datatype == tdsTypeU64) {
1102 *value = malloc(sizeof(uint64_t));
1103 fread(((uint64_t *)(*value)), 1, 8, fd);
1104 } else if ((datatype == tdsTypeSingleFloat) || (datatype == tdsTypeSingleFloatWithUnit)) {
1105 *value = malloc(sizeof(float));
1106 fread(((float *)(*value)), 1, 4, fd);
1107 } else if ((datatype == tdsTypeDoubleFloat) || (datatype == tdsTypeDoubleFloatWithUnit)) {
1108 *value = malloc(sizeof(double));
1109 fread(((double *)(*value)), 1, 8, fd);
1110 } else if (datatype == tdsTypeBoolean) {
1111 *value = malloc(sizeof(int8_t));
1112 fread(((int8_t *)(*value)), 1, 1, fd);
1113 } else if (datatype == tdsTypeTimeStamp) {
1114 *value = malloc(sizeof(double));
1115 fread(&uLLong, 1, 8, fd);
1116 fread(&LLong, 1, 8, fd);
1117 /*LLong = LLong - 2082844791LL; */ /* Subtract seconds between 1904 and 1970 */
1118 *((double *)(*value)) = LLong + (uLLong * 5.42101086242752217e-20);
1119 } else if (datatype == tdsTypeVoid) {
1120 fprintf(stderr, "tdms2sdds: datatype Void is not yet supported in tdms2sdds\n");
1121 exit(1);
1122 } else if (datatype == tdsTypeExtendedFloat) {
1123 fprintf(stderr, "tdms2sdds: datatype ExtendedFloat is not yet supported in tdms2sdds\n");
1124 exit(1);
1125 } else if (datatype == tdsTypeExtendedFloatWithUnit) {
1126 fprintf(stderr, "tdms2sdds: datatype ExtendedFloatWithUnit is not yet supported in tdms2sdds\n");
1127 exit(1);
1128 } else if (datatype == tdsTypeDAQmxRawData) {
1129 fprintf(stderr, "tdms2sdds: datatype DAQmxRawData is not yet supported in tdms2sdds\n");
1130 exit(1);
1131 } else {
1132 fprintf(stderr, "tdms2sdds: unknown data type\n");
1133 exit(1);
1134 }
1135}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_DefineSimpleParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data parameter within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:318
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
long fexists(const char *filename)
Checks if a file exists.
Definition fexists.c:27
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584