msp430_bsl 0.0.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 +7 -0
- data/MIT-LICENSE +21 -0
- data/README.md +56 -0
- data/bin/upload_hex +86 -0
- data/lib/core_ext/array.rb +13 -0
- data/lib/core_ext/number.rb +19 -0
- data/lib/core_ext/string.rb +8 -0
- data/lib/msp430_bsl/command.rb +60 -0
- data/lib/msp430_bsl/configs.rb +48 -0
- data/lib/msp430_bsl/exceptions.rb +51 -0
- data/lib/msp430_bsl/hex_file.rb +51 -0
- data/lib/msp430_bsl/hex_line.rb +47 -0
- data/lib/msp430_bsl/response.rb +63 -0
- data/lib/msp430_bsl/uart/ack.rb +35 -0
- data/lib/msp430_bsl/uart/connection.rb +196 -0
- data/lib/msp430_bsl/uart/exceptions.rb +68 -0
- data/lib/msp430_bsl/uart/peripheral_interface.rb +136 -0
- data/lib/msp430_bsl/utils.rb +46 -0
- data/lib/msp430_bsl/version.rb +3 -0
- data/lib/msp430_bsl.rb +14 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ca5ed6ae2b592007808e73255f2f1de59c096f5b2e5702ad86fb7dea7c586981
|
4
|
+
data.tar.gz: 6c289eaece5e0fe084ddba9f5847c87da017c51db2825c44d4463a6a10db7e7f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 327080fb207aabed5bdd0df53f84555268eaf251118c935ee9414547bd437df954b8704cfdd969e0a2cf60e296d9b01a9bf600222fd7a2c96a4f8ca423bf43bd
|
7
|
+
data.tar.gz: 3e8b706fc043fa9048b191e44a5deab69790202418dbbeb51ce93e1ea388637b61847c8cc79129ac6ab1d0a5d0cf4f79f4941263f408e975e9d6341058ea1fec
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Alessandro Verlato
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# MSP430Bsl
|
2
|
+
|
3
|
+
This library is a base for developing MSP430 BSL-based utilities
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'msp430_bsl'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install msp430_bsl
|
20
|
+
|
21
|
+
## Compatibility
|
22
|
+
|
23
|
+
Although it's not tested, this library should be compatibile with Ruby 2.7.0 or higher.
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
**Help is appreciated to write some good USAGE**
|
28
|
+
|
29
|
+
In the `bin` folder there's the `upload_hex` executable.
|
30
|
+
|
31
|
+
TL;DR: the script can upload a .hex file to the target through a normal UART connection (`rts` and `dtr` pins required).
|
32
|
+
|
33
|
+
**The script has been tested only with CC430F5137**
|
34
|
+
|
35
|
+
Just run `bin/upload_hex -h` to show available options.
|
36
|
+
|
37
|
+
## TODO
|
38
|
+
|
39
|
+
* Write specs
|
40
|
+
* Add documentation
|
41
|
+
* Write a good Usage
|
42
|
+
* Add missing features and generalize the ones already present
|
43
|
+
* Delete this TODO section
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
**Bug reports and pull requests are welcome!**
|
48
|
+
|
49
|
+
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
|
50
|
+
the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
51
|
+
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
56
|
+
|
data/bin/upload_hex
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
Bundler.require
|
5
|
+
require 'slop'
|
6
|
+
require_relative '../lib/msp430_bsl'
|
7
|
+
|
8
|
+
begin
|
9
|
+
opts = Slop.parse help: true do |o|
|
10
|
+
o.string '-d', '--device', 'Mandatory: Path to serial programmer device', required: true
|
11
|
+
o.string '-f', '--hexfile', 'Mandatory: Path to HEX file to load', required: true
|
12
|
+
o.string '-g', '--logfile', 'Path to logfile'
|
13
|
+
o.string '-l', '--loglevel', "Logger level. One of ['fatal', 'error', 'warn', 'info', 'debug']. Defaults to 'debug'", default: :debug
|
14
|
+
o.bool '-c', '--check', 'Verify flash content after upload', default: true
|
15
|
+
o.bool '-h', '--help', 'Print this help' do
|
16
|
+
puts "#{o}\n"
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
rescue Slop::MissingArgument => e
|
21
|
+
puts "Error: #{e}. Maybe you specified an empty argument?"
|
22
|
+
exit
|
23
|
+
rescue Slop::UnknownOption => e
|
24
|
+
puts "Error: #{e}"
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
include Msp430Bsl::Utils
|
29
|
+
|
30
|
+
logger = build_logger_from opts
|
31
|
+
|
32
|
+
@board = Msp430Bsl::Uart::Connection.new opts[:device], logger: logger
|
33
|
+
|
34
|
+
# Enter BSL
|
35
|
+
@board.enter_bsl
|
36
|
+
# Mass erase FLASH
|
37
|
+
logger.info 'Mass erasing FLASH'
|
38
|
+
@board.send_command :mass_erase
|
39
|
+
# Unlock BSL protected commands
|
40
|
+
logger.info "'Unlocking BSL's password protected commands'"
|
41
|
+
@board.send_command :rx_password, data: Msp430Bsl::Configs::CMD_RX_PASSWORD
|
42
|
+
# Switch UART to max speed
|
43
|
+
logger.info 'Changing UART BAUD to 115200'
|
44
|
+
@board.send_command :change_baud_rate, data: Msp430Bsl::Configs::BAUD_RATES[115200]
|
45
|
+
@board.set_uart_speed 115200
|
46
|
+
|
47
|
+
# If everything has gone well so far...
|
48
|
+
hexfile = Msp430Bsl::HexFile.new opts[:hexfile]
|
49
|
+
|
50
|
+
# Group lines by contiguous memory addr
|
51
|
+
logger.info 'Writing data into FLASH'
|
52
|
+
line_groups = hexfile.data_lines_grouped_by_contiguous_addr
|
53
|
+
# Try to optimize BSL writes
|
54
|
+
# For each lines group, append as many lines as possible, given the BSL Core Commands buffer size
|
55
|
+
line_groups.each do |group|
|
56
|
+
curr_data_packet = []
|
57
|
+
curr_data_size = 0
|
58
|
+
# Cycle lines in a group
|
59
|
+
group.each do |line|
|
60
|
+
if curr_data_packet.empty?
|
61
|
+
# Use current line's addr as packet addr
|
62
|
+
curr_data_packet << line
|
63
|
+
curr_data_size += 2 + line.data_length # 2 is the addr size (2 bytes)
|
64
|
+
elsif (curr_data_size + line.data_length) <= Msp430Bsl::Uart::Connection::CORE_COMMANDS_BUFFER_SIZE
|
65
|
+
# If there's still room, append the line data
|
66
|
+
curr_data_packet << line
|
67
|
+
curr_data_size += line.data_length
|
68
|
+
else
|
69
|
+
# No room left, send packet
|
70
|
+
@board.send_command :rx_data_block, addr: curr_data_packet.first.addr, data: curr_data_packet.map { |line| line.data }.reduce(:+)
|
71
|
+
curr_data_packet = []
|
72
|
+
curr_data_size = 0
|
73
|
+
redo # Handle current line than would otherwise be skipped
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Send residual lines before handling next group
|
78
|
+
if curr_data_packet.any?
|
79
|
+
@board.send_command :rx_data_block, addr: curr_data_packet.first.addr, data: curr_data_packet.map { |line| line.data }.reduce(:+)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# TODO: Verify CRC or read entire flash and compare to hex lines?
|
84
|
+
|
85
|
+
logger.info 'Closing connection'
|
86
|
+
@board.close_connection
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Numeric
|
2
|
+
def to_hex_str
|
3
|
+
n = to_s(16).upcase
|
4
|
+
if n.length.odd?
|
5
|
+
n = "0#{n}"
|
6
|
+
end
|
7
|
+
n
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes_ary
|
11
|
+
res = []
|
12
|
+
to_hex_str.chars.each_slice(2) { |byte| res << byte.join().to_i(16) }
|
13
|
+
res
|
14
|
+
end
|
15
|
+
|
16
|
+
def millis
|
17
|
+
self / 1_000.0
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
class Command
|
5
|
+
|
6
|
+
attr_accessor :name, :code, :addr, :data, :configs
|
7
|
+
|
8
|
+
def self.supports?(cmd_name)
|
9
|
+
Configs::CMDS.keys.include? cmd_name.to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.[](cmd_name)
|
13
|
+
raise Exceptions::Command::NameNotSupported, cmd_name unless supports?(cmd_name)
|
14
|
+
|
15
|
+
Configs::CMDS[cmd_name.to_sym]
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(cmd_name, addr: nil, data: nil)
|
19
|
+
raise Exceptions::Command::NameNotSupported, cmd_name unless self.class.supports?(cmd_name)
|
20
|
+
|
21
|
+
@name = cmd_name
|
22
|
+
@configs = self.class[@name]
|
23
|
+
@code = configs[:code]
|
24
|
+
@addr = addr
|
25
|
+
@data = data
|
26
|
+
|
27
|
+
validate
|
28
|
+
end
|
29
|
+
|
30
|
+
def packet
|
31
|
+
return @packet if @packet
|
32
|
+
|
33
|
+
@packet = [code, splitted_addr, data].flatten.compact
|
34
|
+
end
|
35
|
+
|
36
|
+
def length
|
37
|
+
code.to_bytes_ary.length
|
38
|
+
end
|
39
|
+
|
40
|
+
# Split address to [low, middle, high] bytes
|
41
|
+
def splitted_addr
|
42
|
+
if addr
|
43
|
+
[ (addr & 0xFF), ((addr >> 8) & 0xFF), ((addr >> 16) & 0xFF) ]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate
|
50
|
+
# Check if command requires address and/or data
|
51
|
+
if configs[:requires_addr] && !addr
|
52
|
+
raise Exceptions::Command::RequiresAddr.new name
|
53
|
+
end
|
54
|
+
|
55
|
+
if configs[:requires_data] && !data
|
56
|
+
raise Exceptions::Command::RequiresData.new name
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
module Configs
|
5
|
+
CMD_KINDS = {
|
6
|
+
data: { code: 0x3A, payload_min_size: 2 },
|
7
|
+
message: { code: 0x3B, payload_size: 1 }
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
CMDS = {
|
11
|
+
rx_data_block: { code: 0x10, requires_addr: true, requires_data: true, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
12
|
+
rx_data_block_fast: { code: 0x1B, requires_addr: true, requires_data: true, response: { kind: nil, data_size: 1 }},
|
13
|
+
rx_password: { code: 0x11, requires_addr: false, requires_data: true, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
14
|
+
erase_segment: { code: 0x12, requires_addr: true, requires_data: false, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
15
|
+
lock_unlock_info: { code: 0x13, requires_addr: false , requires_data: false, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
16
|
+
reserved: { code: 0x14, requires_addr: false , requires_data: false, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
17
|
+
mass_erase: { code: 0x15, requires_addr: false , requires_data: false, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
18
|
+
crc_check: { code: 0x16, requires_addr: true , requires_data: true, response: { kind: CMD_KINDS[:data][:code], data_size: 2 }},
|
19
|
+
load_pc: { code: 0x17, requires_addr: true, requires_data: false, response: { kind: CMD_KINDS[:message][:code], data_size: 1 }},
|
20
|
+
tx_data_block: { code: 0x18, requires_addr: true, requires_data: true, response: { kind: CMD_KINDS[:data][:code], data_size_min: 1 }},
|
21
|
+
tx_bsl_version: { code: 0x19, requires_addr: false , requires_data: false, response: { kind: CMD_KINDS[:data][:code], data_size: 4 }},
|
22
|
+
tx_buffer_size: { code: 0x1A, requires_addr: false , requires_data: false, response: { kind: CMD_KINDS[:data][:code], data_size: 2 }},
|
23
|
+
change_baud_rate: { code: 0x52, requires_addr: false , requires_data: true, response: { kind: nil }}
|
24
|
+
}
|
25
|
+
|
26
|
+
RESPONSE_MESSAGES = {
|
27
|
+
success: { code: 0x00, reason: 'Operation Successful' },
|
28
|
+
flash_write_check_failed: { code: 0x01, reason: 'Flash Write Check Failed. After programming, a CRC is run on the programmed data. If the CRC does not match the expected result, this error is returned' },
|
29
|
+
flash_fail_bit_set: { code: 0x02, reason: "Flash Fail Bit Set. An operation set the FAIL bit in the flash controller (see the MSP430F5xx and MSP430F6xx Family User's Guide for more details on the flash fail bit)" },
|
30
|
+
voltage_changed: { code: 0x03, reason: "Voltage Change During Program. The VPE was set during the requested write operation (see the MSP430F5xx and MSP430F6xx Family User's Guide for more details on the VPE bit)" },
|
31
|
+
bsl_locked: { code: 0x04, reason: 'BSL Locked. The correct password has not yet been supplied to unlock the BSL' },
|
32
|
+
bsl_password_error: { code: 0x05, reason: 'BSL Password Error. An incorrect password was supplied to the BSL when attempting an unlock' },
|
33
|
+
byte_write_forbidden: { code: 0x06, reason: 'Byte Write Forbidden. This error is returned when a byte write is attempted in a flash area' },
|
34
|
+
unknown_command: { code: 0x07, reason: 'Unknown Command. The command given to the BSL was not recognized.' },
|
35
|
+
packet_too_large: { code: 0x08, reason: 'Packet Length Exceeds Buffer Size. The supplied packet length value is too large to be held in the BSL receive buffer' }
|
36
|
+
}
|
37
|
+
|
38
|
+
CMD_RX_PASSWORD = Array.new(32) { 0xFF }
|
39
|
+
|
40
|
+
BAUD_RATES = {
|
41
|
+
9600 => 0x02,
|
42
|
+
19200 => 0x03,
|
43
|
+
38400 => 0x04,
|
44
|
+
57600 => 0x05,
|
45
|
+
115200 => 0x06
|
46
|
+
}.freeze
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
module Exceptions
|
5
|
+
module Command
|
6
|
+
class NameNotSupported < StandardError
|
7
|
+
def initialize(given_name)
|
8
|
+
message = "command '#{given_name}' not recognized. Supported commands: #{Configs::CMDS.keys}"
|
9
|
+
super(message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class RequiresAddr < StandardError
|
14
|
+
def initialize(cmd_name)
|
15
|
+
msg = "command '#{cmd_name}' requires 'addr' param"
|
16
|
+
super(msg)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class RequiresData < StandardError
|
21
|
+
def initialize(cmd_name)
|
22
|
+
msg = "command '#{cmd_name}' requires 'data' param"
|
23
|
+
super(msg)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Response
|
29
|
+
class KindNotSupported < StandardError
|
30
|
+
def initialize(kind)
|
31
|
+
message = "Response kind '0x#{kind.to_hex_str}' not recognized. Supported response kinds: #{Configs::CMD_KINDS.keys}"
|
32
|
+
super(message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class NotValid < StandardError
|
37
|
+
def initialize(errors)
|
38
|
+
message = "Response not valid. Errors: \n\n#{errors.map { |err| " - #{err[1]}" }.join "\n" }\n"
|
39
|
+
super(message)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class WrongDataSize < StandardError
|
44
|
+
def initialize(data, size, min: false)
|
45
|
+
message = "payload with a size of '#{data.size}' doesn't satisfy the required #{min ? 'min' : ''}size of '#{size}'"
|
46
|
+
super(message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Msp430Bsl
|
2
|
+
class HexFile
|
3
|
+
|
4
|
+
attr_reader :path, :raw_data
|
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
|
17
|
+
end
|
18
|
+
|
19
|
+
def data_lines_grouped_by_contiguous_addr
|
20
|
+
return @grouped_lines if @grouped_lines
|
21
|
+
|
22
|
+
@grouped_lines = []
|
23
|
+
curr_group = nil
|
24
|
+
curr_addr = nil
|
25
|
+
prev_line = nil
|
26
|
+
lines.each do |line|
|
27
|
+
next unless line.is_of_type? :data
|
28
|
+
|
29
|
+
if curr_addr.nil?
|
30
|
+
# We just started a new group
|
31
|
+
curr_addr = line.addr
|
32
|
+
curr_group = [line]
|
33
|
+
elsif line.has_addr_contiguous_to? prev_line
|
34
|
+
# We already have a current group
|
35
|
+
curr_group << line
|
36
|
+
curr_addr = line.addr
|
37
|
+
else
|
38
|
+
@grouped_lines << curr_group
|
39
|
+
curr_addr = nil
|
40
|
+
redo
|
41
|
+
end
|
42
|
+
|
43
|
+
prev_line = line
|
44
|
+
end
|
45
|
+
|
46
|
+
@grouped_lines << curr_group if curr_group.any?
|
47
|
+
|
48
|
+
@grouped_lines
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
class HexLine
|
5
|
+
include Utils
|
6
|
+
|
7
|
+
attr_reader :raw_data, :data_length, :addr, :type, :data, :crc, :number
|
8
|
+
|
9
|
+
RECORD_TYPES = {
|
10
|
+
data: 0x00,
|
11
|
+
eof: 0x01,
|
12
|
+
ext_seg_addr: 0x02,
|
13
|
+
start_seg_addr: 0x03,
|
14
|
+
ext_lin_addr: 0x04,
|
15
|
+
start_lin_addr: 0x05
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def initialize(data, num: nil)
|
19
|
+
raise StandardError, 'raw_data must be a String' unless data.is_a?(String)
|
20
|
+
|
21
|
+
# 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
|
+
|
24
|
+
@data_length = raw_data[0]
|
25
|
+
@addr = (raw_data[1] << 8) | raw_data[2]
|
26
|
+
@type = raw_data[3]
|
27
|
+
@data = raw_data.slice 4, data_length
|
28
|
+
@crc = raw_data[-1]
|
29
|
+
@number = num
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks if this line's address is contiguous with the one of the given line
|
33
|
+
# Obviously this can be true only if the given line has an address that precedes this line's one
|
34
|
+
def has_addr_contiguous_to?(another_line)
|
35
|
+
another_line.addr + another_line.data_length == addr
|
36
|
+
end
|
37
|
+
|
38
|
+
def crc_ok?
|
39
|
+
crc == crc8(raw_data[0..-2])
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_of_type?(ty)
|
43
|
+
ty = ty.to_sym
|
44
|
+
type == RECORD_TYPES[ty]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
class Response
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def supports_kind?(kind)
|
8
|
+
Configs::CMD_KINDS.values.map { |val| val[:code] }.include? kind
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :kind, :data, :errors
|
13
|
+
|
14
|
+
def initialize(payload)
|
15
|
+
raise ArgumentError, 'payload must be an Array' unless payload.is_a?(Array)
|
16
|
+
|
17
|
+
@kind = payload[0]
|
18
|
+
raise Exceptions::Response::KindNotSupported, kind unless self.class.supports_kind?(kind)
|
19
|
+
|
20
|
+
@data = payload[1..-1]
|
21
|
+
|
22
|
+
if is_data?
|
23
|
+
raise Exceptions::Response::WrongDataSize.new(data, Configs::CMD_KINDS[:data][:payload_min_size]) if data.size < Configs::CMD_KINDS[:data][:payload_min_size]
|
24
|
+
else
|
25
|
+
raise Exceptions::Response::WrongDataSize.new(data, Configs::CMD_KINDS[:message][:payload_size]) if data.size != Configs::CMD_KINDS[:message][:payload_size]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def is_data?
|
30
|
+
kind == Configs::CMD_KINDS[:data]
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_message?
|
34
|
+
kind == Configs::CMD_KINDS[:message][:code]
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_ok_given_command?(command)
|
38
|
+
@errors = []
|
39
|
+
|
40
|
+
# Verify if response kind is compatible with sent command
|
41
|
+
unless kind == command.configs[:response][:kind]
|
42
|
+
@errors << [:kind, "Kind NOK. Expected response kind: 0x#{command.configs[:response][:kind].to_hex_str} - got: 0x#{kind.to_hex_str}"]
|
43
|
+
end
|
44
|
+
# Check response exact data size
|
45
|
+
if command.configs.has_key?(:data_size) && data.size != command.configs[:data_size]
|
46
|
+
@errors << [:data_size, "Data size NOK. Expected data size to be exactly '#{command.configs[:data_size]}' bytes, got '#{data.size}' bytes"]
|
47
|
+
end
|
48
|
+
# Check response min data size
|
49
|
+
if command.configs.has_key?(:data_size_min) && data.size < command.configs[:data_size_min]
|
50
|
+
@errors << [:data_size_min, "Min data size NOK. Expected data to have at least a size of '#{command.configs[:min_data_size]}' bytes, got '#{data.size}' bytes"]
|
51
|
+
end
|
52
|
+
# If kind is "message" check response code
|
53
|
+
if is_message?
|
54
|
+
success_code = Configs::RESPONSE_MESSAGES[:success][:code]
|
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]}'"]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
@errors.empty?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
module Uart
|
5
|
+
class Ack
|
6
|
+
|
7
|
+
MESSAGES = {
|
8
|
+
0x00 => { code: :ack, reason: 'ACK - Command correctly received' },
|
9
|
+
0x51 => { code: :header_nok, reason: 'Header incorrect. The packet did not begin with the required 0x80 value' },
|
10
|
+
0x52 => { code: :crc_nok, reason: 'Checksum incorrect. The packet did not have the correct checksum value' },
|
11
|
+
0x53 => { code: :packet_size_zero, reason: 'Packet size zero. The size for the BSL core command was given as 0' },
|
12
|
+
0x54 => { code: :packet_size_exceeds, reason: 'Packet size exceeds buffer. The packet size given is too big for the RX buffer' },
|
13
|
+
0x55 => { code: :unkown_error, reason: 'Unknown error' },
|
14
|
+
0x56 => { code: :unkown_baudrate, reason: 'Unknown baud rate. The supplied data for baud rate change is not a known value' }
|
15
|
+
}
|
16
|
+
|
17
|
+
attr_accessor :value, :message
|
18
|
+
|
19
|
+
def initialize(value)
|
20
|
+
raise Exceptions::Ack::MessageNotSupported, value unless MESSAGES.include?(value)
|
21
|
+
|
22
|
+
@value = value
|
23
|
+
@message = MESSAGES[@value]
|
24
|
+
end
|
25
|
+
|
26
|
+
def ok?
|
27
|
+
value == 0x00
|
28
|
+
end
|
29
|
+
|
30
|
+
def reason
|
31
|
+
message[:reason]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'logger'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
module Msp430Bsl
|
6
|
+
module Uart
|
7
|
+
class Connection
|
8
|
+
|
9
|
+
UART_CONFIGS = { data_bits: 8, stop_bits: 1, parity: SerialPort::EVEN }.transform_keys(&:to_s).freeze
|
10
|
+
|
11
|
+
WAIT_FOR_ACK_MAX = 100.millis
|
12
|
+
WAIT_FOR_RESPONSE_MAX = 100.millis
|
13
|
+
|
14
|
+
MEM_START_MAIN_FLASH = 0x8000
|
15
|
+
|
16
|
+
CORE_COMMANDS_BUFFER_SIZE = 260
|
17
|
+
|
18
|
+
attr_reader :serial_port, :device_path, :logger, :cmd_buff_size
|
19
|
+
|
20
|
+
def initialize(device_path, opts = {})
|
21
|
+
@device_path = device_path
|
22
|
+
@logger = opts.fetch :logger, Logger.new(STDOUT)
|
23
|
+
@cmd_buff_size = opts.fetch :cmd_buf_size, CORE_COMMANDS_BUFFER_SIZE
|
24
|
+
|
25
|
+
@serial_port = SerialPort.new @device_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def close_connection
|
29
|
+
serial_port.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_bsl_reply
|
33
|
+
reply.length > 1 && reply[0] == BSL_MESSAGE && reply[1] == BSL_OK
|
34
|
+
end
|
35
|
+
|
36
|
+
def enter_bsl
|
37
|
+
logger.info "Connecting to target board through UART on #{device_path}"
|
38
|
+
set_uart_speed 9600
|
39
|
+
invoke_bsl
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_response_for(command)
|
43
|
+
raise ArgumentError, "an instance of Msp430Bsl::Command is expected as argument. Given: '#{command.class}'" unless command.is_a?(Command)
|
44
|
+
|
45
|
+
# Wait for first response byte - UART's ACK/NACK
|
46
|
+
ack = nil
|
47
|
+
begin
|
48
|
+
Timeout::timeout(WAIT_FOR_ACK_MAX) do
|
49
|
+
ack = Ack.new serial_port.getbyte
|
50
|
+
end
|
51
|
+
rescue Timeout::Error => e
|
52
|
+
logger.error 'Timeout occurred while waiting for UART ACK'
|
53
|
+
raise e
|
54
|
+
end
|
55
|
+
|
56
|
+
# If we arrived here, ack has been populated
|
57
|
+
if ack && ack.ok?
|
58
|
+
logger.debug "IN <- ACK (1 byte) 0x#{ack.value.to_hex_str}"
|
59
|
+
else
|
60
|
+
logger.error ack.reason
|
61
|
+
raise Exceptions::Ack::NOK, ack.value
|
62
|
+
end
|
63
|
+
|
64
|
+
# If this command has not response, return
|
65
|
+
unless command.configs[:response][:kind]
|
66
|
+
return ack
|
67
|
+
end
|
68
|
+
|
69
|
+
# Wait for command response
|
70
|
+
begin
|
71
|
+
pi = PeripheralInterface.new
|
72
|
+
Timeout::timeout(WAIT_FOR_RESPONSE_MAX) do
|
73
|
+
loop do
|
74
|
+
read = serial_port.readpartial cmd_buff_size
|
75
|
+
pi.push read.unpack 'C*'
|
76
|
+
break if pi.valid?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue Timeout::Error => e
|
80
|
+
logger.error 'Timeout occurred while fetching response from UART'
|
81
|
+
raise e
|
82
|
+
end
|
83
|
+
|
84
|
+
# Unwrap PeripheralInterface and create Response
|
85
|
+
logger.debug "IN <- RES (#{pi.packet.size} bytes) #{pi.to_hex_ary_str}"
|
86
|
+
response = pi.to_response
|
87
|
+
unless response.is_ok_given_command? command
|
88
|
+
raise Msp430Bsl::Exceptions::Response::NotValid, response.errors
|
89
|
+
end
|
90
|
+
|
91
|
+
response
|
92
|
+
end
|
93
|
+
|
94
|
+
def send_command(cmd_name, addr: nil, data: nil, log_only: false)
|
95
|
+
command = Command.new cmd_name, addr: addr, data: data
|
96
|
+
pi = PeripheralInterface.wrap command
|
97
|
+
logger.debug "Sending command '#{command.name}' over UART"
|
98
|
+
# Flush serial's output and input before sending a new command
|
99
|
+
serial_port.flush_output
|
100
|
+
serial_port.flush_input
|
101
|
+
|
102
|
+
unless pi.valid?
|
103
|
+
logger.error "PeripheralInterface not valid. Errors: #{pi.errors}"
|
104
|
+
return nil
|
105
|
+
end
|
106
|
+
|
107
|
+
logger.debug "OUT -> (#{pi.packet.size} bytes) #{pi.to_hex_ary_str}"
|
108
|
+
unless log_only
|
109
|
+
serial_port.write pi.to_uart
|
110
|
+
read_response_for command
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def set_uart_speed(baud)
|
115
|
+
raise StandardError, "BAUD not supported. Supported BAUD: #{Configs::BAUD_RATES.keys}" unless Configs::BAUD_RATES.keys.include?(baud)
|
116
|
+
|
117
|
+
logger.debug "Setting serial port BAUD to #{baud} bps"
|
118
|
+
|
119
|
+
serial_port.set_modem_params UART_CONFIGS.merge('baud' => baud) # We must use strings as keys
|
120
|
+
test_pin_go :high
|
121
|
+
reset_pin_go :low
|
122
|
+
end
|
123
|
+
|
124
|
+
def trigger_reset
|
125
|
+
# slau319 pag. 5 - Fig. 1-1
|
126
|
+
reset_pin_go :low
|
127
|
+
test_pin_go :low
|
128
|
+
sleep 5.millis
|
129
|
+
reset_pin_go :high
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def convert_pin(value, negate: false)
|
135
|
+
res = case value
|
136
|
+
when Symbol
|
137
|
+
value == :high ? 1 : 0
|
138
|
+
when Numeric
|
139
|
+
value == 1 ? 1 : 0
|
140
|
+
when TrueClass
|
141
|
+
1
|
142
|
+
when FalseClass
|
143
|
+
0
|
144
|
+
else
|
145
|
+
raise ArgumentError, 'convert_pin: value not supported'
|
146
|
+
end
|
147
|
+
|
148
|
+
if negate
|
149
|
+
res = res == 1 ? 0 : 1
|
150
|
+
end
|
151
|
+
|
152
|
+
res
|
153
|
+
end
|
154
|
+
|
155
|
+
def invoke_bsl
|
156
|
+
serial_port.flush_input
|
157
|
+
serial_port.flush_output
|
158
|
+
|
159
|
+
logger.info 'Entering BSL...'
|
160
|
+
|
161
|
+
test_pin_go(:low)
|
162
|
+
reset_pin_go(:low)
|
163
|
+
sleep 5.millis
|
164
|
+
2.times do
|
165
|
+
test_pin_go(:high)
|
166
|
+
sleep 1.millis
|
167
|
+
test_pin_go(:low)
|
168
|
+
sleep 1.millis
|
169
|
+
end
|
170
|
+
|
171
|
+
test_pin_go(:high)
|
172
|
+
sleep 1.millis
|
173
|
+
reset_pin_go(:high)
|
174
|
+
sleep 1.millis
|
175
|
+
test_pin_go :low
|
176
|
+
sleep 50.millis # Give microcontroller time to enter BSL
|
177
|
+
|
178
|
+
logger.info 'OK, BSL ready'
|
179
|
+
end
|
180
|
+
|
181
|
+
def negate_pin(value)
|
182
|
+
raise ArgumentError, "value must be Numeric (0,1)" unless value.is_a?(Numeric)
|
183
|
+
|
184
|
+
value == 1 ? 0 : 1
|
185
|
+
end
|
186
|
+
|
187
|
+
def reset_pin_go(value)
|
188
|
+
serial_port.dtr = convert_pin value, negate: true
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_pin_go(value)
|
192
|
+
serial_port.rts = convert_pin value, negate: true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
module Uart
|
5
|
+
module Exceptions
|
6
|
+
module Ack
|
7
|
+
|
8
|
+
class NOK < StandardError
|
9
|
+
def initialize(val)
|
10
|
+
message = "Command ACK not OK. Received value: #{val}"
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class MessageNotSupported < StandardError
|
15
|
+
def initialize(value)
|
16
|
+
message = "message with value 0x#{value.to_hex_str} not supported"
|
17
|
+
super(message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module PeripheralInterface
|
23
|
+
class InterfaceWrapNotACommand < StandardError
|
24
|
+
def initialize(arg)
|
25
|
+
message = "Given argument '#{arg}' must be a Msp430Bsl::Command"
|
26
|
+
super(message)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class InterfaceParseRawDataNotArray < StandardError
|
31
|
+
def initialize
|
32
|
+
message = "PeripheralInterface#parse argument must be an Array"
|
33
|
+
super(message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class InterfaceDataNotArray < StandardError
|
38
|
+
def initialize
|
39
|
+
message = "Peripheral Interface 'data' argument must be an Array"
|
40
|
+
super(message)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class InterfaceSize < StandardError
|
45
|
+
def initialize(received_size)
|
46
|
+
message = "Peripheral Interface size error. Required packet's min size is '#{PeripheralInterface::MIN_PACKET_SIZE}' bytes, given raw_data size is '#{received_size}' bytes"
|
47
|
+
super(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class InterfaceHeaderNOK < StandardError
|
52
|
+
def initialize(received_header)
|
53
|
+
message = "Peripheral interface header NOK. Received '0x#{received_header.to_hex_str}' instead of 0x#{PeripheralInterface::OK_HEADER.to_hex_str}"
|
54
|
+
super(message)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class InterfaceCRCMismatch < StandardError
|
60
|
+
def initialize
|
61
|
+
message = 'Peripheral Interface CRC mismatch'
|
62
|
+
super(message)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Msp430Bsl
|
4
|
+
module Uart
|
5
|
+
class PeripheralInterface
|
6
|
+
include Utils
|
7
|
+
|
8
|
+
MIN_PACKET_SIZE = 6.freeze # bytes
|
9
|
+
OK_HEADER = 0x80.freeze
|
10
|
+
|
11
|
+
HEADER_SIZE = 1.freeze
|
12
|
+
DATA_LEN_SIZE = 2.freeze
|
13
|
+
CRC_SIZE = 2.freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
include Utils
|
17
|
+
|
18
|
+
def wrap(command)
|
19
|
+
unless command.is_a?(Command)
|
20
|
+
raise Exceptions::PeripheralInterfaceWrapNotACommand, command
|
21
|
+
end
|
22
|
+
|
23
|
+
new header: OK_HEADER, data_len: command.packet.size, data: command.packet
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(raw_data)
|
27
|
+
raise Exceptions::PeripheralInterfaceParseRawDataNotArray unless raw_data.is_a?(Array)
|
28
|
+
raise Exceptions::PeripheralInterfaceSize, raw_data.size unless raw_data.size >= MIN_PACKET_SIZE
|
29
|
+
|
30
|
+
header = raw_data[0]
|
31
|
+
data_len = raw_data[2] << 8 | raw_data[1]
|
32
|
+
data = raw_data[3, data_len]
|
33
|
+
crc = raw_data[-1] << 8 | raw_data[-2]
|
34
|
+
|
35
|
+
new header: header, data_len: data_len, data: data, crc: crc
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :header, :data_len, :data, :crc, :errors, :packet, :cmd_kind
|
40
|
+
|
41
|
+
def initialize(header: nil, data_len: nil, data: nil, crc: nil)
|
42
|
+
raise Exceptions::PeripheralInterfaceDataNotArray if (data && !data.is_a?(Array))
|
43
|
+
|
44
|
+
@header = header
|
45
|
+
@data_len = data_len
|
46
|
+
@data = data
|
47
|
+
@crc = crc ? crc : (data ? crc16(data) : nil)
|
48
|
+
@cmd_code
|
49
|
+
|
50
|
+
@partial_data = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def crc_ok?
|
54
|
+
data && crc == crc16(data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def header_ok?
|
58
|
+
header == OK_HEADER
|
59
|
+
end
|
60
|
+
|
61
|
+
def data_len_ok?
|
62
|
+
data&.length == data_len
|
63
|
+
end
|
64
|
+
|
65
|
+
def length
|
66
|
+
packet.length
|
67
|
+
end
|
68
|
+
|
69
|
+
def packet
|
70
|
+
res = data.clone
|
71
|
+
cmd_len = res.length
|
72
|
+
# Calculate CRC (it must be calculated only on command data)
|
73
|
+
crc = crc16 res
|
74
|
+
# Prepend preamble
|
75
|
+
res.prepend 0x80, (cmd_len & 0xFF), ((cmd_len >> 8) & 0xFF)
|
76
|
+
# Append CRC16
|
77
|
+
res.append (crc & 0xFF), ((crc >> 8) & 0xFF)
|
78
|
+
end
|
79
|
+
|
80
|
+
def push(val)
|
81
|
+
@partial_data.append *val
|
82
|
+
|
83
|
+
# If :header has not already been fetched
|
84
|
+
if !header && @partial_data.size >= HEADER_SIZE
|
85
|
+
@header = @partial_data.shift
|
86
|
+
end
|
87
|
+
# If :data_len has not already been fetched, and we have enough data
|
88
|
+
if header && !data_len && @partial_data.size >= DATA_LEN_SIZE
|
89
|
+
values = @partial_data.shift DATA_LEN_SIZE
|
90
|
+
@data_len = values[0] | (values[1] << 8)
|
91
|
+
end
|
92
|
+
|
93
|
+
# If :data has not already been fetched, fetch it
|
94
|
+
if data_len && (data.nil? || data.empty?) && @partial_data.size >= data_len
|
95
|
+
@data = @partial_data.shift data_len
|
96
|
+
end
|
97
|
+
|
98
|
+
if data && !crc && @partial_data.size >= CRC_SIZE
|
99
|
+
values = @partial_data.shift CRC_SIZE
|
100
|
+
@crc = values[0] | (values[1] << 8)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias_method :<<, :push
|
104
|
+
|
105
|
+
def to_hex_ary_str
|
106
|
+
packet.to_hex
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_uart
|
110
|
+
packet.to_chr_string
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_response
|
114
|
+
Response.new data
|
115
|
+
end
|
116
|
+
|
117
|
+
def valid?
|
118
|
+
@errors = []
|
119
|
+
@errors << [:header, 'Header NOK'] unless header_ok?
|
120
|
+
@errors << [:data_len, "'data_len' value (#{data_len}) differs from current data length (#{data&.length})"] unless data_len_ok?
|
121
|
+
@errors << [:crc, 'CRC NOK'] unless crc_ok?
|
122
|
+
|
123
|
+
@errors.empty?
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def parse_raw_data
|
129
|
+
@header = raw_data[0]
|
130
|
+
@data_len = raw_data[2] << 8 | raw_data[1]
|
131
|
+
@data = raw_data[3, data_len]
|
132
|
+
@crc = raw_data[-1] << 8 | raw_data[-2]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module Msp430Bsl
|
5
|
+
module Utils
|
6
|
+
def crc16(data)
|
7
|
+
raise ArgumentError, 'data must be an Array' unless data.is_a?(Array)
|
8
|
+
|
9
|
+
crc = 0xFFFF
|
10
|
+
|
11
|
+
data.each do |byte|
|
12
|
+
x = (crc >> 8 ^ byte) & 0xFF
|
13
|
+
x ^= x >> 4
|
14
|
+
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x
|
15
|
+
end
|
16
|
+
|
17
|
+
crc & 0xFFFF
|
18
|
+
end
|
19
|
+
|
20
|
+
def crc8(data)
|
21
|
+
(~data.reduce(:+) + 1) & 0xFF
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_logger_from(opts)
|
25
|
+
logto = if opts[:logfile]
|
26
|
+
File.expand_path opts[:logfile]
|
27
|
+
else
|
28
|
+
STDOUT
|
29
|
+
end
|
30
|
+
|
31
|
+
Logger.new logto, level: normalize_log_level(opts[:loglevel])
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalize_log_level(level)
|
35
|
+
case level
|
36
|
+
when :debug, ::Logger::DEBUG, 'debug', 'd' then ::Logger::DEBUG
|
37
|
+
when :info, ::Logger::INFO, 'info', 'i' then ::Logger::INFO
|
38
|
+
when :warn, ::Logger::WARN, 'warn', 'w' then ::Logger::WARN
|
39
|
+
when :error, ::Logger::ERROR, 'error', 'e' then ::Logger::ERROR
|
40
|
+
when :fatal, ::Logger::FATAL, 'fatal', 'f' then ::Logger::FATAL
|
41
|
+
else
|
42
|
+
ENV['LOG_LEVEL'] || Logger::DEBUG
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/msp430_bsl.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'zeitwerk'
|
2
|
+
require 'serialport'
|
3
|
+
|
4
|
+
loader = Zeitwerk::Loader.new
|
5
|
+
loader.push_dir File.expand_path(__dir__)
|
6
|
+
core_ext = File.expand_path('core_ext', __dir__)
|
7
|
+
loader.ignore core_ext
|
8
|
+
loader.setup
|
9
|
+
|
10
|
+
# Require core_ext files
|
11
|
+
Dir["#{core_ext}/**/*.rb"].each { |file| require file }
|
12
|
+
|
13
|
+
module Msp430Bsl
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: msp430_bsl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alessandro Verlato
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-06-27 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.8
|
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.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: serialport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: slop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.10.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.10.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.14.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.14.2
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- averlato@gmail.com
|
72
|
+
executables:
|
73
|
+
- upload_hex
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- MIT-LICENSE
|
78
|
+
- README.md
|
79
|
+
- bin/upload_hex
|
80
|
+
- lib/core_ext/array.rb
|
81
|
+
- lib/core_ext/number.rb
|
82
|
+
- lib/core_ext/string.rb
|
83
|
+
- lib/msp430_bsl.rb
|
84
|
+
- lib/msp430_bsl/command.rb
|
85
|
+
- lib/msp430_bsl/configs.rb
|
86
|
+
- lib/msp430_bsl/exceptions.rb
|
87
|
+
- lib/msp430_bsl/hex_file.rb
|
88
|
+
- lib/msp430_bsl/hex_line.rb
|
89
|
+
- lib/msp430_bsl/response.rb
|
90
|
+
- lib/msp430_bsl/uart/ack.rb
|
91
|
+
- lib/msp430_bsl/uart/connection.rb
|
92
|
+
- lib/msp430_bsl/uart/exceptions.rb
|
93
|
+
- lib/msp430_bsl/uart/peripheral_interface.rb
|
94
|
+
- lib/msp430_bsl/utils.rb
|
95
|
+
- lib/msp430_bsl/version.rb
|
96
|
+
homepage: https://github.com/madAle/msp430_bsl
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 2.7.0
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubygems_version: 3.4.6
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Texas Instrument MSP430 BSL Ruby library
|
119
|
+
test_files: []
|