automotive-ecu 0.1.9 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afdcb21c88b030d3a51419219dbc4ebf34c11cdfa22bcb4878b10980bd1758f8
4
- data.tar.gz: 7ba90b0782418f2ae411ced1846292dc3cf69c281efcdbdd55a2bb10d2faca1b
3
+ metadata.gz: d05b1f41faab9eb4a9ffb33697b015f0242d64450f25bedf6ce47aef2aac08ca
4
+ data.tar.gz: ecdc24755f8244e51a2bc20ee9efef50f3e40be5f6a2d5f678d5bdea462f5c8b
5
5
  SHA512:
6
- metadata.gz: 634a92da870fde03b29b91fd52572c13e68cb4265e3570a90e53e83f0653c970ec9f4b2b690a13e3e4454e3ee622c5ab647a1809dcf5f5a388b4db90ec023320
7
- data.tar.gz: df6ac03c377110ef7f663339eccf5a2f3a1989dfb95ce52d5845631ddc9f132def6aed90c9788ecf2ab185ec909b8c2c7c2d10a3f57a451db3f87bc0bedc51c2
6
+ metadata.gz: 1b92c416a9dacb5dd9c28afd30bdf9de68e31390977612752bf23365cf9a9b93894d7e4641bb5629832debb237d549fb4f38c475b2b55ad812c271b99b193e52
7
+ data.tar.gz: f8548dd035ac77f453d2b36717f398107d16207febfb886bc26964a6c84ef1582b0e41ea1039fed4b3afc0ebd48a8230e21eb47255d1064c71ae6f5ab90c9e74
@@ -0,0 +1,78 @@
1
+ require "strscan"
2
+
3
+ class Ecu
4
+ class LabelList
5
+ class DcmLexer
6
+ attr_reader :doc
7
+ def initialize(doc)
8
+ @doc = doc
9
+ @scan = StringScanner.new(doc)
10
+ end
11
+
12
+ KEYWORDS = [
13
+ "FUNKTIONEN", "FESTWERT", "FESTWERTEBLOCK", "KENNLINIE", "GRUPPENKENNLINIE", "FESTKENNLINIE",
14
+ "KENNFELD", "GRUPPENKENNFELD", "FESTKENNFELD", "STUETZSTELLENVERTEILUNG",
15
+ "FKT",
16
+ "ST/X", "ST/Y", "WERT", "ST_TX/X", "ST_TX/Y", "TEXT",
17
+ "FUNKTION",
18
+ "EINHEIT_X", "EINHEIT_Y", "EINHEIT_W",
19
+ "LANGNAME", "DISPLAYNAME",
20
+ "END",
21
+ ].freeze
22
+
23
+ HEADER = "KONSERVIERUNG_FORMAT 2.0"
24
+ WHITESPACE = %r{ [ \t]+ }x
25
+ NEWLINE = %r{ \r\n|\n }x
26
+ COMMENT = %r{ ^\*.*$ }x
27
+ DIMENSIONS_SEP = %r{ @ }x
28
+ QUOTED_TEXT = %r{ "[^"]*" }x
29
+ IDENTIFIER = %r{ [A-Za-z][A-Za-z0-9_\.]* }x
30
+ UNSIGNED_INT = %r{ [0]|[1-9][0-9]* }x
31
+ INT = %r{ [-]?#{UNSIGNED_INT} }x
32
+ FLOAT_EXP = %r{ [eE][+-]?[0-9]+ }x
33
+ FLOAT = %r{
34
+ [-+]?
35
+ (?:
36
+ #{UNSIGNED_INT}?[.][0-9]+#{FLOAT_EXP} | # 1.23e10 or .45e3
37
+ #{UNSIGNED_INT} #{FLOAT_EXP} | # 3e4
38
+ #{UNSIGNED_INT}?[.][0-9]+ | # 7.3 or .50
39
+ #{UNSIGNED_INT} [.][0-9]* # 3.02 or 9.
40
+ )
41
+ }x
42
+ KW_RE = /#{Regexp.union(KEYWORDS.sort)}\b/
43
+ KW_TABLE = Hash[KEYWORDS.map { [_1, _1.upcase.to_sym] }]
44
+
45
+
46
+ def next_token
47
+ @scan.skip(WHITESPACE)
48
+
49
+ return if @scan.eos?
50
+
51
+ case
52
+ when @scan.skip(NEWLINE) then :NEWLINE
53
+ when s = @scan.scan(KW_RE) then KW_TABLE[s]
54
+ when @scan.skip(QUOTED_TEXT) then :QUOTED_TEXT
55
+ when @scan.skip(COMMENT) then :COMMENT
56
+ when @scan.skip(DIMENSIONS_SEP) then :DIMENSIONS_SEP
57
+ when @scan.skip(HEADER) then :HEADER
58
+ when @scan.skip(IDENTIFIER) then :IDENTIFIER
59
+ when @scan.skip(FLOAT) then :FLOAT
60
+ when @scan.skip(INT) then :INT
61
+
62
+ else
63
+ @scan.getch
64
+ :UNKNOWN_CHAR
65
+ end
66
+ end
67
+
68
+ def token_value
69
+ @doc.byteslice(@scan.pos - @scan.matched_size, @scan.matched_size)
70
+ end
71
+
72
+ def lineno
73
+ @doc.byteslice(0, @scan.pos).count("\n") +
74
+ (@scan.beginning_of_line? ? 0 : 1)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,215 @@
1
+ require_relative "dcm_lexer"
2
+ require_relative "dcm_parser_error"
3
+
4
+ class Ecu
5
+ class LabelList
6
+ class DcmParser
7
+
8
+ ARY_PROPERTIES = %i( xvalue yvalue value )
9
+ KEY_MAPPING = {
10
+ "ST/X": :xvalue,
11
+ "ST/Y": :yvalue,
12
+ "WERT": :value,
13
+ "ST_TX/X": :xvalue,
14
+ "ST_TX/Y": :yvalue,
15
+ "TEXT": :value,
16
+ "FUNKTION": :function,
17
+ "DISPLAYNAME": :displayname,
18
+ "EINHEIT_X": :xunit,
19
+ "EINHEIT_Y": :yunit,
20
+ "EINHEIT_W": :unit,
21
+ "LANGNAME": :description,
22
+ }
23
+
24
+ attr_reader :lexer, :state, :labels, :headers, :subheaders
25
+ def initialize(doc)
26
+ @lexer = DcmLexer.new(doc)
27
+ @state = :PRE_HEADER
28
+ @labels = []
29
+ @headers = []
30
+ @subheaders = []
31
+ reset_label!
32
+ end
33
+
34
+ def call
35
+ while tok = lexer.next_token
36
+ begin
37
+ case @state
38
+ in :PRE_HEADER
39
+ case tok
40
+ in :HEADER then next_state(:POST_HEADER)
41
+ in :COMMENT then add_header(lexer.token_value)
42
+ in :NEWLINE
43
+ end
44
+ in :POST_HEADER
45
+ case tok
46
+ in :FUNKTIONEN then next_state(:FUNCTIONS_CONTENT)
47
+ in :FESTWERT then start_label(Festwert)
48
+ in :FESTWERTEBLOCK then start_label(Festwerteblock)
49
+ in :KENNLINIE then start_label(Kennlinie)
50
+ in :GRUPPENKENNLINIE then start_label(Gruppenkennlinie)
51
+ in :FESTKENNLINIE then start_label(Festkennlinie)
52
+ in :KENNFELD then start_label(Kennfeld)
53
+ in :GRUPPENKENNFELD then start_label(Gruppenkennfeld)
54
+ in :FESTKENNFELD then start_label(Festkennfeld)
55
+ in :STUETZSTELLENVERTEILUNG then start_label(Stuetzstellenverteilung)
56
+ in :COMMENT then add_subheader(lexer.token_value)
57
+ in :NEWLINE then # noop
58
+ end
59
+ in :FUNCTIONS_CONTENT
60
+ case tok
61
+ in :FKT then next_state(:FUNCTION_CONTENT)
62
+ in :NEWLINE then # noop
63
+ in :END then next_state(:POST_HEADER)
64
+ end
65
+ in :FUNCTION_CONTENT
66
+ case tok
67
+ in :IDENTIFIER then # append that shit?
68
+ in :QUOTED_TEXT then # append that shit as well?
69
+ in :NEWLINE then next_state(:FUNCTIONS_CONTENT)
70
+ end
71
+ in :LABEL_HEADLINE
72
+ case tok
73
+ in :IDENTIFIER then add_name(lexer.token_value)
74
+ in :DIMENSIONS_SEP then # noop, order handled by #add_dimension
75
+ in :INT then add_dimension(lexer.token_value.to_i)
76
+ in :NEWLINE then next_state(:LABEL_CONTENT)
77
+ end
78
+ in :LABEL_CONTENT
79
+ case tok
80
+ in :"ST/X" then start_property(:"ST/X", :NUMERIC_PROPERTY)
81
+ in :"ST/Y" then start_property(:"ST/Y", :NUMERIC_PROPERTY)
82
+ in :WERT then start_property(:WERT, :NUMERIC_PROPERTY)
83
+ in :"ST_TX/X" then start_property(:"ST_TX/X", :TEXT_PROPERTY)
84
+ in :"ST_TX/Y" then start_property(:"ST_TX/Y", :TEXT_PROPERTY)
85
+ in :TEXT then start_property(:TEXT, :TEXT_PROPERTY)
86
+ in :EINHEIT_X then start_property(:EINHEIT_X, :TEXT_PROPERTY)
87
+ in :EINHEIT_Y then start_property(:EINHEIT_Y, :TEXT_PROPERTY)
88
+ in :EINHEIT_W then start_property(:EINHEIT_W, :TEXT_PROPERTY)
89
+ in :LANGNAME then start_property(:LANGNAME, :TEXT_PROPERTY)
90
+ in :FUNKTION then start_property(:FUNKTION, :ID_PROPERTY)
91
+ in :DISPLAYNAME then start_property(:DISPLAYNAME, :ID_PROPERTY)
92
+ in :END then labels << finish_label
93
+ in :NEWLINE then # noop, DCM badly formatted
94
+ in :COMMENT then # noop, some programs add SST in comments
95
+ end
96
+ in :NUMERIC_PROPERTY
97
+ case tok
98
+ in :FLOAT then append_property(lexer.token_value.to_f)
99
+ in :INT then append_property(lexer.token_value.to_i)
100
+ in :NEWLINE then finish_property
101
+ end
102
+ in :TEXT_PROPERTY
103
+ case tok
104
+ in :QUOTED_TEXT then append_property(lexer.token_value[1..-2])
105
+ in :NEWLINE then finish_property
106
+ end
107
+ in :ID_PROPERTY
108
+ case tok
109
+ in :IDENTIFIER then append_property(lexer.token_value)
110
+ in :NEWLINE then finish_property
111
+ end
112
+ end
113
+ rescue NoMatchingPatternError => e
114
+ raise DcmParserError.new("Unexpected token #{debug_token(tok)} (state: #{state})", lexer)
115
+ rescue StandardError => e
116
+ raise DcmParserError.new("#{e.message} (state: #{@state})", lexer)
117
+ end
118
+ end
119
+ [labels, headers, subheaders]
120
+ end
121
+
122
+ def debug_token(tok)
123
+ if tok == :UNKNOWN_CHAR
124
+ "UNKNOWN_CHAR: #{lexer.token_value}"
125
+ else
126
+ tok
127
+ end
128
+ end
129
+
130
+ def next_state(newstate)
131
+ @state = newstate
132
+ yield if block_given?
133
+ end
134
+
135
+ def add_header(str)
136
+ @headers << str[1..].strip
137
+ end
138
+
139
+ def add_subheader(str)
140
+ @subheaders << str[1..].strip
141
+ end
142
+
143
+ def start_label(constructor)
144
+ next_state(:LABEL_HEADLINE) do
145
+ @constructor = constructor
146
+ end
147
+ end
148
+
149
+ def finish_label
150
+ next_state(:POST_HEADER) do
151
+ @properties
152
+ .except(:displayname)
153
+ .then { @constructor.new(**_1) }
154
+ .tap { reset_label! }
155
+ end
156
+ end
157
+
158
+ def add_name(str)
159
+ fail "Duplicate name" if @properties.key?(:name)
160
+
161
+ @properties[:name] = str
162
+ end
163
+
164
+ def add_dimension(n)
165
+ fail "Wrong order name/dimensions" unless @properties.key?(:name)
166
+ fail "Too many dimensions" if @properties.key?(:xdim) && @properties.key?(:ydim)
167
+
168
+ if @properties.key?(:xdim)
169
+ @properties[:ydim] = n
170
+ else
171
+ @properties[:xdim] = n
172
+ end
173
+ end
174
+
175
+ def start_property(key, newstate)
176
+ next_state(newstate) do
177
+ @key = KEY_MAPPING[key]
178
+ @value = ARY_PROPERTIES.include?(@key) ? [] : nil
179
+ end
180
+ end
181
+
182
+ def append_property(value)
183
+ # TODO: Check if constructor allows array values
184
+ if ARY_PROPERTIES.include?(@key)
185
+ @value << value
186
+ else
187
+ fail "Multiple definitions for #{@key}" if @value
188
+
189
+ @value = value
190
+ end
191
+ end
192
+
193
+ def finish_property
194
+ next_state(:LABEL_CONTENT) do
195
+ @properties.merge!({ @key => @value }, &method(:merge_property))
196
+ end
197
+ end
198
+
199
+ def merge_property(key, old, new)
200
+ fail "Multiple property lines not allowed for #{key}" unless ARY_PROPERTIES.include?(key)
201
+
202
+ old + new
203
+ end
204
+
205
+ def reset_label!
206
+ @constructor = nil
207
+ @properties = {}
208
+ @key = nil
209
+ @value = nil
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+ end
@@ -0,0 +1,35 @@
1
+ class Ecu
2
+ class DcmParserError < StandardError
3
+
4
+ CTXLENGHT = 5
5
+
6
+ attr_reader :doc, :lineno
7
+ def initialize(msg, lexer)
8
+ @msg = msg
9
+ @doc = lexer.doc
10
+ @lineno = lexer.lineno
11
+ end
12
+
13
+ def message = @msg
14
+ def context
15
+ @doc
16
+ .lines[ctx_startline..ctx_endline]
17
+ .each
18
+ .with_index(ctx_startline + 1)
19
+ .map { |line, n| present(line, n, n == lineno) }
20
+ end
21
+
22
+ def present(line, n, highlight)
23
+ case highlight
24
+ when true then fmt(n) + " => | " + line
25
+ when false then fmt(n) + " | " + line
26
+ end
27
+ end
28
+
29
+ def ctx_startline = [0, lineno - CTXLENGHT].max
30
+ def ctx_endline = @endline ||= [doc.lines.count - 1, lineno + CTXLENGHT].min
31
+ def fmt_str = "%#{(ctx_endline + 1).to_s.length}d"
32
+ def fmt(n) = fmt_str % n
33
+
34
+ end
35
+ end
@@ -2,8 +2,5 @@ require_relative "kennfeld"
2
2
 
3
3
  class Ecu
4
4
  class Festkennfeld < Kennfeld
5
- def self.dcm_header
6
- %r{^FESTKENNFELD\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)\s+(?<ydim>\d+)}
7
- end
8
5
  end
