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