aboutsummaryrefslogtreecommitdiff
path: root/Tools/px_uploader.py
diff options
context:
space:
mode:
authorLorenz Meier <lm@inf.ethz.ch>2012-10-02 10:41:21 +0200
committerLorenz Meier <lm@inf.ethz.ch>2012-10-02 10:41:21 +0200
commit21b86cba26d41ff8ba8064c72f0d8e17267df5df (patch)
tree2ebf536f2b5b8070920e12fc97e6525918454367 /Tools/px_uploader.py
parentd75266f3903578b845bd5144556bf8379329d489 (diff)
downloadpx4-firmware-21b86cba26d41ff8ba8064c72f0d8e17267df5df.tar.gz
px4-firmware-21b86cba26d41ff8ba8064c72f0d8e17267df5df.tar.bz2
px4-firmware-21b86cba26d41ff8ba8064c72f0d8e17267df5df.zip
Updated upload script
Diffstat (limited to 'Tools/px_uploader.py')
-rwxr-xr-xTools/px_uploader.py124
1 files changed, 102 insertions, 22 deletions
diff --git a/Tools/px_uploader.py b/Tools/px_uploader.py
index 7ebd37e75..296de721b 100755
--- a/Tools/px_uploader.py
+++ b/Tools/px_uploader.py
@@ -60,6 +60,7 @@ import json
import zlib
import base64
import time
+import array
from sys import platform as _platform
@@ -67,7 +68,41 @@ class firmware(object):
'''Loads a firmware file'''
desc = {}
- image = bytearray()
+ image = bytes()
+ crctab = array.array('I', [
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ])
+ crcpad = bytearray('\xff\xff\xff\xff')
def __init__(self, path):
@@ -76,30 +111,48 @@ class firmware(object):
self.desc = json.load(f)
f.close()
- self.image = zlib.decompress(base64.b64decode(self.desc['image']))
+ self.image = bytearray(zlib.decompress(base64.b64decode(self.desc['image'])))
# pad image to 4-byte length
while ((len(self.image) % 4) != 0):
- self.image += b'\x00'
+ self.image.append('\xff')
def property(self, propname):
return self.desc[propname]
+ def __crc32(self, bytes, state):
+ for byte in bytes:
+ index = (state ^ byte) & 0xff
+ state = self.crctab[index] ^ (state >> 8)
+ return state
+
+ def crc(self, padlen):
+ state = self.__crc32(self.image, int(0))
+ for i in range(len(self.image), (padlen - 1), 4):
+ state = self.__crc32(self.crcpad, state)
+ return state
class uploader(object):
'''Uploads a firmware file to the PX FMU bootloader'''
- NOP = chr(0x00)
- OK = chr(0x10)
- FAILED = chr(0x11)
+ # protocol bytes
INSYNC = chr(0x12)
EOC = chr(0x20)
+
+ # reply bytes
+ OK = chr(0x10)
+ FAILED = chr(0x11)
+ INVALID = chr(0x13) # rev3+
+
+ # command bytes
+ NOP = chr(0x00) # guaranteed to be discarded by the bootloader
GET_SYNC = chr(0x21)
GET_DEVICE = chr(0x22)
CHIP_ERASE = chr(0x23)
- CHIP_VERIFY = chr(0x24)
+ CHIP_VERIFY = chr(0x24) # rev2 only
PROG_MULTI = chr(0x27)
- READ_MULTI = chr(0x28)
+ READ_MULTI = chr(0x28) # rev2 only
+ GET_CRC = chr(0x29) # rev3+
REBOOT = chr(0x30)
INFO_BL_REV = chr(1) # bootloader protocol revision
@@ -126,19 +179,28 @@ class uploader(object):
def __recv(self, count = 1):
c = self.port.read(count)
- if (len(c) < 1):
+ if len(c) < 1:
raise RuntimeError("timeout waiting for data")
# print("recv " + binascii.hexlify(c))
return c
+ def __recv_int(self):
+ raw = self.__recv(4)
+ val = struct.unpack("<I", raw)
+ return val[0]
+
def __getSync(self):
self.port.flush()
c = self.__recv()
- if (c != self.INSYNC):
+ if c is not self.INSYNC:
raise RuntimeError("unexpected 0x%x instead of INSYNC" % ord(c))
c = self.__recv()
- if (c != self.OK):
- raise RuntimeError("unexpected 0x%x instead of OK" % ord(c))
+ if c == self.INVALID:
+ raise RuntimeError("bootloader reports INVALID OPERATION")
+ if c == self.FAILED:
+ raise RuntimeError("bootloader reports OPERATION FAILED")
+ if c != self.OK:
+ raise RuntimeError("unexpected response 0x%x instead of OK" % ord(c))
# attempt to get back into sync with the bootloader
def __sync(self):
@@ -164,10 +226,9 @@ class uploader(object):
# send the GET_DEVICE command and wait for an info parameter
def __getInfo(self, param):
self.__send(uploader.GET_DEVICE + param + uploader.EOC)
- raw = self.__recv(4)
+ value = self.__recv_int()
self.__getSync()
- value = struct.unpack_from('<I', raw)
- return value[0]
+ return value
# send the CHIP_ERASE command and wait for the bootloader to become ready
def __erase(self):
@@ -200,7 +261,7 @@ class uploader(object):
+ uploader.EOC)
self.port.flush()
programmed = self.__recv(len(data))
- if (programmed != data):
+ if programmed != data:
print("got " + binascii.hexlify(programmed))
print("expect " + binascii.hexlify(data))
return False
@@ -209,9 +270,14 @@ class uploader(object):
# send the reboot command
def __reboot(self):
- self.__send(uploader.REBOOT)
+ self.__send(uploader.REBOOT
+ + uploader.EOC)
self.port.flush()
+ # v3+ can report failure if the first word flash fails
+ if self.bl_rev >= 3:
+ self.__getSync()
+
# split a sequence into a list of size-constrained pieces
def __split_len(self, seq, length):
return [seq[i:i+length] for i in range(0, len(seq), length)]
@@ -224,7 +290,7 @@ class uploader(object):
self.__program_multi(bytes)
# verify code
- def __verify(self, fw):
+ def __verify_v2(self, fw):
self.__send(uploader.CHIP_VERIFY
+ uploader.EOC)
self.__getSync()
@@ -234,14 +300,25 @@ class uploader(object):
if (not self.__verify_multi(bytes)):
raise RuntimeError("Verification failed")
+ def __verify_v3(self, fw):
+ expect_crc = fw.crc(self.fw_maxsize)
+ self.__send(uploader.GET_CRC
+ + uploader.EOC)
+ report_crc = self.__recv_int()
+ self.__getSync()
+ if report_crc != expect_crc:
+ print("Expected 0x%x" % expect_crc)
+ print("Got 0x%x" % report_crc)
+ raise RuntimeError("Program CRC failed")
+
# get basic data about the board
def identify(self):
# make sure we are in sync before starting
self.__sync()
# get the bootloader protocol ID first
- bl_rev = self.__getInfo(uploader.INFO_BL_REV)
- if (bl_rev < uploader.BL_REV_MIN) or (bl_rev > uploader.BL_REV_MAX):
+ self.bl_rev = self.__getInfo(uploader.INFO_BL_REV)
+ if (self.bl_rev < uploader.BL_REV_MIN) or (self.bl_rev > uploader.BL_REV_MAX):
print("Unsupported bootloader protocol %d" % uploader.INFO_BL_REV)
raise RuntimeError("Bootloader protocol mismatch")
@@ -264,7 +341,10 @@ class uploader(object):
self.__program(fw)
print("verify...")
- self.__verify(fw)
+ if self.bl_rev == 2:
+ self.__verify_v2(fw)
+ else:
+ self.__verify_v3(fw)
print("done, rebooting.")
self.__reboot()
@@ -313,7 +393,7 @@ while True:
try:
# identify the bootloader
up.identify()
- print("Found board %x,%x on %s" % (up.board_type, up.board_rev, port))
+ print("Found board %x,%x bootloader rev %x on %s" % (up.board_type, up.board_rev, up.bl_rev, port))
except:
# most probably a timeout talking to the port, no bootloader