msp430_bsl 0.3.0 → 0.4.1

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: 35aba075d912b2875eecabcebfc4325f54af1cd3085d23249e9e54949797fe89
4
- data.tar.gz: 18e8e770e7259aac7c1585f38f94adaeba67689589363ba12f8a143b5fd1b66b
3
+ metadata.gz: fdfa8cabae9d6f5217854970766871bafec9efb729f1bba0d312e55065d3dfc2
4
+ data.tar.gz: 25dfc816f5e59d87b5df402c395248a0c09003e54be108608ec65bbf26715c11
5
5
  SHA512:
6
- metadata.gz: 95a9fd34842399eb965857bb83284d82d4f3a8b72f8912459c92f3dd57402c2d4599f9671b95c7bb91ad82595bc1326151f8bcdda0787aab069eb1bbaf58051f
7
- data.tar.gz: c24a4ba28dffbda9f6404c7bcbdfc2155cfe3a17c6f2c49d39a33c1c8fcdeb5e625c18f254d376e74e425b23d3c092c09bc912ffaecb4ff5ed16316371c599db
6
+ metadata.gz: 52ad0b1653f522000fafc6553e100beeff336e560ca9608fd91d804cfd124c334ebe60b4a70aebb19d358373b9d31b6efb11a5629f9659db43c04334d5d268a8
7
+ data.tar.gz: 671065d4376b40a99f9716e091cac284375f3bac2402b4300d16e6c19d741307a954b5dc6161728f0f682c1028eb3ba2100ef7ba218ca314acbd6dc416e17c07
data/bin/dump_flash ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'slop'
4
+ require_relative '../lib/msp430_bsl'
5
+
6
+ # Force sync on STDOUT write. This way the logger flushes its output after every write
7
+ STDOUT.sync = true
8
+
9
+ include Msp430Bsl::Utils
10
+
11
+ MAX_WRITE_ATTEMPTS = 3
12
+ SUPPORTED_OUTPUT_FORMATS = %w(hex raw_data)
13
+ EXTRACT_PASS_FROM_FILE_REGEX = /\:10FFE000(.{32})|\:10FFF000(.{32})/.freeze
14
+
15
+ @opts = {}
16
+ begin
17
+ @opts = Slop.parse help: true do |o|
18
+ o.string '-d', '--device', 'Mandatory: Path to serial programmer device', required: true
19
+ o.string '-o', '--outfile', 'Path to file where to save flash content. Default STDOUT', required: false
20
+ o.string '-g', '--logfile', 'Path to logfile'
21
+ o.string '-p', '--password', '32 bytes password string needed to unlock BSL. Defaults to 32 times 0xFF', default: Msp430Bsl::Configs::CMD_RX_PASSWORD
22
+ o.string '-t', '--extract_pass_from', 'Hex file path from where to extract the BSL password. Looks for the 32 words from 0xFFE0 to 0xFFFF'
23
+ o.array '-r', '--memrange', 'Memory range to read'
24
+ o.string '-s', '--memstartaddr', "Memory's starting address to read from. Defaults to 0x8000", default: 0x8000
25
+ o.string '-e', '--memendaddr', "Memory's last address to read. Defaults to 0xFFFF", default: 0x10000
26
+ o.string '-l', '--loglevel', "Logger level. One of ['fatal', 'error', 'warn', 'info', 'debug']. Default: 'info'", default: :info
27
+ o.string '-f', '--out_format', "Format of output. Supported formats: [hex, raw_data]. Default 'hex' (Intel hex)", default: 'hex'
28
+ o.integer '-b', '--baud', 'BAUD rate with which communicate to BSL. Default: 115200', default: 115200
29
+ o.bool '-h', '--help', 'Print this help' do
30
+ puts "#{o}\n"
31
+ exit
32
+ end
33
+ end
34
+ rescue Slop::MissingArgument => e
35
+ puts "Error: #{e}. Maybe you specified an empty argument?"
36
+ exit
37
+ rescue Slop::UnknownOption => e
38
+ puts "Error: #{e}"
39
+ exit
40
+ end
41
+
42
+ def logger
43
+ @logger ||= build_logger_from @opts
44
+ end
45
+
46
+ def outfile
47
+ @outfile ||= if @opts[:outfile]
48
+ File.open(File.expand_path(@opts[:outfile]), 'w')
49
+ else
50
+ STDOUT
51
+ end
52
+ end
53
+
54
+ # Validations
55
+ unless SUPPORTED_OUTPUT_FORMATS.include? @opts[:out_format]
56
+ logger.error "Output file format '#{@opts[:out_format]} is not supported. Supported formats: #{SUPPORTED_OUTPUT_FORMATS.join ','}'"
57
+ exit 1
58
+ end
59
+
60
+ unless Msp430Bsl::Configs::BAUD_RATES.include? @opts[:baud]
61
+ logger.error "BAUD rate #{@opts[:baud]} not supported. Available BAUD rates: #{ Msp430Bsl::Configs::BAUD_RATES.join ', ' }"
62
+ exit 2
63
+ end
64
+
65
+ if @opts[:memrange].any? && @opts[:memrange].size.odd?
66
+ logger.error "Memory ranges must be provided in pairs. Provided 'memrange' argument with #{@opts[:memrange].size} values => #{@opts[:memrange]}"
67
+ exit 3
68
+ end
69
+
70
+
71
+ # Conversions, normalizations, etc...
72
+ @opts[:memstartaddr] = @opts[:memstartaddr].to_i(16) rescue @opts[:memstartaddr]
73
+ @opts[:memendaddr] = @opts[:memendaddr].to_i(16) rescue @opts[:memendaddr]
74
+
75
+ # If memrange has been provided, convert values to integers parsing as hex
76
+ # else set memrange as [memstartaddr, memendaddr]
77
+ if @opts[:memrange].any?
78
+ @opts[:memrange].map! { |el| el.to_i(16) }
79
+ else
80
+ @opts[:memrange] = [ @opts[:memstartaddr], @opts[:memendaddr] ]
81
+ end
82
+
83
+ # If password param has been provided, convert given string
84
+ if @opts[:password] && !@opts[:password].eql?(Msp430Bsl::Configs::CMD_RX_PASSWORD)
85
+ @opts[:password] = @opts[:password].scan(EXTRACT_PASS_FROM_FILE_REGEX).flatten.compact.join.to_hex_ary
86
+ unless @opts[:password].any?
87
+ logger.error "Wrong password provided. Please copy entirely hex file rows staring with :10FFE0 and :10FFF0"
88
+ exit
89
+ end
90
+ end
91
+ # If extract_pass_from param has been provided, extract BSL password from given file path
92
+ if @opts[:extract_pass_from]
93
+ logger.info "Extracting BSL password from #{@opts[:extract_pass_from]}"
94
+ file_content = File.read @opts[:extract_pass_from]
95
+ lines = file_content.scan(EXTRACT_PASS_FROM_FILE_REGEX).flatten.compact
96
+ @opts[:password] = lines.map { |line| line.scan(/.{2}/).map { |el| el.to_i 16 }}.flatten
97
+ logger.debug "BSL pass: #{@opts[:password].to_hex.join}"
98
+ end
99
+
100
+ # Handy methods
101
+
102
+ # def can_we_ask_another_line?(already_asked_count:, from_addr: , to_addr:, line_size:)
103
+ # # We can't exceed Msp430Bsl::Configs::PURE_DATA_MAX_SIZE
104
+ # return false if (Msp430Bsl::Configs::PURE_DATA_MAX_SIZE - (already_asked_count * line_size)) < line_size
105
+ #
106
+ # # We can't ask lines beyond memendaddr memory address
107
+ # return false if (from_addr + ((already_asked_count + 1) * line_size)) >= to_addr
108
+ #
109
+ # true
110
+ # end
111
+
112
+ def num_of_bytes_to_fetch(from_addr, to_addr)
113
+ [Msp430Bsl::Configs::PURE_DATA_MAX_SIZE, (to_addr - from_addr)].min
114
+ end
115
+
116
+
117
+ ### Core
118
+
119
+ # Build UART Connection
120
+ @board = Msp430Bsl::Uart::Connection.new @opts[:device], logger: logger
121
+
122
+ # Enter BSL
123
+ @board.enter_bsl
124
+ logger.info "Unlocking BSL's password protected commands"
125
+ @board.send_command :rx_password, data: @opts[:password]
126
+ @board.send_command :lock_unlock_info
127
+ # Switch UART to max speed
128
+ logger.info "Changing UART BAUD to #{@opts[:baud]}"
129
+ @board.send_command :change_baud_rate, data: Msp430Bsl::Configs::BAUD_RATES[@opts[:baud]]
130
+ @board.set_uart_speed @opts[:baud]
131
+
132
+ data_file = case @opts[:out_format]
133
+ when 'hex', :hex
134
+ Msp430Bsl::HexFile.new
135
+ when 'raw_data', :raw_data
136
+ Msp430Bsl::RawDataFile.new
137
+ else
138
+ Msp430Bsl::HexFile.new
139
+ end
140
+
141
+ logger.info "Reading flash content..."
142
+
143
+ @opts[:memrange].each_slice(2) do |range|
144
+ current_addr = range[0]
145
+ endaddr = range[1]
146
+ fetched_data = []
147
+ while current_addr < endaddr
148
+ num_bytes = num_of_bytes_to_fetch current_addr, endaddr
149
+
150
+ logger.debug "fetching #{num_bytes} bytes from addr 0x#{current_addr.to_hex_str} to addr 0x#{(current_addr + num_bytes).to_hex_str}"
151
+ resp = @board.send_command :tx_data_block, addr: current_addr, data: num_bytes.to_bytes_ary
152
+ fetched_data << resp.data
153
+ current_addr += num_bytes
154
+ end
155
+
156
+ data_file.add_new_lines_from(fetched_data.flatten, range[0])
157
+ end
158
+
159
+ outfile.write data_file
160
+ outfile.write "\n\n"
161
+
162
+ # Reset board if requested to
163
+ if @opts[:reset]
164
+ logger.info "Resetting board"
165
+ @board.trigger_reset
166
+ end
167
+ logger.info "Closing connection"
168
+ @board.close_connection
169
+ if outfile != STDOUT
170
+ logger.info "Flash content dumped to #{outfile.path}"
171
+ end
data/bin/upload_hex CHANGED
@@ -9,6 +9,7 @@ STDOUT.sync = true
9
9
  include Msp430Bsl::Utils
10
10
 
11
11
  MAX_WRITE_ATTEMPTS = 3
12
+ EXTRACT_PASS_FROM_FILE_REGEX = /\:10FFE000(.{32})|\:10FFF000(.{32})/.freeze
12
13
 
13
14
  @opts = {}
14
15
  begin
@@ -16,9 +17,13 @@ begin
16
17
  o.string '-d', '--device', 'Mandatory: Path to serial programmer device', required: true
17
18
  o.string '-f', '--hexfile', 'Mandatory: Path to HEX file to load', required: true
18
19
  o.string '-g', '--logfile', 'Path to logfile'
19
- o.string '-l', '--loglevel', "Logger level. One of ['fatal', 'error', 'warn', 'info', 'debug']. Default: 'debug'", default: :debug
20
+ o.string '-l', '--loglevel', "Logger level. One of ['fatal', 'error', 'warn', 'info', 'debug']. Default: 'info'", default: :info
20
21
  o.integer '-b', '--baud', 'BAUD rate with which communicate to BSL. Default: 115200', default: 115200
22
+ o.string '-p', '--password', '32 bytes password string needed to unlock BSL. Defaults to 32 times 0xFF', default: Msp430Bsl::Configs::CMD_RX_PASSWORD
23
+ o.string '-t', '--extract_pass_from', 'Hex file path from where to extract the BSL password. Looks for the 32 words from 0xFFE0 to 0xFFFF'
24
+ o.bool '-r', '--reset', 'Reset board after a successful upload', default: false
21
25
  o.bool '-e', '--erase_info', 'Erase info memory. Default: false', default: false # TODO: implement
26
+ o.bool '-n', '--no_mass_erase', 'Skip mass erase. Default: false (By default flash gets totally erased)', default: false
22
27
  o.bool '-c', '--check', 'Verify flash content after each data block write. Default: true', default: true
23
28
  o.bool '-h', '--help', 'Print this help' do
24
29
  puts "#{o}\n"
@@ -33,41 +38,83 @@ rescue Slop::UnknownOption => e
33
38
  exit
34
39
  end
35
40
 
36
- logger = build_logger_from @opts
41
+ def logger
42
+ @logger ||= build_logger_from @opts
43
+ end
37
44
 
38
45
  unless Msp430Bsl::Configs::BAUD_RATES.include? @opts[:baud]
39
46
  logger.error "BAUD rate #{@opts[:baud]} not supported. Available BAUD rates: #{ Msp430Bsl::Configs::BAUD_RATES.join ', ' }"
40
47
  exit
41
48
  end
42
49
 
50
+ # If password param has been provided, convert given string
51
+ if @opts[:password] && !@opts[:password].eql?(Msp430Bsl::Configs::CMD_RX_PASSWORD)
52
+ @opts[:password] = @opts[:password].scan(EXTRACT_PASS_FROM_FILE_REGEX).flatten.compact.join.to_hex_ary
53
+ unless @opts[:password].any?
54
+ logger.error "Wrong password provided. Please copy entirely hex file rows staring with :10FFE0 and :10FFF0"
55
+ exit
56
+ end
57
+ end
58
+
59
+ # If extract_pass_from param has been provided, extract BSL password from given file path
60
+ if @opts[:extract_pass_from]
61
+ logger.info "Extracting BSL password from #{@opts[:extract_pass_from]}"
62
+ file_content = File.read @opts[:extract_pass_from]
63
+ lines = file_content.scan(EXTRACT_PASS_FROM_FILE_REGEX).flatten.compact
64
+ @opts[:password] = lines.map { |line| line.scan(/.{2}/).map { |el| el.to_i 16 }}.flatten
65
+ logger.debug "BSL pass: #{@opts[:password].to_hex.join}"
66
+ end
67
+
43
68
  # Build UART Connection
44
69
  @board = Msp430Bsl::Uart::Connection.new @opts[:device], logger: logger
45
70
 
46
71
  # Enter BSL
47
72
  @board.enter_bsl
48
73
  # Mass erase FLASH
49
- logger.info 'Mass erasing FLASH'
50
- @board.send_command :mass_erase
51
- # Unlock BSL protected commands
74
+ if !@opts[:no_mass_erase]
75
+ logger.info 'Mass erasing FLASH'
76
+ @board.send_command :mass_erase
77
+ end
52
78
  logger.info "Unlocking BSL's password protected commands"
53
- @board.send_command :rx_password, data: Msp430Bsl::Configs::CMD_RX_PASSWORD
79
+ @board.send_command :rx_password, data: @opts[:password]
80
+
54
81
  # Switch UART to max speed
55
82
  logger.info "Changing UART BAUD to #{@opts[:baud]}"
56
83
  @board.send_command :change_baud_rate, data: Msp430Bsl::Configs::BAUD_RATES[@opts[:baud]]
57
84
  @board.set_uart_speed @opts[:baud]
58
85
 
59
86
  # If everything has gone well so far...
60
- hexfile = Msp430Bsl::HexFile.new @opts[:hexfile]
87
+ hexfile = Msp430Bsl::HexFile.load @opts[:hexfile]
61
88
 
62
89
  # Group lines by contiguous memory addr
63
90
  logger.info 'Writing data to FLASH'
64
91
  line_groups = hexfile.data_lines_grouped_by_contiguous_addr
65
92
 
93
+ @erased_segments = []
66
94
  def write_data_packet(lines_packet, check: true)
67
95
  attempts = 0
68
96
  loop do
69
- # Write data to FLASH
70
- resp = @board.send_command :rx_data_block, addr: lines_packet.first.addr, data: lines_packet.map { |line| line.data }.reduce(:+)
97
+ addr = lines_packet.first.addr
98
+ data = lines_packet.map { |line| line.data }.reduce(:+)
99
+ if @opts[:no_mass_erase]
100
+ starting_segment_addr = (addr / 0x200) * 0x200
101
+ ending_segment_addr = ((addr + data.size - 1) / 0x200) * 0x200
102
+ logger.debug "Starting segment addr: #{starting_segment_addr.to_hex_str} - Must erase: #{!@erased_segments.include? starting_segment_addr }"
103
+ logger.debug "Ending segment addr: #{ending_segment_addr.to_hex_str} - Must erase: #{!@erased_segments.include? ending_segment_addr}"
104
+ if !@erased_segments.include? starting_segment_addr
105
+ @board.send_command(:erase_segment, addr: starting_segment_addr)
106
+ end
107
+ if !@erased_segments.include? ending_segment_addr
108
+ @board.send_command(:erase_segment, addr: ending_segment_addr)
109
+ end
110
+
111
+ @erased_segments << starting_segment_addr
112
+ @erased_segments << ending_segment_addr
113
+ @erased_segments.uniq!
114
+ end
115
+
116
+ # Write data to FLASH*
117
+ resp = @board.send_command :rx_data_block, addr: addr, data: data
71
118
 
72
119
  break resp unless check
73
120
  # Check written data
@@ -92,26 +139,32 @@ def write_data_packet(lines_packet, check: true)
92
139
  end
93
140
  end
94
141
 
142
+ def is_there_still_room_for?(next_line, into:) # :into must be the curr_data_packet
143
+ pure_data_length = into.sum { |line| line.data_length } + next_line.data_length
144
+ return false if pure_data_length > Msp430Bsl::Configs::PURE_DATA_MAX_SIZE
145
+
146
+ total_packet_length = pure_data_length + Msp430Bsl::Uart::PeripheralInterface::TOTAL_SIZE
147
+ return false if total_packet_length > Msp430Bsl::Configs::CORE_COMMANDS_BUFFER_SIZE
148
+
149
+ true
150
+ end
151
+
95
152
  # Try to optimize BSL writes
96
153
  # For each lines group, append as many lines as possible, given the BSL Core Commands buffer size
97
154
  line_groups.each do |group|
98
155
  curr_data_packet = []
99
- curr_data_size = 0
100
156
  # Cycle lines in a group
101
157
  group.each do |line|
102
158
  if curr_data_packet.empty?
103
159
  # Use current line's addr as packet addr
104
160
  curr_data_packet << line
105
- curr_data_size += line.data_length + Msp430Bsl::Uart::PeripheralInterface::TOTAL_SIZE
106
- elsif (curr_data_size + line.data_length) <= Msp430Bsl::Uart::Connection::CORE_COMMANDS_BUFFER_SIZE
161
+ elsif is_there_still_room_for?(line, into: curr_data_packet)
107
162
  # If there's still room, append the line data
108
163
  curr_data_packet << line
109
- curr_data_size += line.data_length
110
164
  else
111
165
  # No room left, send packet
112
166
  write_data_packet curr_data_packet, check: @opts[:check]
113
167
  curr_data_packet = []
114
- curr_data_size = 0
115
168
  redo # Handle current line than would otherwise be skipped
116
169
  end
117
170
  end
@@ -122,8 +175,11 @@ line_groups.each do |group|
122
175
  end
123
176
  end
124
177
 
125
- # TODO: Verify CRC or read entire flash and compare to hex lines?
126
-
178
+ # Reset board if requested to
179
+ if @opts[:reset]
180
+ logger.info "Resetting board"
181
+ @board.trigger_reset
182
+ end
127
183
  logger.info 'Closing connection'
128
184
  @board.close_connection
129
185
  logger.info 'Upload done!'
@@ -7,9 +7,16 @@ class Numeric
7
7
  n
8
8
  end
9
9
 
10
- def to_bytes_ary
10
+ def to_bytes_ary(le: true, padding: 2)
11
11
  res = []
12
12
  to_hex_str.chars.each_slice(2) { |byte| res << byte.join().to_i(16) }
13
+ if res.size < padding
14
+ res.prepend Array.new(padding - res.size) { 0 }
15
+ res.flatten!
16
+ end
17
+ if le
18
+ res.reverse!
19
+ end
13
20
  res
14
21
  end
15
22
 
@@ -33,14 +33,11 @@ module Msp430Bsl
33
33
  @packet = [code, splitted_addr, data].flatten.compact
34
34
  end
35
35
 
36
- def length
37
- code.to_bytes_ary.length
38
- end
39
-
40
36
  # Split address to [low, middle, high] bytes
41
37
  def splitted_addr
42
38
  if addr
43
- [ (addr & 0xFF), ((addr >> 8) & 0xFF), ((addr >> 16) & 0xFF) ]
39
+ # [ (addr & 0xFF), ((addr >> 8) & 0xFF), ((addr >> 16) & 0xFF) ]
40
+ addr.to_bytes_ary padding: 3
44
41
  end
45
42
  end
46
43
 
@@ -44,5 +44,13 @@ module Msp430Bsl
44
44
  57600 => 0x05,
45
45
  115200 => 0x06
46
46
  }.freeze
47
+
48
+ CORE_COMMANDS_BUFFER_SIZE = 260
49
+ PURE_DATA_MAX_SIZE = 250
50
+
51
+ def self.reponse_reason_by_code(code)
52
+ message = RESPONSE_MESSAGES.find { |message, data| data[:code] == code }
53
+ message && message.last[:reason]
54
+ end
47
55
  end
48
56
  end
@@ -0,0 +1,32 @@
1
+ module Msp430Bsl
2
+ class DataFile
3
+
4
+ LINE_DATA_SIZE = Configs::PURE_DATA_MAX_SIZE
5
+
6
+ attr_reader :path, :raw_data, :lines
7
+
8
+ def initialize
9
+ @lines = []
10
+ end
11
+
12
+ def add_new_lines_from(data, starting_addr)
13
+ curr_addr = starting_addr
14
+ data.each_slice(line_data_size) do |slice|
15
+ @lines << new_line_from(slice, curr_addr)
16
+ curr_addr += line_data_size
17
+ end
18
+ end
19
+
20
+ def <<(line)
21
+ @lines << line
22
+ end
23
+
24
+ def line_data_size
25
+ self.class::LINE_DATA_SIZE
26
+ end
27
+
28
+ def new_line_from(data, addr, type: :data)
29
+ raise NotImplementedError, 'You must implement this method in a subclass'
30
+ end
31
+ end
32
+ end
@@ -1,19 +1,16 @@
1
1
  module Msp430Bsl
2
- class HexFile
2
+ class HexFile < DataFile
3
3
 
4
- attr_reader :path, :raw_data
4
+ LINE_DATA_SIZE = 0x10.freeze
5
5
 
6
- def initialize(path)
7
- @path = File.expand_path path
8
- @raw_data = File.read path
9
- end
10
-
11
- def lines
12
- return @lines if @lines
13
-
14
- @lines = []
15
- raw_data.each_line.with_index { |line, i| @lines << HexLine.new(line, num: i) }
16
- @lines
6
+ class << self
7
+ def load(path)
8
+ path = File.expand_path path
9
+ raw_data = File.read path
10
+ hexfile = new
11
+ hexfile.load_lines_from raw_data
12
+ hexfile
13
+ end
17
14
  end
18
15
 
19
16
  def data_lines_grouped_by_contiguous_addr
@@ -47,5 +44,28 @@ module Msp430Bsl
47
44
 
48
45
  @grouped_lines
49
46
  end
47
+
48
+ def load_lines_from(raw_data)
49
+ raw_data.each_line.with_index do |line, i|
50
+ line.strip!
51
+ next if line.empty?
52
+
53
+ @lines << HexLine.new(line, num: i)
54
+ end
55
+ end
56
+
57
+ def raw_data
58
+ @lines.map { |l| l.data.to_hex }.join("\n")
59
+ end
60
+
61
+ def new_line_from(data, addr, type: :data)
62
+ data_str = "#{data.size.to_hex_str}#{addr.to_hex_str}#{HexLine::RECORD_TYPES[type].to_hex_str}#{data.to_hex.join}"
63
+ data_str = ":#{data_str}#{crc8(data_str.to_hex_ary).to_hex_str}"
64
+ HexLine.new data_str
65
+ end
66
+
67
+ def to_s
68
+ @lines.map(&:to_s).join("\n")
69
+ end
50
70
  end
51
71
  end
@@ -3,6 +3,7 @@
3
3
  module Msp430Bsl
4
4
  class HexLine
5
5
  include Utils
6
+ extend Utils
6
7
 
7
8
  attr_reader :raw_data, :data_length, :addr, :type, :data, :crc, :number, :end_addr
8
9
 
@@ -19,12 +20,21 @@ module Msp430Bsl
19
20
  raise StandardError, 'raw_data must be a String' unless data.is_a?(String)
20
21
 
21
22
  # Strip String, remove first char i.e. ':' and convert char couples to its hex value.
22
- @raw_data = data.strip[1..-1].to_hex_ary
23
+ if data[0] == ':'
24
+ @raw_data = data.strip[1..-1]
25
+ end
26
+ # Convert raw data to hex array
27
+ @raw_data = @raw_data.to_hex_ary
23
28
 
29
+ # Extract data length
24
30
  @data_length = raw_data[0]
31
+ # Extract addr
25
32
  @addr = (raw_data[1] << 8) | raw_data[2]
33
+ # Extract line type
26
34
  @type = raw_data[3]
35
+ # Extract data
27
36
  @data = raw_data.slice 4, data_length
37
+ # Extract CRC
28
38
  @crc = raw_data[-1]
29
39
  @number = num
30
40
  @end_addr = addr + data_length
@@ -44,5 +54,9 @@ module Msp430Bsl
44
54
  ty = ty.to_sym
45
55
  type == RECORD_TYPES[ty]
46
56
  end
57
+
58
+ def to_s
59
+ ":#{@data_length.to_hex_str}#{@addr.to_hex_str}#{@type.to_hex_str}#{data.to_hex.join}#{@crc.to_hex_str}"
60
+ end
47
61
  end
48
62
  end
@@ -0,0 +1,12 @@
1
+ module Msp430Bsl
2
+ class RawDataFile < DataFile
3
+
4
+ def to_s
5
+ @lines.map { |l| l.to_hex }.join
6
+ end
7
+
8
+ def new_line_from(data, addr, type: :data)
9
+ data
10
+ end
11
+ end
12
+ end
@@ -53,11 +53,15 @@ module Msp430Bsl
53
53
  if is_message?
54
54
  success_code = Configs::RESPONSE_MESSAGES[:success][:code]
55
55
  if data[0] != success_code # First (and only) data byte is message code
56
- @errors << [:message_code, "Message code NOK. Expected message code '#{success_code}', got '#{data[0]}'"]
56
+ @errors << [:message_code, "Message code NOK. Expected message code '#{success_code}', got '#{data[0]}' that should mean: '#{Configs.reponse_reason_by_code(data[0])}'"]
57
57
  end
58
58
  end
59
59
 
60
60
  @errors.empty?
61
61
  end
62
+
63
+ def inspect
64
+ data.to_hex
65
+ end
62
66
  end
63
67
  end
@@ -11,19 +11,15 @@ module Msp430Bsl
11
11
  WAIT_FOR_ACK_MAX = 1000.millis
12
12
  WAIT_FOR_RESPONSE_MAX = 1000.millis
13
13
 
14
- MEM_START_MAIN_FLASH = 0x8000
15
-
16
- CORE_COMMANDS_BUFFER_SIZE = 260
17
-
18
14
  attr_reader :serial_port, :device_path, :logger, :cmd_buff_size
19
15
 
