msp430_bsl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|