gdbflasher 1.0.0
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/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/gdbflasher +76 -0
- data/gdbflasher.gemspec +19 -0
- data/helper_sources/Makefile +22 -0
- data/helper_sources/stm32f10xx_hd.S +115 -0
- data/helper_sources/stm32f10xx_hd.lds +25 -0
- data/helper_sources/stm32f10xx_md.S +115 -0
- data/helper_sources/stm32f10xx_md.lds +25 -0
- data/helper_sources/stm32f4xx.S +109 -0
- data/helper_sources/stm32f4xx.lds +25 -0
- data/helper_sources/stm32l1xx.S +101 -0
- data/helper_sources/stm32l1xx.lds +25 -0
- data/helpers/stm32f10xx_hd.hex +12 -0
- data/helpers/stm32f10xx_hd.sym +7 -0
- data/helpers/stm32f10xx_md.hex +12 -0
- data/helpers/stm32f10xx_md.sym +7 -0
- data/helpers/stm32f4xx.hex +13 -0
- data/helpers/stm32f4xx.sym +7 -0
- data/helpers/stm32l1xx.hex +12 -0
- data/helpers/stm32l1xx.sym +7 -0
- data/lib/gdbflasher/cortexm.rb +19 -0
- data/lib/gdbflasher/ihex.rb +189 -0
- data/lib/gdbflasher/mcu/stm32f10xx_hd.rb +17 -0
- data/lib/gdbflasher/mcu/stm32f10xx_md.rb +17 -0
- data/lib/gdbflasher/mcu/stm32f4xx.rb +25 -0
- data/lib/gdbflasher/mcu/stm32l1xx.rb +21 -0
- data/lib/gdbflasher/mcu.rb +208 -0
- data/lib/gdbflasher/server_connection.rb +334 -0
- data/lib/gdbflasher/version.rb +3 -0
- data/lib/gdbflasher.rb +21 -0
- metadata +93 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
module GdbFlasher
|
2
|
+
|
3
|
+
class MCU
|
4
|
+
def initialize(connection)
|
5
|
+
@connection = connection
|
6
|
+
@symbol_table = {}
|
7
|
+
|
8
|
+
helper_hex = File.join HELPERS, helper_name + ".hex"
|
9
|
+
helper_sym = File.join HELPERS, helper_name + ".sym"
|
10
|
+
|
11
|
+
File.open(helper_sym, "r") do |f|
|
12
|
+
f.each_line do |line|
|
13
|
+
line.rstrip!
|
14
|
+
|
15
|
+
address, symbol = line.split(" ")
|
16
|
+
|
17
|
+
@symbol_table[symbol.intern] = address.to_i 16
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
helper = nil
|
22
|
+
File.open(helper_hex, "r") { |f| helper = IHex.load f }
|
23
|
+
|
24
|
+
connection.reset
|
25
|
+
connection.get_stop_reply
|
26
|
+
|
27
|
+
helper.segments.each do |segment|
|
28
|
+
connection.write_memory segment.base, segment.data
|
29
|
+
end
|
30
|
+
|
31
|
+
initialize_environment
|
32
|
+
|
33
|
+
@connection.insert_breakpoint 0, @symbol_table[:trap], breakpoint_kind
|
34
|
+
|
35
|
+
call_helper :initialize
|
36
|
+
end
|
37
|
+
|
38
|
+
def finalize
|
39
|
+
call_helper :finalize
|
40
|
+
|
41
|
+
@connection.remove_breakpoint 0, @symbol_table[:trap], breakpoint_kind
|
42
|
+
end
|
43
|
+
|
44
|
+
def program_ihex(ihex, extra = {})
|
45
|
+
sectors = []
|
46
|
+
sector_actions = []
|
47
|
+
|
48
|
+
sector_map = self.class.const_get :SECTORS
|
49
|
+
|
50
|
+
sector_map.each_index do |i|
|
51
|
+
sector_begin, sector_end = sector_map[i]
|
52
|
+
|
53
|
+
sector_segment = nil
|
54
|
+
|
55
|
+
ihex.segments.each do |segment|
|
56
|
+
intersection = segment.intersect sector_begin, sector_end
|
57
|
+
|
58
|
+
if intersection.size > 0
|
59
|
+
if sector_segment.nil?
|
60
|
+
sector_segment = IHex::Segment.new
|
61
|
+
sector_segment.base = sector_begin
|
62
|
+
sector_segment.data = blank_byte.chr * (sector_end - sector_begin + 1)
|
63
|
+
|
64
|
+
sectors << sector_segment
|
65
|
+
end
|
66
|
+
|
67
|
+
affected_range = intersection.base - sector_begin...intersection.base + intersection.size - sector_begin
|
68
|
+
sector_segment.data[affected_range] = intersection.data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if extra[:read_disallowed]
|
74
|
+
sector_actions = [ [ :erase, :program ] ] * sectors.count
|
75
|
+
else
|
76
|
+
puts "Checking sectors"
|
77
|
+
|
78
|
+
sectors.each do |sector|
|
79
|
+
data = @connection.read_memory sector.base, sector.size
|
80
|
+
|
81
|
+
if data == sector.data
|
82
|
+
sector_actions << [ ]
|
83
|
+
elsif is_blank(data)
|
84
|
+
sector_actions << [ :program, :verify ]
|
85
|
+
elsif is_blank(sector.data)
|
86
|
+
sector_actions << [ :erase, :verify ]
|
87
|
+
else
|
88
|
+
sector_actions << [ :erase, :program, :verify ]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
puts "Programming sectors:"
|
94
|
+
sectors.each_index do |i|
|
95
|
+
sector = sectors[i]
|
96
|
+
actions = sector_actions[i]
|
97
|
+
|
98
|
+
next if actions.empty?
|
99
|
+
|
100
|
+
sector_id = sector_map.index { |i| i[0] == sector.base }
|
101
|
+
|
102
|
+
printf " - %08X - %08X: ", sector.base, sector.base + sector.size - 1
|
103
|
+
|
104
|
+
actions.each do |action|
|
105
|
+
case action
|
106
|
+
when :erase
|
107
|
+
print "erase, "
|
108
|
+
|
109
|
+
status = erase sector_id
|
110
|
+
if status != 0
|
111
|
+
puts "failure!"
|
112
|
+
warn "Unable to erase sector #{sector_id}, vendor-specific error #{status}"
|
113
|
+
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
|
117
|
+
when :program
|
118
|
+
print "program, "
|
119
|
+
|
120
|
+
offset = 0
|
121
|
+
page_size = @symbol_table[:PAGE_SIZE]
|
122
|
+
buffer = @symbol_table[:page_buffer]
|
123
|
+
|
124
|
+
while offset < sector.size
|
125
|
+
@connection.write_memory buffer, sector.data[offset...offset + page_size]
|
126
|
+
status = program sector.base + offset
|
127
|
+
|
128
|
+
if status != 0
|
129
|
+
puts "failure!"
|
130
|
+
warn "Unable to program page #{(sector.base + offset).to_s 16}, vendor-specific error #{status}"
|
131
|
+
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
|
135
|
+
offset += page_size
|
136
|
+
end
|
137
|
+
|
138
|
+
when :verify
|
139
|
+
print "verify, "
|
140
|
+
|
141
|
+
data = @connection.read_memory sector.base, sector.size
|
142
|
+
|
143
|
+
if data != sector.data
|
144
|
+
puts "failure!"
|
145
|
+
warn "Verification of sector #{sector_id} failed."
|
146
|
+
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
print "all ok.\n"
|
153
|
+
end
|
154
|
+
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
def blank_byte
|
161
|
+
0xFF
|
162
|
+
end
|
163
|
+
|
164
|
+
def erase(sector_id)
|
165
|
+
call_helper :erase, sector_id
|
166
|
+
end
|
167
|
+
|
168
|
+
def program(offset)
|
169
|
+
call_helper :program, offset
|
170
|
+
end
|
171
|
+
|
172
|
+
def is_blank(string)
|
173
|
+
string.bytes.all? { |byte| byte == blank_byte }
|
174
|
+
end
|
175
|
+
|
176
|
+
def initialize_environment
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
def breakpoint_kind
|
181
|
+
4 # ARM breakpoint
|
182
|
+
end
|
183
|
+
|
184
|
+
def lr_offset
|
185
|
+
0
|
186
|
+
end
|
187
|
+
|
188
|
+
def call_helper(func, r0 = 0, r1 = 0, r2 = 0, r3 = 0)
|
189
|
+
regs = @connection.read_registers
|
190
|
+
regs[0..3] = r0, r1, r2, r3
|
191
|
+
regs[14] = @symbol_table[:trap] | lr_offset
|
192
|
+
regs[15] = @symbol_table[func]
|
193
|
+
@connection.write_registers regs
|
194
|
+
|
195
|
+
reply = @connection.continue
|
196
|
+
|
197
|
+
regs = @connection.read_registers
|
198
|
+
|
199
|
+
if reply.signal != 0x05 || regs[15] != @symbol_table[:trap]
|
200
|
+
raise "Target stopped by signal #{reply.signal}, PC = #{regs[15].to_s 16}"
|
201
|
+
end
|
202
|
+
|
203
|
+
regs[0]
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
@@ -0,0 +1,334 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module GdbFlasher
|
4
|
+
class ServerConnection
|
5
|
+
class StopReply
|
6
|
+
attr_accessor :signal, :attributes
|
7
|
+
|
8
|
+
def initialize(signal, attributes = {})
|
9
|
+
@signal = signal
|
10
|
+
@attributes = attributes
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@socket = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect(address)
|
19
|
+
raise "Already connected" unless @socket.nil?
|
20
|
+
|
21
|
+
delimiter = address.rindex ':'
|
22
|
+
raise ArgumentError, "Port must be specified" if delimiter.nil?
|
23
|
+
host = address[0...delimiter]
|
24
|
+
port = address[delimiter + 1..-1].to_i
|
25
|
+
|
26
|
+
@buf = ""
|
27
|
+
@features = {}
|
28
|
+
@need_ack = true
|
29
|
+
|
30
|
+
begin
|
31
|
+
@socket = TCPSocket.new host, port
|
32
|
+
@socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
33
|
+
|
34
|
+
# Query stub features
|
35
|
+
command("qSupported").split(';').each do |feature|
|
36
|
+
if feature[-1] == '-'
|
37
|
+
@features.delete feature[0...-1].intern
|
38
|
+
elsif feature[-1] == '+'
|
39
|
+
@features[feature[0...-1].intern] = true
|
40
|
+
else
|
41
|
+
sep = feature.index '='
|
42
|
+
|
43
|
+
if sep.nil?
|
44
|
+
raise "Unexpected item in qSupported response: #{sep}"
|
45
|
+
end
|
46
|
+
|
47
|
+
@features[feature[0...sep].intern] = feature[sep + 1..-1]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if @features[:PacketSize].nil?
|
52
|
+
raise "PacketSize isn't present in qSupported response"
|
53
|
+
end
|
54
|
+
|
55
|
+
if @features[:QStartNoAckMode]
|
56
|
+
response = command("QStartNoAckMode")
|
57
|
+
|
58
|
+
if response != "OK"
|
59
|
+
raise "Unable to enter NoAck mode: #{response}"
|
60
|
+
end
|
61
|
+
|
62
|
+
@need_ack = false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Load target description
|
66
|
+
if @features[:"qXfer:features:read"]
|
67
|
+
description = read_xfer "features", "target.xml"
|
68
|
+
|
69
|
+
# TODO: parse target description and use register map from it.
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue Exception => e
|
73
|
+
@socket.close unless @socket.nil?
|
74
|
+
@socket = nil
|
75
|
+
|
76
|
+
raise e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def close
|
81
|
+
@socket.close
|
82
|
+
@socket = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def read_registers
|
86
|
+
response = command "g"
|
87
|
+
|
88
|
+
if (response[0] != 'E' || response.length != 3) && response.length % 8 != 0
|
89
|
+
raise "Malformed 'g' response"
|
90
|
+
end
|
91
|
+
|
92
|
+
if response[0] == 'E'
|
93
|
+
raise "GDB server error: #{response[1..2].to_i 16}"
|
94
|
+
end
|
95
|
+
|
96
|
+
Array.new response.length / 8 do |i|
|
97
|
+
big2native response[i * 8...(i + 1) * 8].to_i(16)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def write_registers(regs)
|
102
|
+
send_packet "G" + regs.map { |r| sprintf "%08x", native2big(r) }.join
|
103
|
+
end
|
104
|
+
|
105
|
+
def write_memory(base, string)
|
106
|
+
max_size = (@features[:PacketSize].to_i - 19) & ~1
|
107
|
+
|
108
|
+
offset = 0
|
109
|
+
data = string.unpack("C*").map { |byte| sprintf "%02X", byte }.join
|
110
|
+
|
111
|
+
while offset < data.length
|
112
|
+
chunk_size = [ max_size, data.length - offset ].min
|
113
|
+
|
114
|
+
response = command "M#{base.to_s 16},#{(chunk_size / 2).to_s 16}:#{data[offset...offset + chunk_size]}"
|
115
|
+
|
116
|
+
if response != "OK"
|
117
|
+
raise "Memory write failed: #{response}"
|
118
|
+
end
|
119
|
+
|
120
|
+
base += chunk_size / 2
|
121
|
+
offset += chunk_size
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def read_memory(base, size)
|
126
|
+
max_size = (@features[:PacketSize].to_i - 19) & ~1
|
127
|
+
offset = 0
|
128
|
+
data = ""
|
129
|
+
size *= 2
|
130
|
+
|
131
|
+
while offset < size
|
132
|
+
chunk_size = [ max_size, size - offset ].min
|
133
|
+
|
134
|
+
response = command "m#{base.to_s 16},#{(chunk_size / 2).to_s 16}"
|
135
|
+
|
136
|
+
if response[0] == "E"
|
137
|
+
raise "Memory read failed: #{response}"
|
138
|
+
end
|
139
|
+
|
140
|
+
data += response
|
141
|
+
|
142
|
+
base += chunk_size / 2
|
143
|
+
offset += chunk_size
|
144
|
+
end
|
145
|
+
|
146
|
+
Array.new(data.length / 2) do |i|
|
147
|
+
data[i * 2..i * 2 + 1].to_i 16
|
148
|
+
end.pack("C*")
|
149
|
+
end
|
150
|
+
|
151
|
+
def insert_breakpoint(type, address, kind)
|
152
|
+
response = command "Z#{type.to_s 16},#{address.to_s 16},#{kind.to_s 16}"
|
153
|
+
|
154
|
+
if response != "OK"
|
155
|
+
raise "Breakpoint insertion failed: #{response}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def remove_breakpoint(type, address, kind)
|
160
|
+
response = command "z#{type.to_s 16},#{address.to_s 16},#{kind.to_s 16}"
|
161
|
+
|
162
|
+
if response != "OK"
|
163
|
+
raise "Breakpoint removal failed: #{response}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def continue
|
168
|
+
parse_stop_reply command("c")
|
169
|
+
end
|
170
|
+
|
171
|
+
def step
|
172
|
+
parse_stop_reply command("s")
|
173
|
+
end
|
174
|
+
|
175
|
+
def reset
|
176
|
+
reply = command "r"
|
177
|
+
|
178
|
+
if reply != "OK"
|
179
|
+
raise "Reset failed: #{reply}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_stop_reply
|
184
|
+
parse_stop_reply command("?")
|
185
|
+
end
|
186
|
+
|
187
|
+
def write_register(reg, value)
|
188
|
+
reply = command sprintf("P%x=%08x", reg, big2native(value))
|
189
|
+
|
190
|
+
if reply != "OK"
|
191
|
+
raise "Register write failed: #{reply}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
protected
|
196
|
+
|
197
|
+
def parse_stop_reply(reply)
|
198
|
+
case reply[0]
|
199
|
+
when 'S'
|
200
|
+
StopReply.new reply[1..2].to_i(16)
|
201
|
+
|
202
|
+
when 'T'
|
203
|
+
pairs = reply[3..-1].split ';'
|
204
|
+
values = {}
|
205
|
+
pairs.each do |pair|
|
206
|
+
key, value = pair.split ':'
|
207
|
+
|
208
|
+
if key.match /^[0-9a-fA-F]+/
|
209
|
+
values[key.to_i 16] = value.to_i 16
|
210
|
+
else
|
211
|
+
values[key] = value
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
StopReply.new reply[1..2].to_i(16), values
|
216
|
+
|
217
|
+
else
|
218
|
+
raise "Unknown stop reply: #{reply}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def read_xfer(object, annex)
|
223
|
+
offset = 0
|
224
|
+
size = @features[:PacketSize].to_i - 4
|
225
|
+
contents = ""
|
226
|
+
|
227
|
+
loop do
|
228
|
+
response = command "qXfer:#{object}:read:#{annex}:#{offset}:#{size}"
|
229
|
+
|
230
|
+
offset += response.length - 1
|
231
|
+
contents += response[1..-1]
|
232
|
+
|
233
|
+
if response[0] == 'l'
|
234
|
+
break
|
235
|
+
elsif response[0] != 'm'
|
236
|
+
raise "qXfer failed: #{response}"
|
237
|
+
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
contents
|
242
|
+
end
|
243
|
+
|
244
|
+
def command(s, extra = {})
|
245
|
+
send_packet s, extra
|
246
|
+
|
247
|
+
response = receive_packet
|
248
|
+
end
|
249
|
+
|
250
|
+
def send_packet(data, extra = {})
|
251
|
+
data = data.dup
|
252
|
+
|
253
|
+
if extra[:escape]
|
254
|
+
i = 0
|
255
|
+
|
256
|
+
while i < data.length
|
257
|
+
byte = data[i]
|
258
|
+
|
259
|
+
if byte == '$' || byte == '#' || byte == 0x7d.chr
|
260
|
+
data.insert i, 0x7d.chr
|
261
|
+
|
262
|
+
i += 1
|
263
|
+
end
|
264
|
+
|
265
|
+
i += 1
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
message = sprintf "$%s#%02x", data, data.sum(8)
|
270
|
+
|
271
|
+
if !@features[:PacketSize].nil? && @features[:PacketSize].to_i < message.length
|
272
|
+
raise "Internal error: message is too long"
|
273
|
+
end
|
274
|
+
|
275
|
+
@socket.write message
|
276
|
+
|
277
|
+
if @need_ack
|
278
|
+
loop do
|
279
|
+
ack = @socket.read 1
|
280
|
+
|
281
|
+
case ack
|
282
|
+
when '+'
|
283
|
+
break
|
284
|
+
|
285
|
+
when '-'
|
286
|
+
@socket.write message
|
287
|
+
|
288
|
+
else
|
289
|
+
raise "Unexpected response from server: #{ack}"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def receive_packet
|
296
|
+
loop do
|
297
|
+
@buf += @socket.readpartial 4096
|
298
|
+
|
299
|
+
if @buf[0] != '$'
|
300
|
+
raise "Invalid response from server"
|
301
|
+
end
|
302
|
+
|
303
|
+
idx = @buf.index '#'
|
304
|
+
|
305
|
+
if !idx.nil? && idx + 2 <= @buf.length
|
306
|
+
message = @buf.slice! 0..idx + 2
|
307
|
+
|
308
|
+
data = message[1..-4]
|
309
|
+
|
310
|
+
if @need_ack
|
311
|
+
checksum = data.sum 8
|
312
|
+
if checksum != message[-2..-1].to_i(16)
|
313
|
+
@socket.write '-'
|
314
|
+
else
|
315
|
+
@socket.write '+'
|
316
|
+
|
317
|
+
return data
|
318
|
+
end
|
319
|
+
else
|
320
|
+
return data
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def native2big(v)
|
327
|
+
[ v ].pack("N").unpack("L")[0]
|
328
|
+
end
|
329
|
+
|
330
|
+
def big2native(v)
|
331
|
+
[ v ].pack("L").unpack("N")[0]
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
data/lib/gdbflasher.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "gdbflasher/version"
|
2
|
+
require "gdbflasher/ihex"
|
3
|
+
require "gdbflasher/server_connection"
|
4
|
+
require "gdbflasher/mcu"
|
5
|
+
require "gdbflasher/cortexm"
|
6
|
+
require "gdbflasher/mcu/stm32f4xx"
|
7
|
+
require "gdbflasher/mcu/stm32l1xx"
|
8
|
+
require "gdbflasher/mcu/stm32f10xx_hd"
|
9
|
+
require "gdbflasher/mcu/stm32f10xx_md"
|
10
|
+
|
11
|
+
|
12
|
+
module GdbFlasher
|
13
|
+
MCU_CLASSES = {
|
14
|
+
stm32f4xx: Stm32f4xx,
|
15
|
+
stm32l1xx: Stm32l1xx,
|
16
|
+
stm32f10xx_hd: Stm32f10xxHD,
|
17
|
+
stm32f10xx_md: Stm32f10xxMD
|
18
|
+
}
|
19
|
+
|
20
|
+
HELPERS = File.join File.dirname(__FILE__), "..", "helpers"
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gdbflasher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sergey Gridasov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: trollop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: gdbflasher is a gdbserver-compatible tool for loading firmware into ARM
|
28
|
+
MCUs.
|
29
|
+
email:
|
30
|
+
- grindars@gmail.com
|
31
|
+
executables:
|
32
|
+
- gdbflasher
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- .gitignore
|
37
|
+
- Gemfile
|
38
|
+
- LICENSE
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- bin/gdbflasher
|
42
|
+
- gdbflasher.gemspec
|
43
|
+
- helper_sources/Makefile
|
44
|
+
- helper_sources/stm32f10xx_hd.S
|
45
|
+
- helper_sources/stm32f10xx_hd.lds
|
46
|
+
- helper_sources/stm32f10xx_md.S
|
47
|
+
- helper_sources/stm32f10xx_md.lds
|
48
|
+
- helper_sources/stm32f4xx.S
|
49
|
+
- helper_sources/stm32f4xx.lds
|
50
|
+
- helper_sources/stm32l1xx.S
|
51
|
+
- helper_sources/stm32l1xx.lds
|
52
|
+
- helpers/stm32f10xx_hd.hex
|
53
|
+
- helpers/stm32f10xx_hd.sym
|
54
|
+
- helpers/stm32f10xx_md.hex
|
55
|
+
- helpers/stm32f10xx_md.sym
|
56
|
+
- helpers/stm32f4xx.hex
|
57
|
+
- helpers/stm32f4xx.sym
|
58
|
+
- helpers/stm32l1xx.hex
|
59
|
+
- helpers/stm32l1xx.sym
|
60
|
+
- lib/gdbflasher.rb
|
61
|
+
- lib/gdbflasher/cortexm.rb
|
62
|
+
- lib/gdbflasher/ihex.rb
|
63
|
+
- lib/gdbflasher/mcu.rb
|
64
|
+
- lib/gdbflasher/mcu/stm32f10xx_hd.rb
|
65
|
+
- lib/gdbflasher/mcu/stm32f10xx_md.rb
|
66
|
+
- lib/gdbflasher/mcu/stm32f4xx.rb
|
67
|
+
- lib/gdbflasher/mcu/stm32l1xx.rb
|
68
|
+
- lib/gdbflasher/server_connection.rb
|
69
|
+
- lib/gdbflasher/version.rb
|
70
|
+
homepage: https://github.com/grindars/gdbflasher
|
71
|
+
licenses: []
|
72
|
+
metadata: {}
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 2.0.3
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: Retargetable flasher for ARM microcontrollers
|
93
|
+
test_files: []
|