3
3
# Variable baud rate bootloader for Artemis Apollo3 modules
4
4
5
5
# 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
7
7
# respond with the bootloader version packet
8
8
# 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
12
12
# that to memory and request the next frame. If the CRC fails the Artemis will
13
13
# discard that data and send a request to re-send the previous frame.
14
14
# This cycle repeats until the Artemis receives a done command in place of the
15
15
# 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
18
18
# 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.
21
21
22
22
# 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
25
25
# 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
27
27
# ser.read(n) will time out after 2*ser.timeout
28
28
# Incoming UART data is buffered behind the scenes, probably by the OS.
29
29
46
46
# Commands
47
47
#
48
48
# ***********************************************************************************
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
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
55
55
56
56
barWidthInCharacters = 50 # Width of progress bar, ie [###### % complete
57
57
97
97
98
98
def get_crc16 (data ):
99
99
100
- #Table and code ported from Artemis SVL bootloader
100
+ # Table and code ported from Artemis SVL bootloader
101
101
crc = 0x0000
102
102
data = bytearray (data )
103
103
for ch in data :
@@ -108,30 +108,33 @@ def get_crc16(data):
108
108
return crc
109
109
110
110
111
-
112
111
# ***********************************************************************************
113
112
#
114
- # Wait for a packet
113
+ # Wait for a packet
115
114
#
116
115
# ***********************************************************************************
117
116
def wait_for_packet (ser ):
118
117
119
- packet = {'len' :0 , 'cmd' :0 , 'data' :0 , 'crc' :1 , 'timeout' :1 }
118
+ packet = {'len' : 0 , 'cmd' : 0 , 'data' : 0 , 'crc' : 1 , 'timeout' : 1 }
120
119
121
- n = ser .read (2 ) # get the number of bytes
120
+ n = ser .read (2 ) # get the number of bytes
122
121
if (len (n ) < 2 ):
123
122
return packet
124
-
125
- packet ['len' ] = int .from_bytes (n , byteorder = 'big' , signed = False ) #
123
+
124
+ packet ['len' ] = int .from_bytes (n , byteorder = 'big' , signed = False ) #
126
125
payload = ser .read (packet ['len' ])
127
126
128
127
if (len (payload ) != packet ['len' ]):
129
128
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
129
+
130
+ # all bytes received, so timeout is not true
131
+ packet ['timeout' ] = 0
132
+ # cmd is the first byte of the payload
133
+ packet ['cmd' ] = payload [0 ]
134
+ # the data is the part of the payload that is not cmd or crc
135
+ packet ['data' ] = payload [1 :packet ['len' ]- 2 ]
136
+ # performing the crc on the whole payload should return 0
137
+ packet ['crc' ] = get_crc16 (payload )
135
138
136
139
return packet
137
140
@@ -140,22 +143,20 @@ def wait_for_packet(ser):
140
143
# Send a packet
141
144
#
142
145
# ***********************************************************************************
146
+
147
+
143
148
def send_packet (ser , cmd , data ):
144
149
data = bytearray (data )
145
150
num_bytes = 3 + len (data )
146
- payload = bytearray (cmd .to_bytes (1 ,'big' ))
151
+ payload = bytearray (cmd .to_bytes (1 , 'big' ))
147
152
payload .extend (data )
148
153
crc = get_crc16 (payload )
149
- payload .extend (bytearray (crc .to_bytes (2 ,'big' )))
154
+ payload .extend (bytearray (crc .to_bytes (2 , 'big' )))
150
155
151
- ser .write (num_bytes .to_bytes (2 ,'big' ))
156
+ ser .write (num_bytes .to_bytes (2 , 'big' ))
152
157
ser .write (bytes (payload ))
153
158
154
159
155
-
156
-
157
-
158
-
159
160
# ***********************************************************************************
160
161
#
161
162
# Setup: signal baud rate, get version, and command BL enter
@@ -166,29 +167,25 @@ def phase_setup(ser):
166
167
baud_detect_byte = b'U'
167
168
168
169
verboseprint ('\n phase:\t setup' )
169
-
170
- # Handle the serial startup blip
170
+
171
+ # Handle the serial startup blip
171
172
ser .reset_input_buffer ()
172
- verboseprint ('\t cleared startup blip' )
173
+ verboseprint ('\t cleared startup blip' )
173
174
174
175
ser .write (baud_detect_byte ) # send the baud detection character
175
176
176
177
packet = wait_for_packet (ser )
177
178
if (packet ['timeout' ] or packet ['crc' ]):
178
179
return 1
179
-
180
- twopartprint ('\t ' ,'Got SVL Bootloader Version: ' +
180
+
181
+ twopartprint ('\t ' , 'Got SVL Bootloader Version: ' +
181
182
str (int .from_bytes (packet ['data' ], 'big' )))
182
183
verboseprint ('\t Sending \' enter bootloader\' command' )
183
184
184
185
send_packet (ser , SVL_CMD_BL , b'' )
185
186
186
187
# Now enter the bootload phase
187
188
188
-
189
-
190
-
191
-
192
189
193
190
# ***********************************************************************************
194
191
#
@@ -222,32 +219,34 @@ def phase_bootload(ser):
222
219
bl_done = False
223
220
bl_failed = False
224
221
while ((not bl_done ) and (not bl_failed )):
225
-
226
- packet = wait_for_packet (ser ) # wait for indication by Artemis
222
+
223
+ # wait for indication by Artemis
224
+ packet = wait_for_packet (ser )
227
225
if (packet ['timeout' ] or packet ['crc' ]):
228
226
print ('\n \t error receiving packet' )
229
227
print (packet )
230
228
print ('\n ' )
231
229
bl_failed = True
232
230
bl_done = True
233
231
234
- if ( packet ['cmd' ] == SVL_CMD_NEXT ):
232
+ if (packet ['cmd' ] == SVL_CMD_NEXT ):
235
233
# verboseprint('\tgot frame request')
236
234
curr_frame += 1
237
235
resend_count = 0
238
- elif ( packet ['cmd' ] == SVL_CMD_RETRY ):
236
+ elif (packet ['cmd' ] == SVL_CMD_RETRY ):
239
237
verboseprint ('\t \t retrying...' )
240
238
resend_count += 1
241
- if ( resend_count >= resend_max ):
239
+ if (resend_count >= resend_max ):
242
240
bl_failed = True
243
241
bl_done = True
244
242
else :
245
243
print ('unknown error' )
246
244
bl_failed = True
247
245
bl_done = True
248
246
249
- if ( curr_frame <= total_frames ):
250
- frame_data = application [((curr_frame - 1 )* frame_size ):((curr_frame - 1 + 1 )* frame_size )]
247
+ if (curr_frame <= total_frames ):
248
+ frame_data = application [(
249
+ (curr_frame - 1 )* frame_size ):((curr_frame - 1 + 1 )* frame_size )]
251
250
if (args .verbose ):
252
251
verboseprint ('\t sending frame #' + str (curr_frame ) +
253
252
', length: ' + str (len (frame_data )))
@@ -267,7 +266,7 @@ def phase_bootload(ser):
267
266
send_packet (ser , SVL_CMD_DONE , b'' )
268
267
bl_done = True
269
268
270
- if ( bl_failed == False ):
269
+ if (bl_failed == False ):
271
270
twopartprint ('\n \t ' , 'Upload complete' )
272
271
endTime = time .time ()
273
272
bps = total_len / (endTime - startTime )
@@ -278,10 +277,6 @@ def phase_bootload(ser):
278
277
return bl_failed
279
278
280
279
281
-
282
-
283
-
284
-
285
280
# ***********************************************************************************
286
281
#
287
282
# Help if serial port could not be opened
@@ -294,12 +289,12 @@ def phase_serial_port_help():
294
289
for dev in devices :
295
290
if (dev .device .upper () == args .port .upper ()):
296
291
print (dev .device + " is currently open. Please close any other terminal programs that may be using " +
297
- dev .device + " and try again." )
292
+ dev .device + " and try again." )
298
293
exit ()
299
294
300
295
# otherwise, give user a list of possible com ports
301
296
print (args .port .upper () +
302
- " not found but we detected the following serial ports:" )
297
+ " not found but we detected the following serial ports:" )
303
298
for dev in devices :
304
299
if 'CH340' in dev .description :
305
300
print (
@@ -329,19 +324,20 @@ def main():
329
324
330
325
with serial .Serial (args .port , args .baud , timeout = args .timeout ) as ser :
331
326
332
- t_su = 0.15 # startup time for Artemis bootloader (experimentally determined - 0.095 sec min delay)
327
+ # startup time for Artemis bootloader (experimentally determined - 0.095 sec min delay)
328
+ t_su = 0.15
333
329
334
330
time .sleep (t_su ) # Allow Artemis to come out of reset
335
331
phase_setup (ser ) # Perform baud rate negotiation
336
332
337
333
bl_failed = phase_bootload (ser ) # Bootload
338
334
339
- if ( bl_failed == False ):
335
+ if (bl_failed == False ):
340
336
break
341
337
342
338
except :
343
339
phase_serial_port_help ()
344
-
340
+
345
341
exit ()
346
342
347
343
@@ -367,7 +363,7 @@ def main():
367
363
action = "store_true" )
368
364
369
365
parser .add_argument ("-t" , "--timeout" , default = 0.50 , help = "Communication timeout in seconds (default 0.5)" ,
370
- type = float )
366
+ type = float )
371
367
372
368
if len (sys .argv ) < 2 :
373
369
print ("No port selected. Detected Serial Ports:" )
@@ -390,7 +386,7 @@ def verboseprint(*args):
390
386
391
387
def twopartprint (verbosestr , printstr ):
392
388
if args .verbose :
393
- print (verbosestr , end = '' )
389
+ print (verbosestr , end = '' )
394
390
395
391
print (printstr )
396
392
0 commit comments