9
6
  end
@@ -2,8 +2,5 @@ require_relative "kennlinie"
2
2
 
3
3
  class Ecu
4
4
  class Festkennlinie < Kennlinie
5
- def self.dcm_header
6
- %r{^FESTKENNLINIE\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)}
7
- end
8
5
  end
9
6
  end
@@ -1,9 +1,5 @@
1
1
  class Ecu
2
2
  class Festwert < Label
3
- def self.dcm_header
4
- %r{FESTWERT\s+(?<name>[A-Za-z0-9\._]+)}
5
- end
6
-
7
3
  def to_dcm(indented=false)
8
4
  fmtstr = indented ? "%-25s%s\n" : "%s %s\n"
9
5
 
@@ -2,10 +2,6 @@ require_relative "../../../core_ext"
2
2
 
3
3
  class Ecu
4
4
  class Festwerteblock < Label
5
- def self.dcm_header
6
- %r{^FESTWERTEBLOCK\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)(?:\s+@\s+(?<ydim>\d+))?}
7
- end
8
-
9
5
  def to_dcm(indented=false)
10
6
  fmtstr = indented ? "%-25s%s %s" : "%s %s %d"
11
7
 
@@ -2,8 +2,5 @@ require_relative "kennfeld"
2
2
 
3
3
  class Ecu
4
4
  class Gruppenkennfeld < Kennfeld
5
- def self.dcm_header
6
- %r{^GRUPPENKENNFELD\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)\s+(?<ydim>\d+)}
7
- end
8
5
  end
9
6
  end
@@ -2,8 +2,5 @@ require_relative "kennlinie"
2
2
 
3
3
  class Ecu
4
4
  class Gruppenkennlinie < Kennlinie
5
- def self.dcm_header
6
- %r{^GRUPPENKENNLINIE\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)}
7
- end
8
5
  end
9
6
  end
@@ -1,9 +1,5 @@
1
1
  class Ecu
2
2
  class Kennfeld < Label
3
- def self.dcm_header
4
- %r{^KENNFELD\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)\s+(?<ydim>\d+)}
5
- end
6
-
7
3
  def to_dcm(indented=false)
8
4
  fmtstr = indented ? "%-25s%s %s %s\n" : "%s %s %d %d\n"
9
5
 
@@ -1,9 +1,5 @@
1
1
  class Ecu
2
2
  class Kennlinie < Label
3
- def self.dcm_header
4
- %r{^KENNLINIE\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)}
5
- end
6
-
7
3
  def to_dcm(indented=false)
8
4
  fmtstr = indented ? "%-25s%s %s\n" : "%s %s %d\n"
9
5
 
@@ -1,25 +1,7 @@
1
- require_relative "property_parser"
2
-
3
1
  class Ecu
4
2
  class Label
5
- def self.from_dcm(input)
6
- lines = case input
7
- in Array then input
8
- in String then input.lines
9
- end
10
- hsh = dcm_header.extract_captures(lines.first)
11
-
12
- hsh[:xdim] = hsh[:xdim].to_i if hsh.key?(:xdim)
13
- hsh[:ydim] = hsh[:ydim].to_i if hsh.key?(:ydim)
14
-
15
- fail "Malformed DCM" if hsh.empty?
16
- fail "Malformed DCM" unless lines.last.match?(/^END$/)
17
-
18
- lines[1..-2]
19
- .map { DcmPropertyParser.call(_1) }
20
- .each { hsh.merge!(_1) { |_, old, new| old + new } }
21
-
22
- new(**hsh)
3
+ def to_dcm
4
+ fail "To be defined by child classes"
23
5
  end
24
6
  end
25
7
  end
@@ -1,4 +1,3 @@
1
- require_relative "functions"
2
1
  require_relative "festwert"
3
2
  require_relative "festwerteblock"
4
3
  require_relative "kennlinie"
@@ -8,69 +7,18 @@ require_relative "kennfeld"
8
7
  require_relative "gruppenkennfeld"
