ruby_tdms 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +31 -0
- data/LICENSE.txt +26 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/demo.rb +14 -0
- data/doc/data_types.txt +23 -0
- data/doc/example_disasm.txt +47 -0
- data/doc/tdms_format.txt +101 -0
- data/doc/usage.txt +48 -0
- data/lib/ruby_tdms.rb +2 -0
- data/lib/ruby_tdms/aggregate_channel.rb +53 -0
- data/lib/ruby_tdms/aggregate_channel_enumerator.rb +50 -0
- data/lib/ruby_tdms/channel_enumerator.rb +33 -0
- data/lib/ruby_tdms/data_types.rb +22 -0
- data/lib/ruby_tdms/data_types/base.rb +19 -0
- data/lib/ruby_tdms/data_types/boolean.rb +15 -0
- data/lib/ruby_tdms/data_types/double.rb +19 -0
- data/lib/ruby_tdms/data_types/double_with_unit.rb +19 -0
- data/lib/ruby_tdms/data_types/int16.rb +19 -0
- data/lib/ruby_tdms/data_types/int32.rb +19 -0
- data/lib/ruby_tdms/data_types/int64.rb +19 -0
- data/lib/ruby_tdms/data_types/int8.rb +15 -0
- data/lib/ruby_tdms/data_types/single.rb +19 -0
- data/lib/ruby_tdms/data_types/single_with_unit.rb +19 -0
- data/lib/ruby_tdms/data_types/string.rb +15 -0
- data/lib/ruby_tdms/data_types/timestamp.rb +15 -0
- data/lib/ruby_tdms/data_types/u_int16.rb +19 -0
- data/lib/ruby_tdms/data_types/u_int32.rb +19 -0
- data/lib/ruby_tdms/data_types/u_int64.rb +19 -0
- data/lib/ruby_tdms/data_types/u_int8.rb +15 -0
- data/lib/ruby_tdms/document.rb +105 -0
- data/lib/ruby_tdms/file.rb +13 -0
- data/lib/ruby_tdms/object_parser.rb +47 -0
- data/lib/ruby_tdms/objects/base.rb +47 -0
- data/lib/ruby_tdms/objects/channel.rb +105 -0
- data/lib/ruby_tdms/objects/file.rb +11 -0
- data/lib/ruby_tdms/objects/group.rb +22 -0
- data/lib/ruby_tdms/path.rb +97 -0
- data/lib/ruby_tdms/property.rb +16 -0
- data/lib/ruby_tdms/segment.rb +107 -0
- data/lib/ruby_tdms/streaming.rb +124 -0
- data/lib/ruby_tdms/string_channel_enumerator.rb +49 -0
- data/lib/ruby_tdms/version.rb +3 -0
- data/ruby_tdms.gemspec +38 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8c2010fd87e23f9d15a5dd3a2698eaa8fd6a9e1
|
4
|
+
data.tar.gz: a215da2e96b0594c1de8e49c68cd10ef65c8489d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d3e0a5d0cc9036cacfbd7300134dc134b4ae4fa04b3f89192bb0dd42b6e47aeea3cf698edf451bf9b7e6e87dc4ea0cee501d136225e4d972a340d28e903e361
|
7
|
+
data.tar.gz: 00fd1b34967d4ef65ce032ce3c5c03d97ad05f5cfe498bb0d01d792d6494bb9f44bdcbf76f4fccac423dd6ffbeca889b8aab4c8a60e4bf74b51a27cab88c1219
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/.idea/
|
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby_tdms (2.0.0)
|
5
|
+
coalesce
|
6
|
+
require_all
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
coalesce (0.0.1)
|
12
|
+
docile (1.1.5)
|
13
|
+
minitest (5.5.1)
|
14
|
+
multi_json (1.11.0)
|
15
|
+
rake (10.3.2)
|
16
|
+
require_all (1.4.0)
|
17
|
+
simplecov (0.9.2)
|
18
|
+
docile (~> 1.1.0)
|
19
|
+
multi_json (~> 1.0)
|
20
|
+
simplecov-html (~> 0.9.0)
|
21
|
+
simplecov-html (0.9.0)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
bundler (>= 1.7)
|
28
|
+
minitest
|
29
|
+
rake (~> 10.0)
|
30
|
+
ruby_tdms!
|
31
|
+
simplecov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2012, Mike Naberezny.
|
2
|
+
Copyright (c) 2015-2017, Aaron Ten Clay <aarontc@aarontc.com>.
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
* Neither the name of Maintainable Software, LLC. nor the names of its
|
14
|
+
contributors may be used to endorse or promote products derived from
|
15
|
+
this software without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# RubyTDMS
|
2
|
+
|
3
|
+
(Note: The RubyTDMS gem was formerly known as simply "TDMS". The API did not change from TDMS 1.0.0
|
4
|
+
to RubyTDMS 2.0.0, but the version was bumped due to the breaking name change.)
|
5
|
+
|
6
|
+
TDMS is a binary file format for measurement data. It was created
|
7
|
+
by National Instruments.
|
8
|
+
|
9
|
+
- [NI TDMS File Format](http://zone.ni.com/devzone/cda/tut/p/id/3727)
|
10
|
+
- [TDMS File Format Internal Structure](http://zone.ni.com/devzone/cda/tut/p/id/5696)
|
11
|
+
|
12
|
+
National Instruments software such as LabVIEW, DIAdem, and Measurement
|
13
|
+
Studio support reading and writing TDMS files. NI also provides a DLL
|
14
|
+
written in C for using TDMS files on Windows.
|
15
|
+
|
16
|
+
RubyTDMS provides a convenient way to work with
|
17
|
+
TDMS files on Unix-like platforms.
|
18
|
+
|
19
|
+
## Current State
|
20
|
+
|
21
|
+
This gem is nearly feature-complete for for reading the TDMS files according to the
|
22
|
+
2015 specification from National Instruments.
|
23
|
+
|
24
|
+
- Writing TDMS files is not yet supported.
|
25
|
+
|
26
|
+
## Contributors
|
27
|
+
|
28
|
+
This gem is heavily based on the [TDMS library](http://github.com/mnaberez/tdms) created by Mike Naberezny.
|
data/Rakefile
ADDED
data/demo.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'lib/ruby_tdms'
|
2
|
+
|
3
|
+
filename = File.dirname(__FILE__) + '/test/fixtures/example.tdms'
|
4
|
+
doc = RubyTDMS::File.parse(filename)
|
5
|
+
|
6
|
+
ch1 = doc.channels.find { |c| c.name == 'StatisticsText' }
|
7
|
+
ch2 = doc.channels.find { |c| c.name == 'Res_Noise_1' }
|
8
|
+
|
9
|
+
last = [ch1.values.size, ch2.values.size].min - 1
|
10
|
+
|
11
|
+
puts "#{ch1.name},#{ch2.name}"
|
12
|
+
0.upto(last) do |i|
|
13
|
+
puts "#{ch1.values[i]},#{ch2.values[i]}"
|
14
|
+
end
|
data/doc/data_types.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Data Types
|
2
|
+
|
3
|
+
Identifier Name Length (bytes) Ruby
|
4
|
+
|
5
|
+
0x00000000 tdsTypeVoid 1 Nil
|
6
|
+
0x00000001 tdsTypeI8 1 Integer
|
7
|
+
0x00000002 tdsTypeI16 2 Integer
|
8
|
+
0x00000003 tdsTypeI32 4 Integer
|
9
|
+
0x00000004 tdsTypeI64 8 Integer
|
10
|
+
0x00000005 tdsTypeU8 1 Integer
|
11
|
+
0x00000006 tdsTypeU16 2 Integer
|
12
|
+
0x00000007 tdsTypeU32 4 Integer
|
13
|
+
0x00000008 tdsTypeU64 8 Integer
|
14
|
+
0x00000009 tdsTypeSingleFloat 4 Float
|
15
|
+
0x0000000A tdsTypeDoubleFloat 8 Float
|
16
|
+
0x0000000B tdsTypeExtendedFloat 10 ?
|
17
|
+
0x00000019 tdsTypeSingleFloatWithUnit 4 Float
|
18
|
+
0x0000001A tdsTypeDoubleFloatWithUnit 8 Float
|
19
|
+
0x0000001B tdsTypeExtendedFloatWithUnit 10 ?
|
20
|
+
0x00000020 tdsTypeString 4 len + n chars String
|
21
|
+
0x00000021 tdsTypeBoolean 1 True, False
|
22
|
+
0x00000044 tdsTypeTimeStamp 16 DateTime
|
23
|
+
0xFFFFFFFF tdsTypeDAQmxRawData ? ?
|
@@ -0,0 +1,47 @@
|
|
1
|
+
EXAMPLE.tdms
|
2
|
+
Contains 4 segments
|
3
|
+
|
4
|
+
|
5
|
+
000000 54 44 53 6d "TDSm" id tag
|
6
|
+
000004 0E 00 00 00 0e is ToC flag, other 3 bytes unused
|
7
|
+
000008 68 12 00 00 6812 is little endian for 0x1268 or 4713 (TDMS standard version). Other two bytes unused.
|
8
|
+
00000C E3 88 20 00
|
9
|
+
000010 00 00 00 00 => 64-bit unsigned little endian 0x00000000002088E3 is the next segment offset
|
10
|
+
000014 E3 08 00 00
|
11
|
+
000018 00 00 00 00 => 64-bit unsigned little endian 0x00000000000008E3 is the raw data offset
|
12
|
+
( End of Lead-In )
|
13
|
+
( 00001C is the offset of the next byte after the lead-in )
|
14
|
+
( Next segment offset = 00001C + 2088E3 = 2088FF )
|
15
|
+
( Raw data offset = 00001C + 0008E3 = 0008FF )
|
16
|
+
|
17
|
+
( Start of Metadata )
|
18
|
+
00001C 08 00 00 00 => 32-bit unsigned little endian 0x00000008 is the number of
|
19
|
+
new/changed objects in this segment (8 objects)
|
20
|
+
000020 11 00 00 00 => 32-bit unsigned little endian 0x00000011 is the length of
|
21
|
+
the object's path string (11 bytes)
|
22
|
+
(Begin Path String)
|
23
|
+
000024 2F 27 45 58 /'EX
|
24
|
+
000028 41 4D 50 4C AMPL
|
25
|
+
00002C 45 27 2F 27 E'/'
|
26
|
+
000030 54 69 6D 65 Time
|
27
|
+
000034 27 '
|
28
|
+
(Begin Length of Index)
|
29
|
+
000034 14 00 00
|
30
|
+
000038 0A 00 00 => 32-bit unsigned little endian 0x00000014 is the
|
31
|
+
raw data index
|
32
|
+
(Begin Data Type)
|
33
|
+
000038 0A
|
34
|
+
00003C 00 00 00 => 32-bit unsigned little endian 0x0000000A is the
|
35
|
+
data type (tdsTypeDoubleFloat)
|
36
|
+
|
37
|
+
(Begin Array Dimension)
|
38
|
+
00003C 01
|
39
|
+
000040 00 00 00 => 32-bit unsigned little endian 0x00000001 is the
|
40
|
+
array dimension (always 1)
|
41
|
+
(Begin Number of Values)
|
42
|
+
000040 00
|
43
|
+
000044 04 00 00 00
|
44
|
+
000048 04 00 00 => 64-bit unsigned little endian 0x0000000000000400 is the
|
45
|
+
number of values (1024 values)
|
46
|
+
(Begin Total Size in Bytes)
|
47
|
+
|
data/doc/tdms_format.txt
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
http://zone.ni.com/devzone/cda/tut/p/id/5696
|
2
|
+
|
3
|
+
Object Hierarchy
|
4
|
+
|
5
|
+
Hierarchy Path
|
6
|
+
|
7
|
+
example_events.tdms (File) /
|
8
|
+
|
|
9
|
+
+-- Measured Data (Group) /Measured Data
|
10
|
+
| |
|
11
|
+
| +-- Amplitude Sweep (Channel) /Measured Data/Amplitude Sweep
|
12
|
+
| +-- Phase Sweep (Channel) /Measured Data/Phase Sweep
|
13
|
+
|
|
14
|
+
+-- Dr. T's Events (Group) /Dr. T's Events
|
15
|
+
|
|
16
|
+
+-- Time (Channel) /Dr. T's Events/Time
|
17
|
+
+-- Description (Channel) /Dr. T's Events/Description
|
18
|
+
|
19
|
+
There are exactly 3 levels of objects in TDMS:
|
20
|
+
- File (every TDMS file must have one)
|
21
|
+
- Group (has many Channels, may have none)
|
22
|
+
- Channel (belongs to a Group)
|
23
|
+
|
24
|
+
Every object is identified by a string path. The only thing that
|
25
|
+
identifies an object as being a File, Group, or Channel is the
|
26
|
+
number of Segments in the string path:
|
27
|
+
|
28
|
+
Object Type Example Path Number of Path Segments
|
29
|
+
File / 0
|
30
|
+
Group /Group 1
|
31
|
+
Channel /Group/Channel 2
|
32
|
+
|
33
|
+
|
34
|
+
File Structure
|
35
|
+
|
36
|
+
File is divided into Segments.
|
37
|
+
Each segment contains one or more Objects
|
38
|
+
Every Object has a string Path
|
39
|
+
|
40
|
+
|
41
|
+
Segment
|
42
|
+
|
43
|
+
+-----------+------------+------------+----------------------------
|
44
|
+
| Lead-in | Metadata | Raw Data | Lead-in (Next Segment) ...
|
45
|
+
+-----------+------------+------------+----------------------------
|
46
|
+
|
47
|
+
Lead-in
|
48
|
+
+---------+--------+---------+--------------------+--------------------+---
|
49
|
+
| 4: TDSm | 4: ToC | 4: Vers | 8: Next Seg Offset | 8: Raw Data Offset | Metadata ...
|
50
|
+
+---------+--------+---------+--------------------+--------------------+---
|
51
|
+
00 04 08 0C 14 1C
|
52
|
+
|
53
|
+
|
54
|
+
00-03 4 bytes: TDMS identifier (always "TDSm")
|
55
|
+
04-07 4 bytes: Table of contents (only first byte used)
|
56
|
+
Flags to indicate what is in the segment
|
57
|
+
08-0B 4 bytes: TDMS version number (always 4713)
|
58
|
+
0C-13 8 bytes: Offset of the next segment (little endian). Take the
|
59
|
+
absolute offset of the next byte after the lead-in and
|
60
|
+
add it to this number to find the next segment.
|
61
|
+
14-1B 8 bytes: Offset of the raw data in this segment (little endian).
|
62
|
+
Also calculate it from next byte after the lead-in.
|
63
|
+
|
64
|
+
|
65
|
+
Metadata
|
66
|
+
+----------+-------------+---------+-------------------+--------------+-
|
67
|
+
| 4: Count | 4: Path Len | n: Path | 4: Raw data index | 4: Num Props |
|
68
|
+
+----------+-------------+---------+-------------------+--------------+-
|
69
|
+
00 04 08
|
70
|
+
|
71
|
+
4 bytes: Number of new/changed objects in this segment
|
72
|
+
|
73
|
+
For each object in the segment:
|
74
|
+
4 bytes: Length of object's string path
|
75
|
+
n bytes: Object's string path
|
76
|
+
|
77
|
+
Index block or markers:
|
78
|
+
If no raw data in the segment:
|
79
|
+
4 bytes: FF FF FF FF
|
80
|
+
Else if raw data index block exactly matches last segment:
|
81
|
+
4 bytes: 00 00 00 00
|
82
|
+
Else:
|
83
|
+
4 bytes: Length of raw data index block + 4
|
84
|
+
4 bytes: Data type of the raw data in this object
|
85
|
+
4 bytes: Dimension of raw data array (only first byte used, always 1)
|
86
|
+
8 bytes: Number of values
|
87
|
+
8 bytes: Total size in bytes (?) -- may not be here
|
88
|
+
|
89
|
+
Properties Block:
|
90
|
+
|
91
|
+
4 bytes: Number of properties of this object
|
92
|
+
|
93
|
+
For each property:
|
94
|
+
4 bytes: Length of property name
|
95
|
+
n bytes: Property name
|
96
|
+
4 bytes: Data type of property value (only first byte used)
|
97
|
+
n bytes: Property value
|
98
|
+
String is 4 bytes for length, then bytes of string
|
99
|
+
Others are fixed number of bytes for value based on type
|
100
|
+
|
101
|
+
Raw Data
|
data/doc/usage.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
READING
|
2
|
+
=======
|
3
|
+
|
4
|
+
# display properties of a channel
|
5
|
+
|
6
|
+
group = segment.groups.find {|grp| grp.path == "/EXAMPLE" }
|
7
|
+
speed = group.channels.find {|ch| ch.path == "/EXAMPLE/Time" }
|
8
|
+
speed.properties.each_pair do |k,v|
|
9
|
+
puts k,v
|
10
|
+
end
|
11
|
+
|
12
|
+
# loop through a channel
|
13
|
+
|
14
|
+
group = segment.groups.find {|grp| grp.path == "/EXAMPLE" }
|
15
|
+
speed = group.channels.find {|ch| ch.path == "/EXAMPLE/Time" }
|
16
|
+
speed.values.each do |v|
|
17
|
+
puts v #=> float
|
18
|
+
end
|
19
|
+
|
20
|
+
# spreadsheet of two channels
|
21
|
+
|
22
|
+
group = segment.groups.find {|grp| grp.path == "/EXAMPLE" }
|
23
|
+
|
24
|
+
time = group.channels.find { |ch| ch.path == "/EXAMPLE/Time" }
|
25
|
+
speed = group.channels.find { |ch| ch.path == "/EXAMPLE/Speed" }
|
26
|
+
|
27
|
+
max = [time.values.size, speed.values.size].max - 1
|
28
|
+
0.upto(max) do |i|
|
29
|
+
puts "%f,%f" % (time.values[i], speed.values[i])
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
WRITING
|
34
|
+
=======
|
35
|
+
|
36
|
+
(Note: writing is not yet supported)
|
37
|
+
|
38
|
+
tdms = RubyTDMS::File.new("some filename")
|
39
|
+
seg = tdms.segment.build
|
40
|
+
|
41
|
+
group = seg.groups.build("foo")
|
42
|
+
|
43
|
+
chan = group.channels.build("bar")
|
44
|
+
chan.properties["Flux Capacitor"] = "On"
|
45
|
+
channel.values << 1.02
|
46
|
+
channel.values << 1.02
|
47
|
+
|
48
|
+
seg.save
|
data/lib/ruby_tdms.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'aggregate_channel_enumerator'
|
2
|
+
|
3
|
+
module RubyTDMS
|
4
|
+
class AggregateChannel
|
5
|
+
def initialize(channels = [])
|
6
|
+
@channels = channels
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"#<#{self.class.name}:#{self.object_id} path=#{path.inspect}, #{@channels.length} channel(s)>"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def path
|
16
|
+
@channels[0].path
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def name
|
21
|
+
@channels[0].name
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def data_type
|
26
|
+
@channels[0].data_type
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def data_type_id
|
31
|
+
@channels[0].data_type_id
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def values
|
36
|
+
@values ||= AggregateChannelEnumerator.new @channels
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def as_json
|
41
|
+
result = @channels[0].as_json
|
42
|
+
# Iterate over all channel objects and update properties
|
43
|
+
result[:properties] = @channels.reduce({}) do |properties, channel|
|
44
|
+
channel.properties.each do |property|
|
45
|
+
properties[property.name.to_sym] = property.value
|
46
|
+
end
|
47
|
+
properties
|
48
|
+
end
|
49
|
+
result[:values] = values.to_a
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RubyTDMS
|
2
|
+
class AggregateChannelEnumerator
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(channels)
|
7
|
+
@channels = channels
|
8
|
+
@offsets = []
|
9
|
+
|
10
|
+
size = 0
|
11
|
+
@channels.inject(0) do |size, channel|
|
12
|
+
@offsets << size
|
13
|
+
size += channel.values.size
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def size
|
19
|
+
@size ||= @channels.inject(0) { |sum, chan| sum += chan.values.size }
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def each
|
24
|
+
@channels.each do |channel|
|
25
|
+
channel.values.each { |value| yield value }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def [](i)
|
31
|
+
if (i < 0) || (i >= size)
|
32
|
+
raise RangeError, 'Channel %s has a range of 0 to %d, got invalid index: %d' % [@channels[0].path, size - 1, i]
|
33
|
+
end
|
34
|
+
|
35
|
+
channel, offset = nil, nil
|
36
|
+
j = @offsets.size - 1
|
37
|
+
@offsets.reverse_each do |o|
|
38
|
+
if i >= o
|
39
|
+
channel = @channels[j]
|
40
|
+
offset = @offsets[j]
|
41
|
+
break
|
42
|
+
else
|
43
|
+
j -= 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
channel.values[i - offset]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|