20
16
  def initialize(device_path, opts = {})
21
17
  @device_path = device_path
22
18
  @logger = opts.fetch :logger, Logger.new(STDOUT)
23
- @cmd_buff_size = opts.fetch :cmd_buf_size, CORE_COMMANDS_BUFFER_SIZE
19
+ @cmd_buff_size = opts.fetch :cmd_buf_size, Configs::CORE_COMMANDS_BUFFER_SIZE
24
20
 
25
21
  @serial_port = SerialPort.new @device_path
26
- @serial_port.flow_control = SerialPort::NONE
22
+ @serial_port.flow_control = SerialPort::SOFT
27
23
  end
28
24
 
29
25
  def close_connection
@@ -92,7 +88,7 @@ module Msp430Bsl
92
88
  response
93
89
  end
94
90
 
95
- def send_command(cmd_name, addr: nil, data: nil, log_only: false)
91
+ def send_command(cmd_name, addr: nil, data: nil)
96
92
  command = Command.new cmd_name, addr: addr, data: data
97
93
  pi = PeripheralInterface.wrap command
98
94
  logger.debug "Sending command '#{command.name}' over UART"
@@ -102,18 +98,17 @@ module Msp430Bsl
102
98
 
103
99
  unless pi.valid?
104
100
  logger.error "PeripheralInterface not valid. Errors: #{pi.errors}"
105
- return nil
101
+ raise Exceptions::PeripheralInterface::NotValid, pi.errors
106
102
  end
107
103
 
108
104
  logger.debug "OUT -> (#{pi.packet.size} bytes) #{pi.to_hex_ary_str}"
109
- unless log_only
110
- serial_port.write pi.to_uart
111
- read_response_for command
112
- end
105
+
106
+ serial_port.write pi.to_uart
107
+ read_response_for command
113
108
  end
114
109
 
115
110
  def set_uart_speed(baud)
116
- raise StandardError, "BAUD not supported. Supported BAUD: #{Configs::BAUD_RATES.keys}" unless Configs::BAUD_RATES.keys.include?(baud)
111
+ raise StandardError, "BAUD not supported. Supported BAUDs: #{Configs::BAUD_RATES.keys}" unless Configs::BAUD_RATES.keys.include?(baud)
117
112
 
118
113
  logger.debug "Setting serial port BAUD to #{baud} bps"
119
114
 
@@ -123,7 +118,7 @@ module Msp430Bsl
123
118
  end
124
119
 
125
120
  def trigger_reset
126
- # slau319 pag. 5 - Fig. 1-1
121
+ # slau319af.pdf - pag. 5 - Fig. 1-1
127
122
  reset_pin_go :low
128
123
  test_pin_go :low
129
124
  sleep 5.millis
@@ -24,35 +24,41 @@ module Msp430Bsl
24
24
  end
25
25
 
26
26
  module PeripheralInterface
27
- class InterfaceWrapNotACommand < StandardError
27
+ class NotValid < StandardError
28
+ def initialize(errors)
29
+ message = "PeripheralInterface not valid. Errors: '#{errors}'"
30
+ super(message)
31
+ end
32
+ end
33
+ class DoesNotWrapACommand < StandardError
28
34
  def initialize(arg)
29
35
  message = "Given argument '#{arg}' must be a Msp430Bsl::Command"
30
36
  super(message)
31
37
  end
32
38
  end
33
39
 
34
- class InterfaceParseRawDataNotArray < StandardError
40
+ class ParsedRawDataAreNotAnArray < StandardError
35
41
  def initialize
36
42
  message = "PeripheralInterface#parse argument must be an Array"
37
43
  super(message)
38
44
  end
39
45
  end
40
46
 
41
- class InterfaceDataNotArray < StandardError
47
+ class DataAreNotAnArray < StandardError
42
48
  def initialize
43
49
  message = "Peripheral Interface 'data' argument must be an Array"
44
50
  super(message)
45
51
  end
46
52
  end
47
53
 
48
- class InterfaceSize < StandardError
54
+ class DataSizeError < StandardError
49
55
  def initialize(received_size)
50
56
  message = "Peripheral Interface size error. Required packet's min size is '#{PeripheralInterface::MIN_PACKET_SIZE}' bytes, given raw_data size is '#{received_size}' bytes"
51
57
  super(message)
52
58
  end
53
59
  end
54
60
 
55
- class InterfaceHeaderNOK < StandardError
61
+ class HeaderNOK < StandardError
56
62
  def initialize(received_header)
57
63
  message = "Peripheral interface header NOK. Received '0x#{received_header.to_hex_str}' instead of 0x#{PeripheralInterface::OK_HEADER.to_hex_str}"
58
64
  super(message)
