Skip to content

Commit 48b563c

Browse files
author
Owen
authored
Merge pull request #137 from sparkfun/fix_svl_script
Fix svl script
2 parents eb4dc4e + dfcd5ab commit 48b563c

File tree

2 files changed

+106
-82
lines changed

2 files changed

+106
-82
lines changed

tools/artemis/artemis_svl.py

Lines changed: 106 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@
33
# Variable baud rate bootloader for Artemis Apollo3 modules
44

55
# Immediately upon reset the Artemis module will search for the timing character
6-
# to auto-detect the baud rate. If a valid baud rate is found the Artemis will
6+
# to auto-detect the baud rate. If a valid baud rate is found the Artemis will
77
# respond with the bootloader version packet
88
# If the computer receives a well-formatted version number packet at the desired
9-
# baud rate it will send a command to begin bootloading. The Artemis shall then
10-
# respond with the a command asking for the next frame.
11-
# The host will then send a frame packet. If the CRC is OK the Artemis will write
9+
# baud rate it will send a command to begin bootloading. The Artemis shall then
10+
# respond with the a command asking for the next frame.
11+
# The host will then send a frame packet. If the CRC is OK the Artemis will write
1212
# that to memory and request the next frame. If the CRC fails the Artemis will
1313
# discard that data and send a request to re-send the previous frame.
1414
# This cycle repeats until the Artemis receives a done command in place of the
1515
# requested frame data command.
16-
# The initial baud rate determination must occur within some small timeout. Once
17-
# baud rate detection has completed all additional communication will have a
16+
# The initial baud rate determination must occur within some small timeout. Once
17+
# baud rate detection has completed all additional communication will have a
1818
# universal timeout value. Once the Artemis has begun requesting data it may no
19-
# no longer exit the bootloader. If the host detects a timeout at any point it
20-
# will stop bootloading.
19+
# no longer exit the bootloader. If the host detects a timeout at any point it
20+
# will stop bootloading.
2121

2222
# Notes about PySerial timeout:
23-
# The timeout operates on whole functions - that is to say that a call to
24-
# ser.read(10) will return after ser.timeout, just as will ser.read(1) (assuming
23+
# The timeout operates on whole functions - that is to say that a call to
24+
# ser.read(10) will return after ser.timeout, just as will ser.read(1) (assuming
2525
# that the necessary bytes were not found)
26-
# If there are no incoming bytes (on the line or in the buffer) then two calls to
26+
# If there are no incoming bytes (on the line or in the buffer) then two calls to
2727
# ser.read(n) will time out after 2*ser.timeout
2828
# Incoming UART data is buffered behind the scenes, probably by the OS.
2929

@@ -39,19 +39,23 @@
3939
import sys
4040
import time
4141
import math
42+
import os.path
4243
from sys import exit
4344

45+
SCRIPT_VERSION_MAJOR = "1"
46+
SCRIPT_VERSION_MINOR = "7"
47+
4448
# ***********************************************************************************
4549
#
4650
# Commands
4751
#
4852
# ***********************************************************************************
49-
SVL_CMD_VER = 0x01 # version
50-
SVL_CMD_BL = 0x02 # enter bootload mode
51-
SVL_CMD_NEXT = 0x03 # request next chunk
52-
SVL_CMD_FRAME = 0x04 # indicate app data frame
53-
SVL_CMD_RETRY = 0x05 # request re-send frame
54-
SVL_CMD_DONE = 0x06 # finished - all data sent
53+
SVL_CMD_VER = 0x01 # version
54+
SVL_CMD_BL = 0x02 # enter bootload mode
55+
SVL_CMD_NEXT = 0x03 # request next chunk
56+
SVL_CMD_FRAME = 0x04 # indicate app data frame
57+
SVL_CMD_RETRY = 0x05 # request re-send frame
58+
SVL_CMD_DONE = 0x06 # finished - all data sent
5559

5660
barWidthInCharacters = 50 # Width of progress bar, ie [###### % complete
5761

@@ -97,7 +101,7 @@
97101

98102
def get_crc16(data):
99103

100-
#Table and code ported from Artemis SVL bootloader
104+
# Table and code ported from Artemis SVL bootloader
101105
crc = 0x0000
102106
data = bytearray(data)
103107
for ch in data:
@@ -108,30 +112,33 @@ def get_crc16(data):
108112
return crc
109113

110114

111-
112115
# ***********************************************************************************
113116
#
114-
# Wait for a packet
117+
# Wait for a packet
115118
#
116119
# ***********************************************************************************
117120
def wait_for_packet(ser):
118121

119-
packet = {'len':0, 'cmd':0, 'data':0, 'crc':1, 'timeout':1}
122+
packet = {'len': 0, 'cmd': 0, 'data': 0, 'crc': 1, 'timeout': 1}
120123

