ir_telemetry 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []