Class: IntelHex::Record

Inherits:
Object
  • Object
show all
Defined in:
lib/intel_hex/record.rb

Constant Summary collapse

TYPES =
%i[
  data
  eof
  esa
  ssa
  ela
  sla
].freeze
TYPE_MAP =
TYPES.each_with_index.each_with_object({}) { |(k, i), h| h[k] = i }
TYPE_DATA_LENGTH =
{
  data: (1..255),
  eof: 0,
  esa: 2,
  ssa: 4,
  ela: 2,
  sla: 4,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, length = 0, offset = 0, data = [], checksum = nil, line: nil, validate: false) ⇒ Record

rubocop:disable Metrics/ParameterLists



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/intel_hex/record.rb', line 89

def initialize(type, length = 0, offset = 0, data = [], checksum = nil, line: nil, validate: false)
  @type = type
  @length = length
  @offset = offset
  @data = data
  @calculated_checksum = nil
  @checksum = checksum || calculate_checksum
  @line = line

  self.validate if validate
end

Instance Attribute Details

#checksumObject (readonly)

Returns the value of attribute checksum.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def checksum
  @checksum
end

#dataObject

Returns the value of attribute data.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def data
  @data
end

#lengthObject (readonly)

Returns the value of attribute length.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def length
  @length
end

#lineObject (readonly)

Returns the value of attribute line.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def line
  @line
end

#offsetObject (readonly)

Returns the value of attribute offset.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def offset
  @offset
end

#typeObject (readonly)

Returns the value of attribute type.



86
87
88
# File 'lib/intel_hex/record.rb', line 86

def type
  @type
end

Class Method Details

.data(data) ⇒ Object



54
55
56
57
58
# File 'lib/intel_hex/record.rb', line 54

def self.data(data)
  record = Record.new(:data)
  record.data = data
  record
end

.ela(value) ⇒ Object



78
79
80
# File 'lib/intel_hex/record.rb', line 78

def self.ela(value)
  type_with_value(:ela, value)
end

.eofObject



60
61
62
# File 'lib/intel_hex/record.rb', line 60

def self.eof
  Record.new(:eof)
end

.esa(value) ⇒ Object



70
71
72
# File 'lib/intel_hex/record.rb', line 70

def self.esa(value)
  type_with_value(:esa, value)
end

.parse(line) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/intel_hex/record.rb', line 39

def self.parse(line)
  raise MisformattedFileError, 'Expected \':\' at start of line' unless line[0] == ':'
  raise MisformattedFileError, 'Line length incorrect' unless line.size >= (1 + 2 + 4 + 2)

  length = line[1..2].to_i(16)
  data_end = (9 + length * 2)

  offset = line[3..6].to_i(16)
  type = TYPES[line[7..8].to_i(16)]
  data = line[9...data_end].chars.each_slice(2).map { |a| a.join.to_i(16) }
  checksum = line[data_end..(data_end + 2)].to_i(16)

  Record.new(type, length, offset, data, checksum, line: line, validate: true)
end

.sla(value) ⇒ Object



82
83
84
# File 'lib/intel_hex/record.rb', line 82

def self.sla(value)
  type_with_value(:sla, value)
end

.ssa(value) ⇒ Object



74
75
76
# File 'lib/intel_hex/record.rb', line 74

def self.ssa(value)
  type_with_value(:ssa, value)
end

.type_with_value(type, value) ⇒ Object



64
65
66
67
68
# File 'lib/intel_hex/record.rb', line 64

def self.type_with_value(type, value)
  record = Record.new(type)
  record.send("#{type}=".to_sym, value)
  record
end

Instance Method Details

#calculate_checksumObject



126
127
128
129
130
131
132
133
# File 'lib/intel_hex/record.rb', line 126

def calculate_checksum
  return @calculated_checksum if @calculated_checksum

  sum = length + ((offset & 0xff00) >> 8) + (offset & 0x00ff) + TYPE_MAP[type]
  sum += data.sum

  @calculated_checksum = (((sum & 0xff) ^ 0xff) + 1) & 0xff
end

#data_sObject

rubocop:enable Metrics/ParameterLists



102
103
104
# File 'lib/intel_hex/record.rb', line 102

def data_s
  "[#{data.map { |b| '%02x' % b }.join(' ')}]"
end

#data_to_uint16(offset = 0) ⇒ Object Also known as: esa, ela



210
211
212
# File 'lib/intel_hex/record.rb', line 210

