ó
m:£Pc           @   sü  d  Z  d d l Z d d l Z e Z i  Z d „  Z i dG d 6dH d 6dI d
 6dJ d 6dK d 6dL d 6Z d d d d d d d d d d d d d d d d  d! d" d# g Z i d d$ 6d  d% 6d! d& 6d" d' 6d# d( 6Z	 i d) d 6d* d 6d+ d 6d, d 6d- d 6d. d 6d/ d 6d0 d 6d1 d 6d2 d 6d3 d 6d4 d 6d4 d 6d4 d 6d4 d 6d4 d  6d* d! 6d4 d" 6d4 d# 6Z
 d5 „  Z d6 „  Z d7 „  Z d8 „  Z d9 „  Z d: „  Z d; „  Z d< „  Z d= „  Z d> „  Z d? „  Z d@ „  Z dA „  Z dB „  Z dC „  Z dD „  Z dE „  Z dF „  Z d S(M   só  


================================================================
                Standalone Python TDMS reader, 
   (not using the NI libraries for they were Windows-specific)
================================================================


based on the format description on
http://zone.ni.com/devzone/cda/tut/p/id/5696



Floris van Vugt
IMMM Hannover
http://florisvanvugt.free.fr/


I am greatly indebted for insightful bug-corrections by:
ADAM REEVE
JUERGEN NEUBAUER, PH.D.

Thanks guys!


iÿÿÿÿNc         C   s0   d j  g  |  D] } d t | ƒ ^ q ƒ j ƒ  S(   sR   
    Convert a byte string to it's hex string representation e.g. for output.
    t    s   %02X (   t   joint   ordt   strip(   t   byteStrt   x(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt	   byteToHex1   s    l    i   t   kTocMetaDatai   t   kTocRawDatai   t   kTocDAQmxRawDatai   t   kTocInterleavedDatai   t   kTocBigEndiani   t   kTocNewObjListt   tdsTypeVoidt	   tdsTypeI8t
   tdsTypeI16t
   tdsTypeI32t
   tdsTypeI64t	   tdsTypeU8t
   tdsTypeU16t
   tdsTypeU32t
   tdsTypeU64t   tdsTypeSingleFloatt   tdsTypeDoubleFloatt   tdsTypeExtendedFloatt   tdsTypeSingleFloatWithUnitt   tdsTypeDoubleFloatWithUnitt   tdsTypeExtendedFloatWithUnitt   tdsTypeStringt   tdsTypeBooleant   tdsTypeTimeStampt   tdsTypeDAQmxRawDatai   i    i!   iD   Iÿÿÿÿ    R    t   bt   ht   lt   qt   Bt   Ht   Lt   Qt   ft   dt    c         C   s<   t  j d |  ƒ d } | t j ƒ  k r0 t | St | Sd S(   s:   
    Find back the data type from
    raw input data.
    s   <Li    N(   t   structt   unpackt   tdsDataTypesDefinedt   keyst   tdsDataTypes(   t   st   repr(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   dataTypeFrom’   s    c         C   st   |  d k r d S|  d k r  d S|  d k r0 d	 S|  d k r@ d S|  d k rP d S|  d  k r` d S|  d! k rp t  Sd S("   sW   
    How many bytes we need to read to
    read in an object of the given datatype
    R   i    R   R   R   i   R   R   i   R   R   R   R   i   R   R   R   R   i   R   i   R   R   R   R   N(   R   (   R   R   R   (   R   R   (   R   R   R   R   (   R   R   R   R   (   R   (   R   R   R   R   (   t   False(   t   datatype(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   dataTypeLengthŸ   s$       	c         C   s   t  |  S(   sƒ   
    Returns the identifier for the given datatype
    that we need to feed into struct.unpack to get
    the right thing out.
    (   t   tdsDataTypesTranscriptions(   R4   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   dataTypeTranscriptionÅ   s    c         C   s`   | d k r8 t  j | d |  ƒ } | d | d d f S| t | ƒ } t  j | |  ƒ d St S(   sI   
    We just read s from the file,
    and now we need to unpack it.
    R   t   Qqi   i    i   iÀÿÿÿg      ð;(   R+   R,   R7   R3   (   R0   t
   endiannessR4   t   tt   code(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   getValueÔ   s    c         C   sæ   |  j  d ƒ } | d k r0 d | f GHt ƒ  n  |  j  d ƒ } t j d | ƒ d } i  } x, t j ƒ  D] } | t | @d k | | <qh W|  j  d ƒ } t j d | ƒ d } |  j  d ƒ } t j d | ƒ \ } } | | | | f S(	   s'   
    Read the lead-in of a segment
    i   t   TDSms2   Error: segment does not start with TDSm, but with s   <ii    i   s   <QQ(   R=   (   t   readt   exitR+   R,   t   tocPropertiesR.   (   R(   R0   t   toct   metadatat   propt   versiont   next_segment_offsett   raw_data_offset(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt
   readLeadIní   s    
c         C   s5  |  j  d ƒ } t j d | ƒ d } |  j  | ƒ } |  j  d ƒ } t j d | ƒ d } | d k rn d
 } n | d k r‡ t | } n„ | } |  j  d ƒ } t | ƒ } |  j  d ƒ } t j d | ƒ d } |  j  d ƒ } t j d | ƒ d }	 | | |	 f } | t | <|  j  d ƒ } t j d | ƒ d }
 i  } xì t d |
 ƒ D]Û } |  j  d ƒ } t j d | ƒ d } |  j  | ƒ } |  j  d ƒ } t | ƒ } d } | d k rä|  j  d ƒ } t j d | ƒ d } |  j  | ƒ } n- t | ƒ } |  j  | ƒ } t | d	 | ƒ } | | f | | <qFW| | | | f S(   s+   
    Read object in the metadata array
    i   s   <Li    Iÿÿÿÿ    i   s   <QR    R   t   <(    (   R>   R+   R,   t   object_rawdataR2   t   rangeR5   R<   (   R(   R0   t   lntht
   objectpatht   rawdataindext   rawdatat
   inf_lengtht   rawdata_datatypet   rawdata_dimt   rawdata_valuest   nPropt
   propertiest   jt   numbt   nameR4   t   valuet   lengtet   nm(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt
   readObject  sT    	
	
c         C   s/   |  } x" | j  ƒ  D] } | | | | <q W| S(   sc   
    Merge the two property lists, using the newprop
    list to overwrite if conflicts arise.
    (   R.   (   RC   t   newpropt   retpropt   k(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   mergeProperties‰  s    c         C   s‡   |  \ } } } } | \ } } } }	 | | k rG d G| G| GHt  ƒ  n  | d k rb | }
 | } n | }
 | } | |
 | t | |	 ƒ f S(   s›   
    Ok, we are given two objects: obj and alt.
    We make all the changes (new values or
    overwriting old values), taking newobj as
    dominant.
    s,   Error: trying to merge non-same objectpaths:Iÿÿÿÿ    i    (   Iÿÿÿÿ    i    (   R?   R_   (   t   objt   newobjRL   RM   RN   RT   t   newobjectpatht   newrawdataindext
   newrawdatat   newpropertiest   retrawdataindext
   retrawdata(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   mergeObject  s    
	c         C   s_   |  } xR | j  ƒ  D]D } | | j  ƒ  k rI t | | | | ƒ | | <q | | | | <q W| S(   sU   
    Return the objects (metadata), but
    add the stuff that is in newobjects.
    (   R.   Rh   (   t   objectst
   newobjectst
   retobjectsR`   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   mergeObjectsÈ  s    c         C   sÈ   |  j  d ƒ } t j d | ƒ d } i  } g  } xŠ t d | ƒ D]y } t |  ƒ } | \ } } }	 }
 t rw d G| GHn  | | j ƒ  k r£ t | | | ƒ | | <qA | | | <| j | ƒ qA W| | f S(   sy  
    Read meta data from file f.
    
    We return (objects,objectorder) where
    objects is the structure containing all information about
    objects, and objectorder is a list of objectpaths (object ID's if you want)
    in the order that they have been presented. We need this
    later when we start reading the raw data, since it then comes
    in this very order.
    i   s   <li    s   Read object(	   R>   R+   R,   RJ   R[   t   verboseR.   Rl   t   append(   R(   R0   t   nObjectsRi   t   objectordert   iR`   RL   RM   RN   RT   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   readMetaDataå  s    
c         C   s   |  \ } } } } | d k S(   s”   
    Tell us whether the given object is a channel
    (in the current segment) and if so, returns
    the meta information about the raw data.
    Iÿÿÿÿ    (    (   R`   t   _RM   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt	   isChannel  s    c   #      C   s  | \ } } } } | d }	 d }
 | d r5 d }
 n  i  } g  | D] } t  | | ƒ rB | ^ qB } x€ | D]x } | | } | \ } } } } | \ } } } | d k r¿ d G| Gd GHt ƒ  n  t | ƒ } | | | } | | | <qk Wt g  | D] } | | ^ qñ ƒ } | d k r| } n  | | } | | } | | d	 k rRt d
 ƒ ‚ n  t rwd G| Gd G| Gd G| Gd Gn  |	 r=d GHi  } x | D] } g  | | <qWd	 } xi| | k  r9xq | D]i } | | } | \ } } \ } } } } t | ƒ } |  j | ƒ } t | |
 | ƒ }  | | j |  ƒ q¿W| d 7} q¬WnØ t rKd GHn  i  } x | D] } g  | | <qXWx¦ t	 | ƒ D]˜ }! x | D]‡ } | | }" | | \ } } \ } } } } t | ƒ } xI t	 d	 | ƒ D]8 } |  j | ƒ } t | |
 | ƒ }  | | j |  ƒ qÑWq†WqyW| S(   sn  
    Read raw data from file f,
    given the previously read leadin.
    segmentobjects are the objects that are given in this segment.
    Objectorder is a list of objectpaths (object id's) that shows
    the order in which the objects are given in the metadata. 
    That is important, for that will be the order in which their
    raw data needs to be read.
    R
   RH   R   t   >i   s   Error! Raw data dimension is s    and should have been 1.iÿÿÿÿi    s-   Data size is not a multiple of the chunk sizes   Ready for readings   bytes (s   ) int   chunkss    ==> Interleaveds    ==> Not Interleaved(
   Rt   R?   R5   t   sumt
   ValueErrorRm   R>   R<   Rn   RJ   (#   R(   t   leadint   segmentobjectsRp   t   filesizeRB   RD   RE   RF   t   interleavedR9   t   channel_sizesR`   t   channelst   ct   channelRW   RM   RN   t   valuesRP   RQ   RR   t   datapointsizet   channel_sizet
   chunk_sizet   total_chunkst   n_chunkst   dataRU   R4   R0   RX   t   chunkt   size(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   readRawData(  sp    

 	)

#	

 

c         C   sS   xL | j  ƒ  D]> } | |  j  ƒ  k r= |  | j | | ƒ q | | |  | <q W|  S(   s=   
    Return the raw data, appended the new
    raw data.
    (   R.   t   extend(   RN   Rd   R€   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   mergeRawData½  s
    c         C   sœ   | \ } } t  |  ƒ } | \ } } } }	 i  }
 | d r^ t |  ƒ \ }
 } t | |
 ƒ } n  | d r’ t |  | |
 | | ƒ } t | | ƒ } n  | | f S(   sh   
    Read a segment from file f, whose filesize is given,
    and data is what we have read already
    R   R   (   RG   Rr   Rl   RŠ   RŒ   (   R(   R{   R‡   Ri   RN   Ry   RB   RD   RE   RF   Rj   t   newobjectordert   newdata(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   readSegmentÕ  s    

c         C   sG   d } x: |  D]2 } |  | \ } } | | d t  | ƒ d } q W| S(   NR    t   =s   , (   t   str(   t   propst   rett   prt   tpt   val(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   dumpProperties  s
     c         C   sp  |  \ } } d } xE | j  ƒ  D]7 } | | \ } } } } d | d t | ƒ d GHq Wd }	 t g  | j  ƒ  D]( } | | j  ƒ  k rp t | | ƒ ^ qp ƒ }
 g  | j  ƒ  D] } t | | ƒ r® | ^ q® } | d j | ƒ d 7} x‚ t |
 ƒ D]t }	 xa | D]Y } d } | | j  ƒ  k rL|	 t | | ƒ k  rLt | | |	 ƒ } n  | | d 7} qW| d 7} qô W| S(   s`   
    Dump the (objects,rawdata) that we read from a TDMS file
    straight into a CSV file.
    R    s   OBJECT s    (s   )
i    s   	s   
(   R.   R—   t   maxt   lenRt   R   RJ   R‘   (   t   .0Ri   R‡   R“   R`   RL   RM   RN   RT   Rq   t   maxiR~   R–   (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   csvDump
  s"    	A/(c         C   sŽ   |  \ } } } } d | j  ƒ  k rŠ d | j  ƒ  k rŠ | d \ } } | d \ } } g  t d t | ƒ ƒ D] }	 | |	 | ^ ql }
 |
 St S(   s`  
    Ok, so we've read the data. Now it's possible that we require some post-processing. For example, if at least one track has time-data set, we'll add a corresponding time vector.

    So channel is the channel for which we want to have the time vector.
    And object contains its meta data.

    We return False if we can't find time data
    
    t   wf_incrementt   wf_start_offseti    (   R.   RJ   R™   R3   (   R`   R€   RL   RM   RN   RT   Rs   t   incrt   offsetRq   t	   timetrack(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   addTimeTrack9  s    0c         C   sf   i  i  f } t  |  d ƒ } t j j |  ƒ } x( | j ƒ  | k  rW t | | | ƒ } q0 W| j ƒ  | S(   sA  
    Reads TDMS file with the given filename.
    We return the data, which is, object meta data and raw channel data.

    Notice that we do not read the (optionally) accompanying .tdms_index
    since it is supposed to be an exact copy of the .tdms file, without the
    raw data. So it should contain nothing new.
    t   rb(   t   opent   ost   patht   getsizet   tellR   t   close(   t   filenameR‡   R(   t   sz(    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyR>   a  s    
l    l    l   € l     l   @ l    (   t   __doc__R+   R¥   R3   Rm   RI   R   R@   R/   R-   R6   R2   R5   R7   R<   RG   R[   R_   Rh   Rl   Rr   Rt   RŠ   RŒ   R   R—   Rœ   R¢   R>   (    (    (    s,   ../includes/DAS/0512NIstandard.ONN/pyTDMS.pyt   <module>   s–   	

	

		&			,	p		+		2		•		,			/	(