Class: IntelHex::Record

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

Constant Summary collapse

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

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

Returns a new instance of Record.



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/intel_hex/record.rb', line 84

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.



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

def checksum
  @checksum
end

#dataObject

Returns the value of attribute data.



80
81
82
# File 'lib/intel_hex/record.rb', line 80

def data
  @data
end

#lengthObject (readonly)

Returns the value of attribute length.



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

def length
  @length
end

#lineObject (readonly)

Returns the value of attribute line.



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

def line
  @line
end

#offsetObject (readonly)

Returns the value of attribute offset.



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

def offset
  @offset
end

#typeObject (readonly)

Returns the value of attribute type.



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

def type
  @type
end

Class Method Details

.data(data) ⇒ Object



45
46
47
48
49
# File 'lib/intel_hex/record.rb', line 45

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

.ela(value) ⇒ Object



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

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

.eofObject



51
52
53
# File 'lib/intel_hex/record.rb', line 51

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

.esa(value) ⇒ Object



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

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

.parse(line) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/intel_hex/record.rb', line 30

def self.parse(line)
  raise MisformattedFileError.new("Expected ':' at start of line") unless line[0] == ':'
  raise MisformattedFileError.new("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].split('').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



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

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

.ssa(value) ⇒ Object



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

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

.type_with_value(type, value) ⇒ Object



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

def self.type_with_value(type, value)
  record = Record.new(type)
  record.send((type.to_s + '=').to_sym, value)
  record
end

Instance Method Details

#calculate_checksumObject



110
111
112
113
114
115
116
117
# File 'lib/intel_hex/record.rb', line 110

def calculate_checksum
  return @calculated_checksum if @calculated_checksum

  sum = length + ((offset & 0xff00) >> 8) + (offset & 0x00ff) + TYPE_MAP[type]
  sum += data.inject(0) { |s, n| s += n; s }

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

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



190
191
192
# File 'lib/intel_hex/record.rb', line 190

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



203
204
205
# File 'lib/intel_hex/record.rb', line 203

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



171
172
173
174
175
176
177
178
179
# File 'lib/intel_hex/record.rb', line 171

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



119
120
121
122
# File 'lib/intel_hex/record.rb', line 119

def recalculate_checksum
  @calculated_checksum = nil
  calculate_checksum
end

#to_asciiObject



100
101
102
103
104
105
106
107
108
# File 'lib/intel_hex/record.rb', line 100

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

#to_sObject



96
97
98
# File 'lib/intel_hex/record.rb', line 96

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

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



194
195
196
197
198
199
200
201
# File 'lib/intel_hex/record.rb', line 194

def uint16_to_data(value, offset = 0)
  self.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=



207
208
209
210
211
212
213
214
215
216
# File 'lib/intel_hex/record.rb', line 207

def uint32_to_data(value, offset = 0)
  self.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)


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

def valid?
  begin
    validate
    return true
  rescue
    return false
  end
end

#validateObject



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

def validate
  validate_type
  validate_length
  validate_offset
  validate_data
  validate_checksum
end

#validate_checksumObject



167
168
169
# File 'lib/intel_hex/record.rb', line 167

def validate_checksum
  raise InvalidChecksumError.new("Checksum value #{checksum} does not match expected checksum #{calculate_checksum}") unless calculate_checksum == checksum
end

#validate_dataObject

Raises:



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

def validate_data
  raise InvalidDataError.new("Data length #{data.size} does not match length #{length}") unless data.size == length
end

#validate_lengthObject

Raises:



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/intel_hex/record.rb', line 150

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.new("Length for type #{type} must be #{valid_length}; #{length} given") 
end

#validate_offsetObject

Raises:



145
146
147
148
# File 'lib/intel_hex/record.rb', line 145

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

#validate_typeObject

Raises:



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

def validate_type
  raise InvalidTypeError.new("Type #{type} is invalid") unless TYPE_MAP.include?(type)
end