121-
n = ser.read(2) # get the number of bytes
124+
n = ser.read(2) # get the number of bytes
122125
if(len(n) < 2):
123126
return packet
124-
125-
packet['len'] = int.from_bytes(n, byteorder='big', signed=False) #
127+
128+
packet['len'] = int.from_bytes(n, byteorder='big', signed=False) #
126129
payload = ser.read(packet['len'])
127130

128131
if(len(payload) != packet['len']):
129132
return packet
130-
131-
packet['timeout'] = 0 # all bytes received, so timeout is not true
132-
packet['cmd'] = payload[0] # cmd is the first byte of the payload
133-
packet['data'] = payload[1:packet['len']-2] # the data is the part of the payload that is not cmd or crc
134-
packet['crc'] = get_crc16(payload) # performing the crc on the whole payload should return 0
133+
134+
# all bytes received, so timeout is not true
135+
packet['timeout'] = 0
136+
# cmd is the first byte of the payload
137+
packet['cmd'] = payload[0]
138+
# the data is the part of the payload that is not cmd or crc
139+
packet['data'] = payload[1:packet['len']-2]
140+
# performing the crc on the whole payload should return 0
141+
packet['crc'] = get_crc16(payload)
135142

136143
return packet
137144

@@ -140,22 +147,20 @@ def wait_for_packet(ser):
140147
# Send a packet
141148
#
142149
# ***********************************************************************************
150+
151+
143152
def send_packet(ser, cmd, data):
144153
data = bytearray(data)
145154
num_bytes = 3 + len(data)
146-
payload = bytearray(cmd.to_bytes(1,'big'))
155+
payload = bytearray(cmd.to_bytes(1, 'big'))
147156
payload.extend(data)
148157
crc = get_crc16(payload)
149-
payload.extend(bytearray(crc.to_bytes(2,'big')))
158+
payload.extend(bytearray(crc.to_bytes(2, 'big')))
150159

151-
ser.write(num_bytes.to_bytes(2,'big'))
160+
ser.write(num_bytes.to_bytes(2, 'big'))
152161
ser.write(bytes(payload))
153162

154163

155-
156-
157-
158-
159164
# ***********************************************************************************
160165
#
161166
# Setup: signal baud rate, get version, and command BL enter
@@ -165,29 +170,27 @@ def phase_setup(ser):
165170

166171
baud_detect_byte = b'U'
167172

168-
verboseprint('\nphase:\tsetup')
169-
170-
# Handle the serial startup blip
173+
verboseprint('\nPhase:\tSetup')
174+
175+
# Handle the serial startup blip
171176
ser.reset_input_buffer()
172-
verboseprint('\tcleared startup blip')
177+
verboseprint('\tCleared startup blip')
173178

174179
ser.write(baud_detect_byte) # send the baud detection character
175180

176181
packet = wait_for_packet(ser)
177182
if(packet['timeout'] or packet['crc']):
178-
return 1
179-
180-
twopartprint('\t','Got SVL Bootloader Version: ' +
183+
return False # failed to enter bootloader
184+
185+
twopartprint('\t', 'Got SVL Bootloader Version: ' +
181186
str(int.from_bytes(packet['data'], 'big')))
182187
verboseprint('\tSending \'enter bootloader\' command')
183188

184189
send_packet(ser, SVL_CMD_BL, b'')
185190

186-
# Now enter the bootload phase
187-
188-
189-
191+
return True
190192

193+
# Now enter the bootload phase
191194

192195

193196
# ***********************************************************************************
@@ -203,7 +206,7 @@ def phase_bootload(ser):
203206
resend_max = 4
204207
resend_count = 0
205208

206-
verboseprint('\nphase:\tbootload')
209+
verboseprint('\nPhase:\tBootload')
207210

208211
with open(args.binfile, mode='rb') as binfile:
209212
application = binfile.read()
@@ -220,36 +223,38 @@ def phase_bootload(ser):
220223
' bytes to send in ' + str(total_frames) + ' frames')
221224

222225
bl_done = False
223-
bl_failed = False
224-
while((not bl_done) and (not bl_failed)):
225-
226-
packet = wait_for_packet(ser) # wait for indication by Artemis
226+
bl_succeeded = True
227+
while((bl_done == False) and (bl_succeeded == True)):
228+
229+
# wait for indication by Artemis
230+
packet = wait_for_packet(ser)
227231
if(packet['timeout'] or packet['crc']):
228-
print('\n\terror receiving packet')
229-
print(packet)
230-
print('\n')
231-
bl_failed = True
232+
verboseprint('\n\tError receiving packet')
233+
verboseprint(packet)
234+
verboseprint('\n')
235+
bl_succeeded = False
232236
bl_done = True
233237