9
8
  require_relative "festkennfeld"
10
9
  require_relative "stuetzstellenverteilung"
11
- require_relative "malformed_dcm_error"
12
- require_relative "buffer"
10
+
11
+ require_relative "dcm_parser"
13
12
 
14
13
  class Ecu
15
14
  class LabelList
16
15
 
17
- DCM_HEADER = "KONSERVIERUNG_FORMAT 2.0"
18
- BLANKLINE_REGEX = /^\s*$/
19
- COMMENT_REGEX = /^\*.*/
16
+ DCM_HEADER = "KONSERVIERUNG_FORMAT 2.0"
20
17
 
21
18
  def self.from_dcm(str)
22
- buffer = DcmBuffer.new
23
- headers = []
24
- subheaders = []
25
- functions = []
26
- labels = {}
27
-
28
- str.each_line.lazy.with_index(1).each do |line, n|
29
- line = normalize_whitespace(line)
30
- case line
31
- when BLANKLINE_REGEX then next
32
- when COMMENT_REGEX
33
- case buffer.header
34
- when :pre then headers << line[1..].strip
35
- when :after then subheaders << line[1..].strip
36
- when :done then # Header time over, do nothing
37
- end
38
- when DCM_HEADER then buffer.header_seen!
39
- when Functions.dcm_header then buffer.start!(Functions, [line])
40
- when Festwert.dcm_header then buffer.start!(Festwert, [line])
41
- when Festwerteblock.dcm_header then buffer.start!(Festwerteblock, [line])
42
- when Kennlinie.dcm_header then buffer.start!(Kennlinie, [line])
43
- when Gruppenkennlinie.dcm_header then buffer.start!(Gruppenkennlinie, [line])
44
- when Festkennlinie.dcm_header then buffer.start!(Festkennlinie, [line])
45
- when Kennfeld.dcm_header then buffer.start!(Kennfeld, [line])
46
- when Gruppenkennfeld.dcm_header then buffer.start!(Gruppenkennfeld, [line])
47
- when Festkennfeld.dcm_header then buffer.start!(Festkennfeld, [line])
48
- when Stuetzstellenverteilung.dcm_header then buffer.start!(Stuetzstellenverteilung, [line])
49
- when "END" then
50
- case obj = buffer.finish!(line)
51
- when Label
52
- fail "Duplicate label #{obj.name}" unless labels[obj.name].nil?
53
-
54
- labels[obj.name] = obj
55
- when Functions
56
- fail "Duplicate functions definition" unless functions.empty?
57
-
58
- functions = obj
59
- else
60
- fail "Unknown object #{obj}"
61
- end
62
- else
63
- buffer.append!(line)
64
- end
65
- rescue StandardError => e
66
- raise MalformedDcmError.new(e.message, n, str), e.message
67
- end
68
-
69
- new(labels.values, headers, subheaders, true)
70
- end
71
-
72
- def self.normalize_whitespace(line)
73
- line.chomp.gsub(/[[:space:]]/, " ").rstrip
19
+ DcmParser.new(str)
20
+ .then { _1.call }
21
+ .then { new(*_1, true) }
74
22
  end
