ir_telemetry 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8ef0d8e19ef07ebde17c382070101cfb4ee0c1fdcde2c5eca90142015081ce10
4
+ data.tar.gz: 4f8153e93f0fee0b77311dddf5f4091c0b00f14d29842fff75dfe56fcbfba59c
5
+ SHA512:
6
+ metadata.gz: 1492a7732612f22293c2c93d791a036b4845c9a8657f7ba900b68b762a7b874e0abfa16f0262ab005317cded94c18fa114483d2428a6ee59b040cb82ecd154e8
7
+ data.tar.gz: 76cd07bc6873df019c13baaaff59595c1afe181b63867be6725f1b074fcb40c1a7ef0e30bdf372c3a36ab9e59c2171cc75c257c0efc36bf3d721fa8241e890be
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/testdouble/standard
3
+ ruby_version: 2.6
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.2.0] - 2023-05-30
4
+
5
+ - Add dataset iteration
6
+ - Add test workflow
7
+ - Add Session string parsing
8
+
9
+ ## [0.1.0] - 2023-05-23
10
+
11
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in ir_telemetry.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
11
+
12
+ gem "standard", "~> 1.3"
data/Gemfile.lock ADDED
@@ -0,0 +1,65 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ir_telemetry (0.2.0)
5
+ bindata (~> 2.4)
6
+ zeitwerk (~> 2.6)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ bindata (2.4.15)
13
+ json (2.6.3)
14
+ language_server-protocol (3.17.0.3)
15
+ lint_roller (1.0.0)
16
+ minitest (5.18.0)
17
+ parallel (1.23.0)
18
+ parser (3.2.2.1)
19
+ ast (~> 2.4.1)
20
+ rainbow (3.1.1)
21
+ rake (13.0.6)
22
+ regexp_parser (2.8.0)
23
+ rexml (3.2.5)
24
+ rubocop (1.50.2)
25
+ json (~> 2.3)
26
+ parallel (~> 1.10)
27
+ parser (>= 3.2.0.0)
28
+ rainbow (>= 2.2.2, < 4.0)
29
+ regexp_parser (>= 1.8, < 3.0)
30
+ rexml (>= 3.2.5, < 4.0)
31
+ rubocop-ast (>= 1.28.0, < 2.0)
32
+ ruby-progressbar (~> 1.7)
33
+ unicode-display_width (>= 2.4.0, < 3.0)
34
+ rubocop-ast (1.28.1)
35
+ parser (>= 3.2.1.0)
36
+ rubocop-performance (1.16.0)
37
+ rubocop (>= 1.7.0, < 2.0)
38
+ rubocop-ast (>= 0.4.0)
39
+ ruby-progressbar (1.13.0)
40
+ standard (1.28.2)
41
+ language_server-protocol (~> 3.17.0.2)
42
+ lint_roller (~> 1.0)
43
+ rubocop (~> 1.50.2)
44
+ standard-custom (~> 1.0.0)
45
+ standard-performance (~> 1.0.1)
46
+ standard-custom (1.0.0)
47
+ lint_roller (~> 1.0)
48
+ standard-performance (1.0.1)
49
+ lint_roller (~> 1.0)
50
+ rubocop-performance (~> 1.16.0)
51
+ unicode-display_width (2.4.2)
52
+ zeitwerk (2.6.8)
53
+
54
+ PLATFORMS
55
+ arm64-darwin-21
56
+ x86_64-linux
57
+
58
+ DEPENDENCIES
59
+ ir_telemetry!
60
+ minitest (~> 5.0)
61
+ rake (~> 13.0)
62
+ standard (~> 1.3)
63
+
64
+ BUNDLED WITH
65
+ 2.4.10
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ [![CI](https://github.com/virolea/ir_telemetry/actions/workflows/ci.yml/badge.svg)](https://github.com/virolea/ir_telemetry/actions/workflows/ci.yml)
2
+
3
+ # iRacing Telemetry
4
+
5
+ Parse and browse iRacing telemetry files with Ruby.
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add ir_telemetry
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install ir_telemetry
16
+
17
+ ## Usage
18
+
19
+ ### Quick start
20
+
21
+ ```ruby
22
+ ibt_filepath = "/path/to/telemetry/file.ibt"
23
+
24
+ IRTelemetry::IBTFile.open(ibt_filepath) do |file|
25
+ # access session information hash
26
+ session_info = file.session_info
27
+ session_info['WeekendInfo']['TrackName'] # => e.g. jerez gp
28
+
29
+ # access telemetry data
30
+ file.dataset.each do |data_point|
31
+ data_point["Speed"] # => e.g. 2432.65
32
+ data_point["Lap"] # => 4
33
+ end
34
+ end
35
+ ```
36
+
37
+ The above code is a shorthand for:
38
+
39
+ ```ruby
40
+ ibt_filepath = "/path/to/telemetry/file.ibt"
41
+
42
+ ibt_file = IRTelemetry::IBTFile.new(ibt_filepath)
43
+
44
+ session_info = ibt_file.session_info
45
+ session_info["WeekendInfo"""]["'"TrackName"] # => e.g. jerez gp
46
+
47
+ ibt_file.dataset.each do |data_point|
48
+ data_point["Speed"] # => e.g. 2432.65
49
+ data_point["Lap"] # => 4
50
+ end
51
+
52
+ # close the io stream
53
+ ibt_file.close
54
+ ```
55
+
56
+ ### Session information
57
+
58
+ The session information is accessible through the `IBTFile` object instance. It is a Hash loaded from the session YAML which schema can be found in the Appendix B of the [telemetry docs](docs/telemetry_11_23_15.pdf).
59
+
60
+ ```ruby
61
+ ibt_filepath = "/path/to/telemetry/file.ibt"
62
+
63
+ ibt_file = IRTelemetry::IBTFile.new(ibt_filepath)
64
+
65
+ # Session info is a plain Ruby Hash.
66
+ session_info = ibt_file.session_info
67
+ session_info["WeekendInfo"]["TrackName"]
68
+ ```
69
+
70
+ ### Telemetry data
71
+
72
+ The telemetry data is accessible through the `IBTFile` object instance. It is a `Dataset` object which is an `Enumerable` of `DataPoint` objects. You can then access telemetry variables on the datapoint by calling `[]` on it. For a complete list of available variables, see the Appendix A of the [telemetry docs](docs/telemetry_11_23_15.pdf)
73
+
74
+ ```ruby
75
+ ibt_filepath = "/path/to/telemetry/file.ibt"
76
+
77
+ ibt_file = IRTelemetry::IBTFile.new(ibt_filepath)
78
+
79
+ # Telemetry data is a Dataset object
80
+ dataset = ibt_file.dataset
81
+ ```
82
+
83
+ #### Iterating over available data
84
+
85
+ ```ruby
86
+ dataset.each do |data_point|
87
+ puts data_point["Speed"]
88
+ end
89
+ ```
90
+
91
+ #### Accessing a data point at a particular index
92
+
93
+ ```ruby
94
+ puts dataset[0]["Speed"]
95
+ ```
96
+
97
+
98
+ ## Development
99
+
100
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
101
+
102
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
103
+
104
+ ## Contributing
105
+
106
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ir_telemetry.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ require "standard/rake"
13
+
14
+ task default: %i[test standard]
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRTelemetry
4
+ class DataPoint
5
+ VAR_TYPES_MAPPING = {
6
+ 1 => {
7
+ size: 1,
8
+ type: :irsdk_bool,
9
+ handler: BinData::Bit8
10
+ },
11
+ 2 => {
12
+ size: 4,
13
+ type: :irsdk_int,
14
+ handler: BinData::Int32le
15
+ },
16
+ 3 => {
17
+ size: 4,
18
+ type: :irsdk_bit_field,
19
+ handler: BinData::Int32le
20
+ },
21
+ 4 => {
22
+ size: 4,
23
+ type: :irsdk_float,
24
+ handler: BinData::FloatLe
25
+ },
26
+ 5 => {
27
+ size: 8,
28
+ type: :irsdk_double,
29
+ handler: BinData::DoubleLe
30
+ }
31
+ }.freeze
32
+
33
+ def initialize(buffer, dataset)
34
+ @buffer = buffer
35
+ @dataset = dataset
36
+ end
37
+
38
+ def [](variable_name)
39
+ variable = @dataset.variables[variable_name]
40
+ type = VAR_TYPES_MAPPING[variable.var_type]
41
+
42
+ type[:handler].read(
43
+ @buffer.byteslice(variable.offset, type[:size])
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRTelemetry
4
+ class Dataset
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ attr_reader :variables
9
+
10
+ def_delegators :@file, :header, :io
11
+
12
+ def initialize(file)
13
+ @file = file
14
+ @variables = set_variables
15
+ end
16
+
17
+ def [](index)
18
+ io.seek(buffer_offset + index * buffer_length)
19
+
20
+ buffer = io.read(buffer_length)
21
+ DataPoint.new(buffer, self)
22
+ end
23
+
24
+ def each(&block)
25
+ start_at_the_beginning
26
+
27
+ while (buffer = io.read(buffer_length))
28
+ data_point = DataPoint.new(buffer, self)
29
+
30
+ yield data_point if block
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def set_variables
37
+ io.seek(header.var_header_offset)
38
+
39
+ var_buffer = io.read(IBTFile::IRSDK_VAR_HEADER_SIZE * header.num_vars)
40
+
41
+ variables = {}
42
+
43
+ (0...header.num_vars - 1).each do |i|
44
+ irsdk_var = Headers::IRSDKVarHeader.read(
45
+ var_buffer.byteslice(i * IBTFile::IRSDK_VAR_HEADER_SIZE, IBTFile::IRSDK_VAR_HEADER_SIZE)
46
+ )
47
+
48
+ variables[irsdk_var.name.to_s] = irsdk_var
49
+ end
50
+
51
+ variables
52
+ end
53
+
54
+ def start_at_the_beginning
55
+ io.seek(buffer_offset)
56
+ end
57
+
58
+ def buffer_offset
59
+ header.var_buf[0].buf_offset
60
+ end
61
+
62
+ def buffer_length
63
+ header.buf_len
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRTelemetry
4
+ class Headers::IRSDKHeader < BinData::Record
5
+ IRSDK_MAX_BUFS = 4
6
+
7
+ endian :little
8
+
9
+ int32 :version
10
+ int32 :status
11
+ int32 :tick_rate
12
+
13
+ int32 :session_info_update
14
+ int32 :session_info_len
15
+ int32 :session_info_offset
16
+
17
+ int32 :num_vars
18
+ int32 :var_header_offset
19
+
20
+ int32 :num_buf
21
+ int32 :buf_len
22
+ array :pad, type: :int32, initial_length: 2
23
+
24
+ array :var_buf, initial_length: IRSDK_MAX_BUFS do
25
+ endian :little
26
+
27
+ int32 :tick_count
28
+ int32 :buf_offset
29
+ array :pad, type: :int32, initial_length: 2
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRTelemetry
4
+ class Headers::IRSDKVarHeader < BinData::Record
5
+ endian :little
6
+
7
+ int32 :var_type
8
+ int32 :offset
9
+ int32 :var_count
10
+
11
+ bit8 :count_as_time
12
+ string :pad, length: 3
13
+
14
+ string :name, length: IBTFile::IRSDK_MAX_STRING, trim_padding: true
15
+ string :desc, length: IBTFile::IRSDK_MAX_DESC, trim_padding: true
16
+ string :unit, length: IBTFile::IRSDK_MAX_STRING, trim_padding: true
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "date"
5
+
6
+ module IRTelemetry
7
+ class IBTFile
8
+ attr_reader :header, :io
9
+
10
+ IRSDK_HEADER_SIZE = 112
11
+ IRSDK_VAR_HEADER_SIZE = 144
12
+
13
+ IRSDK_MAX_STRING = 32
14
+ IRSDK_MAX_DESC = 64
15
+
16
+ IBT_FILE_ENCODING = "Windows-1252"
17
+
18
+ class << self
19
+ def open(filepath, &block)
20
+ io = new(filepath)
21
+ block.call(io)
22
+ ensure
23
+ io&.close
24
+ end
25
+ end
26
+
27
+ def initialize(filepath)
28
+ @io = File.open(filepath, "rb")
29
+ @header = Headers::IRSDKHeader.read(@io)
30
+ end
31
+
32
+ def close
33
+ @io.close
34
+ end
35
+
36
+ def session_info
37
+ @io.seek(@header.session_info_offset)
38
+ session_string = @io.read(@header.session_info_len)
39
+ session_string.force_encoding(IBT_FILE_ENCODING)
40
+ session_string.encode("UTF-8")
41
+
42
+ YAML.safe_load(session_string, permitted_classes: [Date])
43
+ end
44
+
45
+ def dataset
46
+ @dataset ||= Dataset.new(self)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRTelemetry
4
+ VERSION = "0.2.0"
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ require "bindata"
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.inflector.inflect "ir_telemetry" => "IRTelemetry"
8
+ loader.inflector.inflect "ibt_file" => "IBTFile"
9
+ loader.inflector.inflect "irsdk_header" => "IRSDKHeader"
10
+ loader.inflector.inflect "irsdk_var_header" => "IRSDKVarHeader"
11
+ loader.setup
12
+
13
+ module IRTelemetry
14
+ class Error < StandardError; end
15
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ir_telemetry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Vincent Rolea
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-05-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: zeitwerk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bindata
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.4'
41
+ description: Parse and browse iRacing telemetry files with Ruby.
42
+ email:
43
+ - low.salt3234@fastmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".standard.yml"
49
+ - CHANGELOG.md
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - README.md
53
+ - Rakefile
54
+ - lib/ir_telemetry.rb
55
+ - lib/ir_telemetry/data_point.rb
56
+ - lib/ir_telemetry/dataset.rb
57
+ - lib/ir_telemetry/headers/irsdk_header.rb
58
+ - lib/ir_telemetry/headers/irsdk_var_header.rb
59
+ - lib/ir_telemetry/ibt_file.rb
60
+ - lib/ir_telemetry/version.rb
61
+ homepage: https://github.com/virolea/ir_telemetry
62
+ licenses:
63
+ - MIT
64
+ metadata:
65
+ allowed_push_host: https://rubygems.org
66
+ homepage_uri: https://github.com/virolea/ir_telemetry
67
+ source_code_uri: https://github.com/virolea/ir_telemetry
68
+ changelog_uri: https://github.com/virolea/ir_telemetry/blob/main/CHANGELOG.md
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 2.6.0
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.3.7
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Parse and browse iRacing telemetry files with Ruby.
88
+ test_files: []