13 import os, sys, subprocess
17 print(
"""-------------------------------------------------------------
18 Welcome to the Ubiquity Robotics Firmware Updater!
20 Please make sure that you are not running any ROS nodes.
21 - sudo systemctl stop magni-base
23 Note: Updating the firmware requires access to the internet.
24 -------------------------------------------------------------
27 TMP_FILE_PATH =
'/tmp/firmware'
30 parser = argparse.ArgumentParser(description=
'Ubiquity Robotics Firmware Updater')
31 parser.add_argument(
'--device', help=
'Serial port to use (eg /dev/ttyAMA0)', default=
'/dev/ttyAMA0')
32 parser.add_argument(
'--file', help=
'Path to a firmware file', default=
'')
33 args = parser.parse_args()
35 serial_port = args.device
37 if (subprocess.call([
'fuser',
'-v', serial_port], stdout=
None) == 0):
39 print(
"Another process is using the serial port, cannot upgrade firmware")
40 print(
"Make sure you stopped any running ROS nodes. To stop default nodes:")
41 print(
"sudo systemctl stop magni-base")
45 path_to_file = args.file
48 path_to_file = TMP_FILE_PATH
50 email = raw_input(
"Please enter your email address: ").strip()
55 r = requests.post(
'https://api.ubiquityrobotics.com/token/', json = {
'email': email})
57 if r.status_code == 500:
58 print(
"Error: 500 Internal Server Error. Something went wrong, try again in a few minutes. If the error persists, contact support.")
59 elif r.status_code != 200:
60 print(
"Error with requesting a token %d" % r.status_code)
63 print(
"An access token was sent to your email address")
65 token = raw_input(
"Please enter your access token: ").strip()
67 version = raw_input(
"What version would you like (press enter for latest): ").strip()
72 auth_headers = {
"Authorization":
"Bearer %s" % token}
73 r = requests.get(
'https://api.ubiquityrobotics.com/firmware/%s' % version, headers=auth_headers)
75 if r.status_code == 401:
76 print(
"Error: 401 Unauthorized. Please make sure that your token is valid and entered correctly.")
78 elif r.status_code == 404:
79 print(
"Error: 404 Not Found. The firmware version that you requested was not found.")
80 elif r.status_code == 500:
81 print(
"Error: 500 Internal Server Error. Something went wrong, try again in a few minutes. If the error persists, contact support.")
82 elif r.status_code != 200:
83 print(
"Error downloading firmware %d" % r.status_code)
86 with open(path_to_file,
'w+b')
as fd:
87 for chunk
in r.iter_content(chunk_size=128):
90 print(
"\nUpdating firmware now. Do not power off the robot. This is expected to take less than a minute.")
107 if type(bc) != int
or bc < 1:
108 raise Exception(
"Invalid read: " + str(bc))
121 f = open(filename,
"r")
126 not_encrypted =
False
133 if c ==
":" and encrypted:
134 raise Exception(
"Partial encryption")
135 if c ==
"+" and not_encrypted:
136 raise Exception(
"Partial encryption")
137 if c
not in [
'\n',
'\r',
'\t',
' ',
':',
"+"]:
138 fcontent = fcontent + c
139 while len(fcontent) >= 2:
140 fout += chr(int(fcontent[0:2], 16))
141 fcontent = fcontent[2:]
142 assert not_encrypted
or encrypted
149 out = out + ord(b) * scale
153 arrc = [x
for x
in arr]
158 asilicon_id = [x
for x
in f.read(4)]
159 asilicon_id.reverse()
161 for a
in asilicon_id:
164 silicon_rev = f.read(1)
165 checksum_type = f.read(1)
166 return silicon_id, silicon_rev, checksum_type
171 data = f.read(data_length)
173 return flash_id, row_number, data_length, data, checksum
179 data = f.read(data_length + 12)
180 return flash_id, row_number, data_length, data
184 return str(x) +
" <- " + str([hex(ord(l))
for l
in x])
186 return str(type(x)) +
" -> " + str(x)
202 if type(mylen) != int
or mylen < 0:
203 raise Exception(
"Invalid length goal for packet: " +
cstr(mylen))
204 if len(self.
inp) != mylen:
205 raise Exception(
"Invalid length for packet: " + len(self.
inp) +
" should be " + str(inp))
211 for step
in xrange(0, mylen):
212 numa.append(chr(num % 256))
214 self.
out.extend(numa)
217 raise Exception(
"Write to packet after send")
221 self.
out.extend([i
for i
in x])
223 self.
out.append(chr(x))
227 raise Exception(
"Read from packet before send")
228 if type(bytes) != int
or bytes < 1:
229 raise Exception(
"Invalid byte read: " +
cstr(bytes))
239 init_bytes = [chr(0x1), self.
cmd,
240 chr((len(self.
out) / 1) % 256),
241 chr((len(self.
out) / 256) % 256)]
242 init_bytes.extend(self.
out)
244 if DEBUG: print(
"-"*120)
245 if DEBUG: print(
"Send packet: " +
cstr(self.
out))
248 for c
in init_bytes: ib_buf += c
249 if DEBUG: print(
"Packet without end and checksum is",
cstr(ib_buf))
252 if DEBUG: print(
"Checksum is", checksum,
"LSB", (checksum / 1) % 256,
"MSB", (checksum / 256) % 256)
254 ib_buf += chr((checksum / 1) % 256)
255 ib_buf += chr((checksum / 256) % 256)
266 start_byte = header[0:1]
267 if start_byte != str(chr(0x01)):
268 raise Exception(
"Packet did not start with valid start byte, instead: " +
cstr(start_byte) +
" -- header: " +
cstr(header))
269 status_code = header[1:2]
270 if status_code != str(chr(0x00)):
271 raise Exception(
"Packet did not start with valid status, instead: " +
cstr(status_code) +
" -- header: " +
cstr(header))
272 data_length_raw = header[2:4]
273 data_length = (ord(data_length_raw[0])) + (ord(data_length_raw[1])) * 256
274 if DEBUG: print(
"Read in", data_length,
"from",
cstr(data_length_raw))
276 if len(self.
inp) != data_length:
277 raise Exception(
"We tried to read: " + str(data_length) +
" but instead read: " + str(len(self.
inp)) +
" -- header: " +
cstr(header))
280 checksum_bytes = start_byte + status_code + data_length_raw + self.
inp
283 checksum_raw = self.
ser.
read(2)
284 checksum = (ord(checksum_raw[0])) + (ord(checksum_raw[1]) * 256)
285 if checksum != checksum_comp:
286 raise Exception(
"Invalid checksum for packet: " +
cstr(checksum) +
" != " +
cstr(checksum_comp) +
" -- header: " +
cstr(header))
289 if end_byte != str(chr(0x17)):
290 raise Exception(
"Invalid terminator for packet: " +
cstr(end_byte) +
" -- header: " +
cstr(header))
311 x = (crc >> 8) ^ (int(ord(byte)) & 0xFF)
313 crc = ushort(ushort(crc << 8) ^ ushort(x << 12) ^ ushort(x << 5) ^ ushort(x))
319 p.write(row_number, 2)
328 silicon_id = p.read(4)
329 silicon_rev = p.read(1)
330 bootloader_version = p.read(3)
331 return silicon_id, silicon_rev, bootloader_version
338 flash_first_row = p.read_num(2)
339 flash_last_row = p.read_num(2)
340 return flash_first_row, flash_last_row
345 p.write(row_number, 2)
354 p.write(row_number, 2)
363 p.write(row_number, 2)
366 checksum = p.read_num(1)
385 p.write(app_number, 1)
388 valid_app_number = p.read_num(1)
389 active_app_number = p.read_num(1)
390 return valid_app_number, active_app_number
394 p.write(app_number, 1)
407 p.do_ignore_response()
413 return ((a & 0xFF) + (b & 0xFF)) & 0xFF
416 r =
add8(checksum, flash_id)
417 r =
add8(r, row_number)
418 r =
add8(r, row_number >> 8)
419 r =
add8(r, row_size)
420 r =
add8(r, row_size >> 8)
421 if DEBUG: print(
"Checksum convert:", checksum, flash_id, row_number, row_size,
"out:", r)
428 print(
"Unable to open file: ", path_to_file)
429 except InvalidFileException:
430 print(
"File is not of the correct format")
431 print(
"Encryption:", hex_stream.is_encrypted())
434 parity=serial.PARITY_NONE, stopbits=1, xonxoff=0, rtscts=0)
437 request_bootloader = [0x7E, 0x3E, 0x01, 0x01, 0x01, 0x01, 0x01]
438 request_bootloader.append(0xFF - sum(request_bootloader[1:]))
439 ser.write(
"".join([chr(x)
for x
in request_bootloader]))
444 file_silicon_id, file_silicon_rev, file_checksum_type =
read__header(hex_stream)
445 if file_silicon_id != silicon_id:
446 raise Exception(
"The silicon ids did not match " +
cstr(file_silicon_id) +
" != " +
cstr(silicon_id))
447 if file_silicon_rev != silicon_rev:
448 raise Exception(
"The silicon revs did not match")
450 if file_checksum_type != str(chr(0)):
451 raise Exception(
"Invalid checksum type: " +
cstr(file_checksum_type))
457 while hex_stream.is_open():
458 if not hex_stream.is_encrypted():
460 print(
"Writing row", row_number,
"for", flash_id,
"process at", (
"%.2f" % last_percent),
"percent completion")
461 last_percent = (100.0 * hex_stream.get_position()) / hex_stream.get_size()
464 if DEBUG: print(
"Write", flash_id, row_number, data_length, len(data), checksum,
"->", real_checksum)
467 if DEBUG: print(
"Flash: ", flash_first_row, flash_last_row)
468 if row_number < flash_first_row
or row_number > flash_last_row:
469 raise Exception(
"Invalid row: must be between " + str(flash_first_row)
470 +
" and " + str(flash_last_row) +
" but is " + str(row_number))
476 while data_strip != []
and data_strip !=
"":
477 bytes_at_a_time = 256
478 data_next = data_strip[0:bytes_at_a_time]
479 data_strip = data_strip[bytes_at_a_time:]
480 data_sent += bytes_at_a_time
481 if DEBUG: print(
"Sending", len(data_next),
"Sent: ", data_sent,
"Left: ", len(data_strip))
482 if data_strip == []
or data_strip ==
"":
484 if DEBUG: print(
"Last packet")
487 if real_checksum != comp_checksum:
488 raise Exception(
"Checksum error at " + flash_id +
" " + row_number
489 +
". We wanted " +
cstr(real_checksum) +
" but we got " +
cstr(comp_checksum))
491 if DEBUG: print(
"Checksum valid", flash_id, row_number,
"->", real_checksum,
"==", comp_checksum)
496 print(
"Writing row", row_number,
"for", flash_id,
"process at", (
"%.2f" % last_percent),
"percent completion")
497 last_percent = (100.0 * hex_stream.get_position()) / hex_stream.get_size()
498 assert len(data) < 256
502 raise Exception(
"Application checksum invalid")
513 print(
"Finished upgrading firmware!")