75
23
 
76
24
  def to_dcm(indented=false)
@@ -1,9 +1,5 @@
1
1
  class Ecu
2
2
  class Stuetzstellenverteilung < Label
3
- def self.dcm_header
4
- %r{STUETZSTELLENVERTEILUNG\s+(?<name>[A-Za-z0-9\._]+)\s+(?<xdim>\d+)}
5
- end
6
-
7
3
  def to_dcm(indented=false)
8
4
  fmtstr = indented ? "%-25s%s %s\n" : "%s %s %d\n"
9
5
 
@@ -13,7 +13,15 @@ class Ecu
13
13
  attr_reader :name, :function, :description
14
14
 
15
15
  def init_error(message)
16
- fail ArgumentError, "Error creating #{name}: " + message
16
+ fail ArgumentError, "Error creating #{name}: " +
17
+ message + "\n" +
18
+ inspect_instance_vars + "\n\n"
19
+ end
20
+
21
+ def inspect_instance_vars
22
+ instance_variables
23
+ .map { "#{_1} = #{instance_variable_get(_1)}" }
24
+ .join("\n")
17
25
  end
18
26
 
19
27
  def type
data/lib/ecu/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Ecu
2
- VERSION = "0.1.9"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: automotive-ecu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Mueller
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2025-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: terminal-table
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: benchmark-ips
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Provides an interface for exporting/importing signals and labels to various
70
84
  automotive formats (*.lab, *.dcm)
71
85
  email:
@@ -91,20 +105,19 @@ files:
91
105
  - lib/ecu/interfaces/a2l/label_list.rb
92
106
  - lib/ecu/interfaces/a2l/signal_list.rb
93
107
  - lib/ecu/interfaces/dbc/signal_list.rb
94
- - lib/ecu/interfaces/dcm/buffer.rb
108
+ - lib/ecu/interfaces/dcm/dcm_lexer.rb
109
+ - lib/ecu/interfaces/dcm/dcm_parser.rb
110
+ - lib/ecu/interfaces/dcm/dcm_parser_error.rb
95
111
  - lib/ecu/interfaces/dcm/festkennfeld.rb
96
112
  - lib/ecu/interfaces/dcm/festkennlinie.rb
97
113
  - lib/ecu/interfaces/dcm/festwert.rb
98
114
  - lib/ecu/interfaces/dcm/festwerteblock.rb
99
- - lib/ecu/interfaces/dcm/functions.rb
100
115
  - lib/ecu/interfaces/dcm/gruppenkennfeld.rb
101
116
  - lib/ecu/interfaces/dcm/gruppenkennlinie.rb
102
117
  - lib/ecu/interfaces/dcm/kennfeld.rb
103
118
  - lib/ecu/interfaces/dcm/kennlinie.rb
104
119
  - lib/ecu/interfaces/dcm/label.rb
105
120
  - lib/ecu/interfaces/dcm/label_list.rb
106
- - lib/ecu/interfaces/dcm/malformed_dcm_error.rb
107
- - lib/ecu/interfaces/dcm/property_parser.rb
108
121
  - lib/ecu/interfaces/dcm/stuetzstellenverteilung.rb
109
122
  - lib/ecu/interfaces/lab/combined_list.rb
