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!")