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