1 /*
2
3 Copyright (C) 2010-2019 Alois Schloegl <alois.schloegl@ist.ac.at>
4
5 This file is part of the "BioSig for C/C++" repository
6 (biosig4c++) at http://biosig.sf.net/
7
8 BioSig is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 3
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21 References:
22 [1] TDMS File Format Internal Structure, Publish Date: Jun 23, 2014
23 NI-Tutorial-5696-en.pdf downloaded from ni.com
24 [2] npTDMS package for python
25 https://github.com/adamreeve/npTDMS.git
26
27 */
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <stddef.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "../biosig-dev.h"
35
36 typedef struct {
37 uint32_t TDMSCONST;
38 uint32_t toc_mask;
39 uint32_t version;
40 uint64_t nextSegmentOffset;
41 uint64_t rawDataOffset;
42 uint32_t numObjects;
43 size_t data_position;
44 size_t size;
45 } __attribute__((aligned(4),packed)) tdms_segment_t;
46 #define LEAD_SIZE 28
47
48 #define kTocMetaData (1L<<1)
49 #define kTocRawData (1L<<3)
50 #define kTocDAQmxRawData (1L<<7)
51 #define kTocInterleavedData (1L<<5)
52 #define kTocBigEndian (1L<<6)
53 #define kTocNewObjList (1L<<2)
54
55 typedef enum {
56 tdsTypeVoid,
57 tdsTypeI8,
58 tdsTypeI16,
59 tdsTypeI32,
60 tdsTypeI64,
61 tdsTypeU8,
62 tdsTypeU16,
63 tdsTypeU32,
64 tdsTypeU64,
65 tdsTypeSingleFloat,
66 tdsTypeDoubleFloat,
67 tdsTypeExtendedFloat,
68 tdsTypeSingleFloatWithUnit=0x19,
69 tdsTypeDoubleFloatWithUnit,
70 tdsTypeExtendedFloatWithUnit,
71 tdsTypeString=0x20,
72 tdsTypeBoolean=0x21,
73 tdsTypeTimeStamp=0x44,
74 tdsTypeFixedPoint=0x4F,
75 tdsTypeComplexSingleFloat=0x08000c,
76 tdsTypeComplexDoubleFloat=0x10000d,
77 tdsTypeDAQmxRawData=0xFFFFFFFF
78 } tdsDataType;
79
80
81 /*
82 defines single tdms object
83 */
84 typedef struct {
85 tdsDataType datatype;
86 void *value;
87 char *object_path;
88 } tdms_object_t;
89
90 // define object store
91 typedef struct {
92 size_t numObjects;
93 tdms_object_t *list;
94 } tdms_object_store_t;
95
96 // find element in object store
find_element(tdms_object_store_t * objList,const char * key)97 ssize_t find_element(tdms_object_store_t *objList, const char *key) {
98 for (size_t k=0; k < objList->numObjects; k++) {
99 if (!strcmp(objList->list[k].object_path, key)) return k;
100 }
101 return -1;
102 }
103
104 // add (or replace) element in object store
add_element(tdms_object_store_t * objList,tdms_object_t element)105 void add_element(tdms_object_store_t *objList, tdms_object_t element) {
106 ssize_t idx = find_element(objList, element.object_path);
107 if (idx < 0) {
108 objList->numObjects++;
109 objList->list = realloc(objList->list, objList->numObjects * sizeof(tdms_object_t));
110 idx = objList->numObjects - 1;
111 }
112 memcpy(objList->list+idx, &element, sizeof(tdms_object_t));
113 }
114
115 // read number of objects into object store
read_tdms_objects(tdms_object_store_t O,void * ptr,uint32_t numObj)116 void read_tdms_objects(tdms_object_store_t O, void *ptr, uint32_t numObj) {
117
118 // this function is under construction
119 return;
120
121 tdms_object_t element;
122
123 // skip first 4 bytes, theise contains number of objects
124 uint32_t numberOfObjects = leu32p(ptr);
125 ptr += 4;
126 char *pstr = NULL;
127 for (uint32_t k = 0; k < numObj; k++) {
128 uint32_t plen = leu32p(ptr);
129
130 pstr = realloc(pstr,plen+1);
131 memcpy(pstr, ptr+4, plen);
132 pstr[plen] = 0;
133
134 if (VERBOSE_LEVEL > 8) fprintf(stdout,"%s (line %i): Object %d [%d]<%s>\n",__func__,__LINE__, k, plen, pstr);
135
136 ptr += 4 + plen;
137 uint32_t idx = leu32p(ptr);
138 ptr += 4;
139 uint32_t numberOfProperties = leu32p(ptr);
140 ptr += 4;
141
142 if (VERBOSE_LEVEL>8) fprintf(stdout,"%s (line %i): Object %i/%i <%s> ((%d) has %i properties \n",__func__,__LINE__, k, numberOfObjects, pstr, idx, numberOfProperties);
143 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i/%i path='%s' rawDataIdx=0x%08x\n",__func__,__LINE__, k, numberOfObjects, pstr, idx);
144
145 char *propName = NULL;
146 char *propVal = NULL;
147 for (uint32_t p = 0; p < numberOfProperties; p++) {
148 // property name
149 uint32_t plen = leu32p(ptr);
150 propName = realloc(propName,plen+1);
151 memcpy(propName, ptr+4, plen);
152 propName[plen] = 0;
153 ptr += 4+plen;
154
155 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i/%i <%s>\n",__func__,__LINE__, k, p, numberOfProperties, propName);
156
157 // property type
158 uint32_t propType = leu32p(ptr);
159 ptr += 4;
160
161 // property value
162 int32_t val_i32;
163 switch (propType) {
164 case tdsTypeVoid:
165 case tdsTypeI8:
166 case tdsTypeI16:
167
168 case tdsTypeI32: {
169 // int32
170 int32_t val = lei32p(ptr);
171 ptr += 4;
172 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int32)=%i\n",__func__,__LINE__, k, p,propName,val);
173 break;
174 }
175 case tdsTypeI64:
176 case tdsTypeU8:
177 case tdsTypeU16:
178
179 case tdsTypeU32: {
180 // uint32
181 uint32_t val = leu32p(ptr);
182 ptr += 4;
183 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int32)=%i\n",__func__,__LINE__, k, p,propName,val);
184 break;
185 }
186
187 case tdsTypeU64:
188 case tdsTypeSingleFloat:
189 case tdsTypeDoubleFloat:
190 case tdsTypeExtendedFloat:
191 case tdsTypeSingleFloatWithUnit: // =0x19,
192 case tdsTypeDoubleFloatWithUnit:
193 case tdsTypeExtendedFloatWithUnit:
194
195 case tdsTypeString: // case 0x20:
196 plen = leu32p(ptr);
197 propVal = realloc(propVal,plen+1);
198 memcpy(propVal,ptr+4,plen);
199 propVal[plen]=0;
200 ptr += 4+plen;
201 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(string)=<%s>\n",__func__,__LINE__, k, p,propName, propVal);
202 break;
203
204 case tdsTypeBoolean:
205
206 case tdsTypeTimeStamp: // = 0x44
207 ptr += 4+plen;
208 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(string)=<%s>\n",__func__,__LINE__, k, p,propName, propVal);
209 break;
210
211 case tdsTypeFixedPoint: // 0x4F,
212 case tdsTypeComplexSingleFloat: // =0x08000c,
213 case tdsTypeComplexDoubleFloat: // =0x10000d,
214 case tdsTypeDAQmxRawData: // =0xFFFFFFFF
215
216 default:
217 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %d property %d <%s>type=0x%x not supported. Skip %d bytes\n",__func__,__LINE__, k, p,propName,propType, plen);
218 }
219 }
220
221
222 switch (idx) {
223 case 0xffffffff : // no raw data
224 break;
225 case 0x00001269 : // DAQmx Format Changing scaler
226 break;
227 case 0x00001369 : // DAQmx Digital Line scaler
228 break;
229 case 0x00000000 : //
230 ;
231 }
232 }
233 if (pstr) free(pstr);
234 }
235
236
sopen_tdms_read(HDRTYPE * hdr)237 EXTERN_C void sopen_tdms_read(HDRTYPE* hdr) {
238 /*
239 this function will be called by the function SOPEN in "biosig.c"
240
241 Input:
242 char* Header // contains the file content
243
244 Output:
245 HDRTYPE *hdr // defines the HDR structure accoring to "biosig.h"
246 */
247
248 // read whole file into memory
249 size_t count = hdr->HeadLen;
250 while (!ifeof(hdr)) {
251 size_t bufsiz = 2*count;
252 hdr->AS.Header = (uint8_t*)realloc(hdr->AS.Header, bufsiz+1);
253 count += ifread(hdr->AS.Header+count, 1, bufsiz-count, hdr);
254 }
255 hdr->AS.Header[count]=0;
256 hdr->HeadLen = count;
257
258 tdms_object_store_t ObjectStore;
259 ObjectStore.numObjects=0;
260 ObjectStore.list=NULL;
261
262 /*
263 Specification obtained from http://www.ni.com/white-paper/5696/en
264 however, there are also TDMS data out there, that is based on an XML header
265 and a separate binary file. This is somewhat confusing.
266 */
267 fprintf(stderr,"%s (line %i): Format TDMS is very experimental\n",__func__,__LINE__);
268
269
270 /***** Lead In *****/
271 int currentSegment = 0;
272 int currentSegmentTableSize = 16;
273
274 // top level comprised of a single object that holds file-specific information like author or title.
275 tdms_segment_t *segTable = malloc(currentSegmentTableSize * sizeof(tdms_segment_t));
276 memcpy(segTable, hdr->AS.Header, LEAD_SIZE+4);
277
278 hdr->FILE.LittleEndian = !(segTable[0].toc_mask & kTocBigEndian);
279 if ( (__BYTE_ORDER == __LITTLE_ENDIAN) != !(segTable[0].toc_mask & kTocBigEndian) ) {
280 segTable[0].version = bswap_32(segTable[0].version);
281 segTable[0].nextSegmentOffset = bswap_64(segTable[0].nextSegmentOffset);
282 segTable[0].rawDataOffset = bswap_64(segTable[0].rawDataOffset);
283 segTable[0].numObjects = bswap_32(segTable[0].numObjects);
284 }
285 segTable[currentSegment].data_position = LEAD_SIZE + segTable[currentSegment].rawDataOffset; // data position
286 segTable[currentSegment].size = (segTable[currentSegment].toc_mask & kTocRawData) ?
287 (segTable[currentSegment].nextSegmentOffset - segTable[currentSegment].rawDataOffset) : 0;
288
289 switch (segTable[0].version) {
290 case 4712: hdr->Version = 1.0; break;
291 case 4713: hdr->Version = 2.0; break;
292 default:
293 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"This version of format TDMS is currently not supported");
294 }
295
296 read_tdms_objects(ObjectStore, hdr->AS.Header+LEAD_SIZE ,segTable[0].numObjects);
297
298 size_t pos = LEAD_SIZE + segTable[currentSegment].nextSegmentOffset;
299
300 // read table of indices for all segments
301 while (++currentSegment) {
302 // manage memory allocation of index table
303 if (currentSegment >= currentSegmentTableSize) {
304 currentSegmentTableSize *= 2;
305 segTable = realloc(segTable, currentSegmentTableSize * sizeof(tdms_segment_t));
306 }
307
308 // read next segment
309 memcpy(segTable + currentSegment, hdr->AS.Header + pos, LEAD_SIZE+4); // copy global, and 1 segment
310 if ( (__BYTE_ORDER == __LITTLE_ENDIAN) != !(segTable[currentSegment].toc_mask & kTocBigEndian) ) {
311 segTable[currentSegment].version = bswap_32(segTable[currentSegment].version);
312 segTable[currentSegment].nextSegmentOffset = bswap_64(segTable[currentSegment].nextSegmentOffset);
313 segTable[currentSegment].rawDataOffset = bswap_64(segTable[currentSegment].rawDataOffset);
314 segTable[currentSegment].numObjects = bswap_32(segTable[currentSegment].numObjects);
315 }
316 segTable[currentSegment].data_position = pos + LEAD_SIZE + segTable[currentSegment].rawDataOffset;
317 segTable[currentSegment].size = (segTable[currentSegment].toc_mask & kTocRawData) ?
318 (segTable[currentSegment].nextSegmentOffset - segTable[currentSegment].rawDataOffset) : -1;
319
320 read_tdms_objects(ObjectStore, hdr->AS.Header+pos+LEAD_SIZE, segTable[currentSegment].numObjects);
321
322 if (segTable[currentSegment].nextSegmentOffset == (uint64_t)(-1LL)) break;
323 if (segTable[currentSegment].nextSegmentOffset == 0) break;
324
325 if (VERBOSE_LEVEL>8) fprintf(stdout,"%s (line %d): %s\n\tLittleEndian=%d\n\tVersion=%d\n\t@beginSeg %ld\n\t@NextSegment %ld\n\t@rawDataOffset %ld\n",__func__,__LINE__, hdr->AS.Header,hdr->FILE.LittleEndian, segTable[currentSegment].version, pos, segTable[currentSegment].nextSegmentOffset, segTable[currentSegment].rawDataOffset);
326
327 pos += LEAD_SIZE + segTable[currentSegment].nextSegmentOffset;
328 }
329
330 if (VERBOSE_LEVEL > 7) {
331 // show index table segTable
332 fprintf(stdout, "#seg\tTMDs\tmask\tver\tnumObj\tnextSegOff\trawDataOffset\tDataPosition\tsize\n");
333 char tmpstr[8]; tmpstr[4]=0;
334 for (int k = 0; k < currentSegment; k++) {
335 memcpy(tmpstr,&segTable[k].TDMSCONST,4);
336 fprintf(stdout, "%d\t%04s\t0x%04x\t%d\t%d\t%9ld\t%9ld\t%9ld\t%ld\n", k,
337 tmpstr, segTable[k].toc_mask, segTable[k].version, segTable[k].numObjects,
338 segTable[k].nextSegmentOffset, segTable[k].rawDataOffset, segTable[k].data_position, segTable[k].size);
339 }
340 }
341
342 uint64_t nextSegmentOffset = leu64p(hdr->AS.Header+12);
343 uint64_t RawDataOffset = leu64p(hdr->AS.Header+20);
344 pos = 28;
345
346 /***** Meta data *****/
347 if (1) {
348 //while (pos<RawDataOffset) {
349 uint32_t numberOfObjects = leu32p(hdr->AS.Header+pos);
350 pos += 4;
351 char *pstr=NULL;
352 for (uint32_t k=0; k < numberOfObjects; k++) {
353 uint32_t plen = leu32p(hdr->AS.Header+pos);
354 if (VERBOSE_LEVEL>8) fprintf(stdout,"%s (line %i): %i %i %i\n",__func__,__LINE__, (int)hdr->HeadLen, (int)pos,plen);
355 pstr = realloc(pstr,plen+1);
356 memcpy(pstr,hdr->AS.Header+pos+4,plen);
357 pstr[plen]=0;
358
359 pos += 4+plen;
360 uint32_t idx = leu32p(hdr->AS.Header+pos);
361 pos += 4;
362 uint32_t numberOfProperties = leu32p(hdr->AS.Header+pos);
363 pos += 4;
364
365 if (VERBOSE_LEVEL>8) fprintf(stdout,"%s (line %i): Object %i/%i <%s> ((%d) has %i properties \n",
366 __func__,__LINE__, k,numberOfObjects,pstr,idx,numberOfProperties);
367
368 char *propName=NULL;
369 char *propVal=NULL;
370 for (uint32_t p=0; p < numberOfProperties; p++) {
371 // property name
372 uint32_t plen = leu32p(hdr->AS.Header+pos);
373 propName = realloc(propName,plen+1);
374 memcpy(propName,hdr->AS.Header+pos+4,plen);
375 propName[plen]=0;
376 pos += 4+plen;
377
378 // property type
379 uint32_t propType = leu32p(hdr->AS.Header+pos);
380 pos += 4;
381
382 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i/%i %d<%s> 0x%08x\n",__func__,__LINE__, k, p, numberOfProperties, plen,propName, propType);
383
384
385 // property value
386 int32_t val_i32;
387 switch (propType) {
388 case tdsTypeVoid:
389 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(void)\n",__func__,__LINE__, k, p,propName);
390 break;
391 case tdsTypeI8: {
392 int8_t val = (int8_t)hdr->AS.Header[pos];
393 pos += 1;
394 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int8)=%i\n",__func__,__LINE__, k, p,propName,val);
395 break;
396 }
397 case tdsTypeI16: {
398 int16_t val = lei16p(hdr->AS.Header+pos);
399 pos += 2;
400 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int16)=%i\n",__func__,__LINE__, k, p,propName,val);
401 break;
402 }
403 case tdsTypeI32: {
404 // int32
405 int32_t val = lei32p(hdr->AS.Header+pos);
406 pos += 4;
407 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int32)=%i\n",__func__,__LINE__, k, p,propName,val);
408 break;
409 }
410 case tdsTypeI64: {
411 // int64
412 int64_t val = lei64p(hdr->AS.Header+pos);
413 pos += 8;
414 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int64)=%ld\n",__func__,__LINE__, k, p,propName,val);
415 break;
416 }
417 case tdsTypeU8: {
418 uint8_t val = (uint8_t)hdr->AS.Header[pos];
419 pos += 1;
420 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(uint8)=%i\n",__func__,__LINE__, k, p,propName,val);
421 break;
422 }
423 case tdsTypeU16: {
424 uint16_t val = leu16p(hdr->AS.Header+pos);
425 pos += 1;
426 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(uint16)=%i\n",__func__,__LINE__, k, p,propName,val);
427 break;
428 }
429
430 case tdsTypeU32: { // case 0x07:
431 // uint32
432 uint32_t val = leu32p(hdr->AS.Header+pos);
433 pos += 4;
434 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(int32)=%i\n",__func__,__LINE__, k, p,propName,val);
435 break;
436 }
437
438 case tdsTypeU64: {
439 // uint64
440 uint64_t val = leu64p(hdr->AS.Header+pos);
441 pos += 8;
442 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(uint64)=%ld\n",__func__,__LINE__, k, p,propName,val);
443 break;
444 }
445 case tdsTypeSingleFloat: {
446 float val = lef32p(hdr->AS.Header+pos);
447 pos += 4;
448 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(float32)=%g\n",__func__,__LINE__, k, p,propName,val);
449 break;
450 }
451 case tdsTypeDoubleFloat: {
452 // double
453 double val = lef64p(hdr->AS.Header+pos);
454 pos += 8;
455 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(float64)=%ld\n",__func__,__LINE__, k, p,propName,val);
456 break;
457 }
458 case tdsTypeExtendedFloat:{
459 // double
460 // double val = lef128p(hdr->AS.Header+pos);
461 pos += 16;
462 break;
463 }
464 case tdsTypeSingleFloatWithUnit: // =0x19,
465 case tdsTypeDoubleFloatWithUnit:
466 case tdsTypeExtendedFloatWithUnit:
467
468 case tdsTypeString: // case 0x20:
469 plen = leu32p(hdr->AS.Header+pos);
470 propVal = realloc(propVal,plen+1);
471 memcpy(propVal,hdr->AS.Header+pos+4,plen);
472 propVal[plen]=0;
473 pos += 4+plen;
474 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(string)=<%s>\n",__func__,__LINE__, k, p,propName, propVal);
475 break;
476
477 case tdsTypeBoolean: {
478 uint8_t val = (uint8_t)hdr->AS.Header[pos];
479 pos += 1;
480 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(boolean)=%i\n",__func__,__LINE__, k, p,propName,val);
481 break;
482 }
483
484 case tdsTypeTimeStamp: { //=0x44
485 // NI Timestamps according to http://www.ni.com/product-documentation/7900/en/
486 int64_t time_seconds = lei64p(hdr->AS.Header+pos);
487 uint64_t time_fraction = leu64p(hdr->AS.Header+pos+8);
488 gdftime_t T0 = ldexp((time_seconds+ldexp(time_fraction,-64))/(24.0*3600.0)+695422,32);
489 pos += 16;
490 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i timestamp %ld %.8g \n",__func__,__LINE__, k, time_seconds, ldexp(time_fraction,-64));
491 break;
492 }
493
494 case tdsTypeFixedPoint: // 0x4F,
495 pos += 8;
496 break;
497
498 case 0x61:
499 //plen = leu32p(hdr->AS.Header+pos);
500 pos += 16;
501 break;
502
503 case tdsTypeComplexSingleFloat: { // =0x08000c,
504 float val[2];
505 val[0] = lef32p(hdr->AS.Header+pos);
506 val[1] = lef32p(hdr->AS.Header+pos);
507 pos += 16;
508 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(float64)=%g + i%h\n",__func__,__LINE__, k, p, propName, val[0], val[1]);
509 break;
510 }
511 case tdsTypeComplexDoubleFloat: {// =0x10000d,
512 double val[2];
513 val[0] = lef64p(hdr->AS.Header+pos);
514 val[1] = lef64p(hdr->AS.Header+pos);
515 pos += 16;
516 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i property %i <%s>(float64)=%g + i%h\n",__func__,__LINE__, k, p, propName, val[0], val[1]);
517 break;
518 }
519 case tdsTypeDAQmxRawData: { // =0xFFFFFFFF
520 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %d property %d <%s>type=0x%x not supported. Skip %d bytes\n",__func__,__LINE__, k, p,propName,propType, plen);
521 break;
522 }
523
524 default:
525 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %d property %d <%s>type=0x%x not supported. Skip %d bytes\n",__func__,__LINE__, k, p,propName,propType, plen);
526 }
527 }
528
529
530 if (VERBOSE_LEVEL>6) fprintf(stdout,"%s (line %i): object %i/%i path='%s' rawDataIdx=0x%08x\n",__func__,__LINE__, k, numberOfObjects, pstr, idx);
531
532 switch (idx) {
533 case 0xffffffff : // no raw data
534 break;
535 case 0x00001269 : // DAQmx Format Changing scaler
536 break;
537 case 0x00001369 : // DAQmx Digital Line scaler
538 break;
539 case 0x00000000 : //
540 ;
541 }
542 }
543 }
544
545 if (segTable) free(segTable);
546 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"Format TDMS is currently not supported");
547 }
548
549