Object.fs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. namespace FSharp.Data.Tdms
  2. open System
  3. open System.IO
  4. open System.Numerics
  5. open System.Runtime.InteropServices
  6. open System.Threading.Tasks
  7. type Object =
  8. { Name: string
  9. BigEndian: bool
  10. mutable RawDataBlocks: RawDataBlocks option
  11. Properties: Property ResizeArray }
  12. module Object =
  13. let addPrimitiveRawDataBlock ty primitiveRawDataBlock object =
  14. match object.RawDataBlocks with
  15. | None ->
  16. let primitiveRawDataBlockArray = ResizeArray()
  17. primitiveRawDataBlockArray.Add primitiveRawDataBlock
  18. object.RawDataBlocks <- Some(PrimitiveRawDataBlocks(ty, primitiveRawDataBlockArray))
  19. | Some (PrimitiveRawDataBlocks (ty', primitiveRawDataBlockArray)) ->
  20. if ty <> ty' then
  21. failwithf
  22. "Object %s already has type %A, cannot add a primitive data block of type %A to it; check whether the TDMS file is valid"
  23. object.Name
  24. ty'
  25. ty
  26. else
  27. primitiveRawDataBlockArray.Add primitiveRawDataBlock
  28. | Some (StringRawDataBlocks _) ->
  29. failwithf
  30. "Object %s already has type string, cannot add a primitive data block of type %A to it; check whether the TDMS file is valid"
  31. object.Name
  32. ty
  33. let addStringRawDataBlock stringRawDataBlock object =
  34. match object.RawDataBlocks with
  35. | None ->
  36. let stringRawDataBlockArray = ResizeArray()
  37. stringRawDataBlockArray.Add stringRawDataBlock
  38. object.RawDataBlocks <- Some(StringRawDataBlocks stringRawDataBlockArray)
  39. | Some (PrimitiveRawDataBlocks (ty', _)) ->
  40. failwithf
  41. "Object %s already has type %A, cannot add a string data block to it; check whether the TDMS file is valid"
  42. object.Name
  43. ty'
  44. | Some (StringRawDataBlocks stringRawDataBlockArray) -> stringRawDataBlockArray.Add stringRawDataBlock
  45. let readRawDataIndex
  46. object
  47. (rawDataPosition: uint64)
  48. (buffer: byte ReadOnlySpan byref)
  49. bigEndian
  50. (interleaved: bool)
  51. =
  52. match Buffer.readUInt &buffer bigEndian with
  53. | 0u ->
  54. match object.RawDataBlocks with
  55. | None -> failwithf "Missing raw data index for object %s; check whether the TDMS file is valid" object.Name
  56. | Some (PrimitiveRawDataBlocks (ty, primitiveRawDataBlockArray)) ->
  57. match Seq.tryLast primitiveRawDataBlockArray with
  58. | None ->
  59. failwithf
  60. "Missing primitive raw data blocks for object %s; this is a bug in FSharp.Data.Tdms"
  61. object.Name
  62. | Some (DecimatedPrimitiveRawDataBlock (_, bytes)) ->
  63. if interleaved then
  64. failwithf
  65. "Object %s raw data changes from decimated to interleaved without a new raw data index; check whether the TDMS file is valid"
  66. object.Name
  67. else
  68. primitiveRawDataBlockArray.Add(DecimatedPrimitiveRawDataBlock(rawDataPosition, bytes))
  69. bytes
  70. | Some (InterleavedPrimitiveRawDataBlock _) ->
  71. if not interleaved then
  72. failwithf
  73. "Object %s raw data changes from interleaved to decimated without a new raw data index; check whether the TDMS file is valid"
  74. object.Name
  75. else
  76. uint64 (Marshal.SizeOf ty)
  77. | Some (StringRawDataBlocks stringRawDataBlockArray) ->
  78. match Seq.tryLast stringRawDataBlockArray with
  79. | None ->
  80. failwithf
  81. "Missing string raw data blocks for object %s; this is a bug in FSharp.Data.Tdms"
  82. object.Name
  83. | Some (_, length, bytes) ->
  84. stringRawDataBlockArray.Add(rawDataPosition, length, bytes)
  85. bytes
  86. | 20u ->
  87. let ty = Buffer.readType &buffer bigEndian
  88. Buffer.readUInt &buffer bigEndian |> ignore
  89. let length = Buffer.readUInt64 &buffer bigEndian
  90. let size = Marshal.SizeOf ty
  91. if not interleaved then
  92. addPrimitiveRawDataBlock ty (DecimatedPrimitiveRawDataBlock(rawDataPosition, length)) object
  93. length * uint64 size
  94. else
  95. addPrimitiveRawDataBlock
  96. ty
  97. (InterleavedPrimitiveRawDataBlock
  98. { Start = rawDataPosition
  99. Count = length
  100. Skip = 0uL })
  101. object
  102. uint64 size
  103. | 28u ->
  104. Buffer.readType &buffer bigEndian |> ignore
  105. Buffer.readUInt &buffer bigEndian |> ignore
  106. let length = Buffer.readUInt64 &buffer bigEndian
  107. let bytes = Buffer.readUInt64 &buffer bigEndian
  108. addStringRawDataBlock (rawDataPosition, length, bytes) object
  109. bytes
  110. | 0xFFFFFFFFu -> 0uL
  111. | 0x1269u
  112. | 0x126Au ->
  113. let ty = Buffer.readType &buffer bigEndian
  114. let dimension = Buffer.readUInt &buffer bigEndian
  115. let chunkSize = Buffer.readUInt64 &buffer bigEndian
  116. let scalerCount = Buffer.readUInt &buffer bigEndian |> int
  117. let scalers =
  118. Array.zeroCreate<FormatChangingScaler> scalerCount
  119. for scalerIndex = 0 to scalerCount - 1 do
  120. scalers.[scalerIndex] <- RawDataBlock.readFormatChangingScaler &buffer bigEndian
  121. let widthCount = Buffer.readUInt &buffer bigEndian |> int
  122. let widths = Array.zeroCreate<uint> widthCount
  123. for widthIndex = 0 to widthCount - 1 do
  124. widths.[widthIndex] <- Buffer.readUInt &buffer bigEndian
  125. //object.LastRawDataIndex <- Some (DaqMx (ty, dimension, chunkSize, scalers, widths))
  126. 0uL
  127. | length -> failwithf "Invalid raw data index length: %i" length
  128. let toChannel
  129. filePath
  130. ({ Name = name
  131. Properties = properties
  132. RawDataBlocks = rawDataBlocks
  133. BigEndian = bigEndian }: Object)
  134. =
  135. { Name =
  136. name.Split([| '/' |], StringSplitOptions.RemoveEmptyEntries).[1]
  137. .Trim('\'')
  138. FilePath = filePath
  139. Properties = properties
  140. RawDataBlocks = rawDataBlocks
  141. BigEndian = bigEndian }
  142. let toGroup
  143. filePath
  144. channels
  145. ({ Name = groupName
  146. Properties = groupProperties }: Object)
  147. =
  148. { Name =
  149. groupName.Split([| '/' |], StringSplitOptions.RemoveEmptyEntries).[0]
  150. .Trim('\'')
  151. Properties = groupProperties
  152. Channels = Seq.map (toChannel filePath) channels }