def data_to_uint16(offset = 0)
  (data[offset + 0] << 8) | data[offset + 1]
end

#data_to_uint32(offset = 0) ⇒ Object Also known as: ssa, sla



223
224
225
# File 'lib/intel_hex/record.rb', line 223

def data_to_uint32(offset = 0)
  (data[offset + 0] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]
end

#each_byte_with_addressObject



191
192
193
194
195
196
197
198
199
# File 'lib/intel_hex/record.rb', line 191

def each_byte_with_address
  return Enumerator.new(self, :each_byte_with_address) unless block_given?

  data.each_with_index do |byte, i|
    yield byte, offset + i
  end

  nil
end

#recalculate_checksumObject



135
136
137
138
# File 'lib/intel_hex/record.rb', line 135

def recalculate_checksum
  @calculated_checksum = nil
  calculate_checksum
end

#to_asciiObject



116
117
118
119
120
121
122
123
124
# File 'lib/intel_hex/record.rb', line 116

def to_ascii
  ':%02X%04X%02X%s%02X' % [
    length,
    offset,
    TYPE_MAP[type],
    data.map { |b| '%02X' % b }.join,
    checksum,
  ]
end

#to_sObject



112
113
114
# File 'lib/intel_hex/record.rb', line 112

def to_s
  "#<#{self.class.name} type=#{type} offset=#{offset} length=#{length} #{value_s}>"
end

#uint16_to_data(value, offset = 0) ⇒ Object Also known as: esa=, ela=



214
215
216
217
218
219
220
221
# File 'lib/intel_hex/record.rb', line 214

def uint16_to_data(value, offset = 0)
  data[(offset...(offset + 2))] = [
    (value & 0xff00) >> 8,
    value & 0x00ff,
  ]
  @length = data.size
  @checksum = recalculate_checksum
end

#uint32_to_data(value, offset = 0) ⇒ Object Also known as: ssa=, sla=



227
228
229
230
231
232
233
234
235
236
# File 'lib/intel_hex/record.rb', line 227

def uint32_to_data(value, offset = 0)
  data[(offset...(offset + 4))] = [
    (value & 0xff000000) >> 24,
    (value & 0x00ff0000) >> 16,
    (value & 0x0000ff00) >> 8,
    value & 0x000000ff,
  ]
  @length = data.size
  @checksum = recalculate_checksum
end

#valid?Boolean

Returns:

  • (Boolean)


140
141
142
143
144
145
# File 'lib/intel_hex/record.rb', line 140

def valid?
  validate
  true
rescue ValidationError
  false
end

#validateObject



147
148
149
150
151
152
153
# File 'lib/intel_hex/record.rb', line 147

def validate
  validate_type
  validate_length
  validate_offset
  validate_data
  validate_checksum
end

#validate_checksumObject



185
186
187
188
189
# File 'lib/intel_hex/record.rb', line 185

def validate_checksum
  return if calculate_checksum == checksum

  raise InvalidChecksumError, "Checksum value #{checksum} does not match expected checksum #{calculate_checksum}"
end

#validate_dataObject

Raises:



179
180
181
182
183
# File 'lib/intel_hex/record.rb', line 179

def validate_data
  return if data.size == length

  raise InvalidDataError, "Data length #{data.size} does not match length #{length}"
end

#validate_lengthObject

Raises:



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/intel_hex/record.rb', line 166

def validate_length
  valid_length = TYPE_DATA_LENGTH[type]

  case valid_length
  when Integer
    return if length == valid_length
  when Range
    return if valid_length.include?(length)
  end

  raise InvalidLengthError, "Length for type #{type} must be #{valid_length}; #{length} given"
end

#validate_offsetObject

Raises:



161
162
163
164
# File 'lib/intel_hex/record.rb', line 161

def validate_offset
  raise InvalidOffsetError, "Offset #{offset} is negative" unless offset >= 0
  raise InvalidOffsetError, "Offset #{offset} is too large" unless offset < 2**16
end

#validate_typeObject

Raises:



155
156
157
158
159
# File 'lib/intel_hex/record.rb', line 155

def validate_type
  return if TYPE_MAP.include?(type)

  raise InvalidTypeError, "Type #{type} is invalid"
end

#value_sObject



106
107
108
109
110
# File 'lib/intel_hex/record.rb', line 106

def value_s
  return '' if type == :eof

  "#{type}=#{type == :data ? data_s : send(type)}"
end