234-
if( packet['cmd'] == SVL_CMD_NEXT ):
238+
if(packet['cmd'] == SVL_CMD_NEXT):
235239
# verboseprint('\tgot frame request')
236240
curr_frame += 1
237241
resend_count = 0
238-
elif( packet['cmd'] == SVL_CMD_RETRY ):
239-
verboseprint('\t\tretrying...')
242+
elif(packet['cmd'] == SVL_CMD_RETRY):
243+
verboseprint('\t\tRetrying...')
240244
resend_count += 1
241-
if( resend_count >= resend_max ):
242-
bl_failed = True
245+
if(resend_count >= resend_max):
246+
bl_succeeded = False
243247
bl_done = True
244248
else:
245-
print('unknown error')
246-
bl_failed = True
249+
print('Timeout or unknown error')
250+
bl_succeeded = False
247251
bl_done = True
248252

249-
if( curr_frame <= total_frames ):
250-
frame_data = application[((curr_frame-1)*frame_size):((curr_frame-1+1)*frame_size)]
253+
if(curr_frame <= total_frames):
254+
frame_data = application[(
255+
(curr_frame-1)*frame_size):((curr_frame-1+1)*frame_size)]
251256
if(args.verbose):
252-
verboseprint('\tsending frame #'+str(curr_frame) +
257+
verboseprint('\tSending frame #'+str(curr_frame) +
253258
', length: '+str(len(frame_data)))
254259
else:
255260
percentComplete = curr_frame * 100 / total_frames
@@ -267,19 +272,15 @@ def phase_bootload(ser):
267272
send_packet(ser, SVL_CMD_DONE, b'')
268273
bl_done = True
269274

270-
if( bl_failed == False ):
275+
if(bl_succeeded == True):
271276
twopartprint('\n\t', 'Upload complete')
272277
endTime = time.time()
273278
bps = total_len / (endTime - startTime)
274279
verboseprint('\n\tNominal bootload bps: ' + str(round(bps, 2)))
275280
else:
276281
twopartprint('\n\t', 'Upload failed')
277282

278-
return bl_failed
279-
280-
281-
282-
283+
return bl_succeeded
283284

284285

285286
# ***********************************************************************************
@@ -294,12 +295,12 @@ def phase_serial_port_help():
294295
for dev in devices:
295296
if(dev.device.upper() == args.port.upper()):
296297
print(dev.device + " is currently open. Please close any other terminal programs that may be using " +
297-
dev.device + " and try again.")
298+
dev.device + " and try again.")
298299
exit()
299300

300301
# otherwise, give user a list of possible com ports
301302
print(args.port.upper() +
302-
" not found but we detected the following serial ports:")
303+
" not found but we detected the following serial ports:")
303304
for dev in devices:
304305
if 'CH340' in dev.description:
305306
print(
@@ -325,23 +326,46 @@ def main():
325326

326327
print('\n\nArtemis SVL Bootloader')
327328

329+
verboseprint("Script version " + SCRIPT_VERSION_MAJOR +
330+
"." + SCRIPT_VERSION_MINOR)
331+
332+
if not os.path.exists(args.binfile):
333+
print("Bin file {} does not exist.".format(args.binfile))
334+
exit()
335+
336+
bl_success = False
337+
entered_bootloader = False
338+
328339
for _ in range(num_tries):
329340

330341
with serial.Serial(args.port, args.baud, timeout=args.timeout) as ser:
331342

332-
t_su = 0.15 # startup time for Artemis bootloader (experimentally determined - 0.095 sec min delay)
343+
# startup time for Artemis bootloader (experimentally determined - 0.095 sec min delay)
344+
t_su = 0.15
333345

334346
time.sleep(t_su) # Allow Artemis to come out of reset
335-
phase_setup(ser) # Perform baud rate negotiation
336347

337-
bl_failed = phase_bootload(ser) # Bootload
348+
# Perform baud rate negotiation
349+
entered_bootloader = phase_setup(ser)
350+
351+
if(entered_bootloader == True):
352+
bl_success = phase_bootload(ser)
353+
if(bl_success == True): # Bootload
354+
#print("Bootload complete!")
355+
break
356+
else:
357+
verboseprint("Failed to enter bootload phase")
338358

339-
if( bl_failed == False ):
359+
if(bl_success == True):
340360
break
341361

342-
except:
362+
if(entered_bootloader == False):
363+
print(
364+
"Target failed to enter bootload mode. Verify the right COM port is selected and that your board has the SVL bootloader.")
365+
366+
except serial.SerialException:
343367
phase_serial_port_help()
344-
368+
345369
exit()
346370

347371

@@ -367,7 +391,7 @@ def main():
367391
action="store_true")
368392

369393
parser.add_argument("-t", "--timeout", default=0.50, help="Communication timeout in seconds (default 0.5)",
370-
type=float)
394+
type=float)
371395

372396
if len(sys.argv) < 2:
373397
print("No port selected. Detected Serial Ports:")
@@ -390,7 +414,7 @@ def verboseprint(*args):
390414

391415
def twopartprint(verbosestr, printstr):
392416
if args.verbose:
393-
print(verbosestr, end = '')
417+
print(verbosestr, end='')
394418

395419
print(printstr)
396420

tools/artemis/windows/artemis_svl.exe

2.62 KB
Binary file not shown.

0 commit comments

Comments
 (0)