110
123
  - lib/ecu/interfaces/lab/lab_parser.rb
@@ -1,39 +0,0 @@
1
- class DcmBuffer
2
- attr_reader :buffer, :header, :constructor
3
- def initialize
4
- @constructor = nil
5
- @header = :pre
6
- @buffer = []
7
- end
8
-
9
- def start!(constructor, buffer)
10
- fail "Nested parameter" unless self.buffer.empty?
11
- fail "Missing DCM header" if self.header == :pre
12
-
13
- @header = :done
14
- @constructor = constructor
15
- @buffer = buffer
16
- end
17
-
18
- def finish!(line)
19
- fail "Unexpected END" if constructor.nil?
20
- append!(line)
21
-
22
- constructor.from_dcm(buffer).tap { reset! }
23
- end
24
-
25
- def reset!
26
- @constructor = nil
27
- @buffer = []
28
- end
29
-
30
- def header_seen!
31
- @header = :after
32
- end
33
-
34
- def append!(line)
35
- fail "No label started" if constructor.nil?
36
-
37
- @buffer << line
38
- end
39
- end
@@ -1,13 +0,0 @@
1
- require_relative "property_parser"
2
-
3
- class Ecu
4
- class Functions
5
- def self.dcm_header
6
- /FUNKTIONEN.*/
7
- end
8
-
9
- def self.from_dcm(input)
10
- new
11
- end
12
- end
13
- end
@@ -1,34 +0,0 @@
1
- class Ecu
2
- class MalformedDcmError < StandardError
3
- attr_reader :lineno, :filecontent
4
- def initialize(msg, lineno, filecontent)
5
- super(msg)
6
- @lineno = lineno
7
- @filecontent = filecontent
8
- end
9
-
10
- def to_s = "Malformed DCM: #{super} near line ##{lineno}"
11
- def to_str = to_s
12
-
13
- def context
14
- filecontent
15
- .lines
16
- .each
17
- .with_index(1)
18
- .map { |line, n| present(line, n, n == lineno) }
19
- .then { _1[ctx_startline..ctx_endline] }
20
- end
21
-
22
- def present(line, n, highlight)
23
- case highlight
24
- when true then fmt(n) + " => | " + line
25
- when false then fmt(n) + " | " + line
26
- end
27
- end
28
-
29
- def ctx_startline = [0, lineno - 7].max
30
- def ctx_endline = @endline ||= [filecontent.lines.count - 1, lineno + 3].min
31
- def fmt_str = "%#{(ctx_endline + 1).to_s.length}d"
32
- def fmt(n) = fmt_str % n
33
- end
34
- end
@@ -1,50 +0,0 @@
1
- class Ecu
2
- class DcmPropertyParser
3
-
4
- def self.call(line)
5
- key, _, value = line.strip.partition(/\s+/)
6
- eval_property(key, value)
7
- end
8
-
9
- private
10
-
11
- def self.eval_property(key, value)
12
- case key
13
- when "ST/X" then { xvalue: numeric_array(value) }
14
- when "ST/Y" then { yvalue: numeric_array(value) }
15
- when "WERT" then { value: numeric_array(value) }
16
- when "ST_TX/X" then { xvalue: string_array(value) }
17
- when "ST_TX/Y" then { yvalue: string_array(value) }
18
- when "TEXT" then { value: string_array(value) }
19
- when "FUNKTION" then { function: value }
20
- when "EINHEIT_X" then { xunit: string_value(value) }
21
- when "EINHEIT_Y" then { yunit: string_value(value) }
22
- when "EINHEIT_W" then { unit: string_value(value) }
23
- when "LANGNAME" then { description: string_value(value) }
24
- when "DISPLAYNAME" then { }
25
- else fail ArgumentError, "Unknown key #{key}"
26
- end
27
- end
28
-
29
- def self.string_value(str)
30
- str.delete_surrounding('"')
31
- end
32
-
33
- def self.numeric_array(str)
34
- str.split.map { numeric_value(_1) }
35
- end
36
-
37
- def self.string_array(str)
38
- str.scan(/"([^"]*)"/).flatten
39
- end
40
-
41
- def self.numeric_value(str)
42
- case str
43
- in /^\d+$/ then str.to_i
44
- in /^\d+\.$/ then str.to_f
45
- else Float(str)
46
- end
47
- end
48
-
49
- end
50
- end