@@ -60,7 +66,7 @@ module Msp430Bsl
60
66
 
61
67
  end
62
68
 
63
- class InterfaceCRCMismatch < StandardError
69
+ class CRCMismatch < StandardError
64
70
  def initialize
65
71
  message = 'Peripheral Interface CRC mismatch'
66
72
  super(message)
@@ -18,15 +18,15 @@ module Msp430Bsl
18
18
 
19
19
  def wrap(command)
20
20
  unless command.is_a?(Command)
21
- raise Exceptions::PeripheralInterfaceWrapNotACommand, command
21
+ raise Exceptions::PeripheralInterface::DoesNotWrapACommand, command
22
22
  end
23
23
 
24
24
  new header: OK_HEADER, data_len: command.packet.size, data: command.packet
25
25
  end
26
26
 
27
27
  def parse(raw_data)
28
- raise Exceptions::PeripheralInterfaceParseRawDataNotArray unless raw_data.is_a?(Array)
29
- raise Exceptions::PeripheralInterfaceSize, raw_data.size unless raw_data.size >= MIN_PACKET_SIZE
28
+ raise Exceptions::PeripheralInterface::ParsedRawDataAreNotAnArray unless raw_data.is_a?(Array)
29
+ raise Exceptions::PeripheralInterface::DataSizeError, raw_data.size unless raw_data.size >= MIN_PACKET_SIZE
30
30
 
31
31
  header = raw_data[0]
32
32
  data_len = raw_data[2] << 8 | raw_data[1]
@@ -40,7 +40,7 @@ module Msp430Bsl
40
40
  attr_reader :header, :data_len, :data, :crc, :errors, :packet, :cmd_kind
41
41
 
42
42
  def initialize(header: nil, data_len: nil, data: nil, crc: nil)
43
- raise Exceptions::PeripheralInterfaceDataNotArray if (data && !data.is_a?(Array))
43
+ raise Exceptions::PeripheralInterface::DataAreNotAnArray if (data && !data.is_a?(Array))
44
44
 
45
45
  @header = header
46
46
  @data_len = data_len
@@ -1,3 +1,3 @@
1
1
  module Msp430Bsl
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.4.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msp430_bsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Verlato
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-10-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: zeitwerk
@@ -30,14 +29,14 @@ dependencies:
30
29
  requirements:
31
30
  - - '='
32
31
  - !ruby/object:Gem::Version
33
- version: 1.3.2
32
+ version: 1.4.0
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - '='
39
38
  - !ruby/object:Gem::Version
40
- version: 1.3.2
39
+ version: 1.4.0
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: slop
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -59,23 +58,24 @@ dependencies:
59
58
  - - '='
60
59
  - !ruby/object:Gem::Version
61
60
  version: 0.14.2
62
- type: :runtime
61
+ type: :development
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - '='
67
66
  - !ruby/object:Gem::Version
68
67
  version: 0.14.2
69
- description:
70
68
  email:
71
69
  - averlato@gmail.com
72
70
  executables:
71
+ - dump_flash
73
72
  - upload_hex
74
73
  extensions: []
75
74
  extra_rdoc_files: []
76
75
  files:
77
76
  - MIT-LICENSE
78
77
  - README.md
78
+ - bin/dump_flash
79
79
  - bin/upload_hex
80
80
  - lib/core_ext/array.rb
81
81
  - lib/core_ext/number.rb
@@ -83,9 +83,11 @@ files:
83
83
  - lib/msp430_bsl.rb
84
84
  - lib/msp430_bsl/command.rb
85
85
  - lib/msp430_bsl/configs.rb
86
+ - lib/msp430_bsl/data_file.rb
86
87
  - lib/msp430_bsl/exceptions.rb
87
88
  - lib/msp430_bsl/hex_file.rb
88
89
  - lib/msp430_bsl/hex_line.rb
90
+ - lib/msp430_bsl/raw_data_file.rb
89
91
  - lib/msp430_bsl/response.rb
90
92
  - lib/msp430_bsl/uart/ack.rb
91
93
  - lib/msp430_bsl/uart/connection.rb
@@ -97,7 +99,6 @@ homepage: https://github.com/madAle/msp430_bsl
97
99
  licenses:
98
100
  - MIT
99
101
  metadata: {}
100
- post_install_message:
101
102
  rdoc_options: []
102
103
  require_paths:
103
104
  - lib
@@ -112,8 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
113
  - !ruby/object:Gem::Version
113
114
  version: '0'
114
115
  requirements: []
115
- rubygems_version: 3.4.20
116
- signing_key:
116
+ rubygems_version: 3.6.9
117
117
  specification_version: 4
118
118
  summary: Texas Instrument MSP430 BSL Ruby library
119
119
  test_files: []