274 lines
8.5 KiB
Python
274 lines
8.5 KiB
Python
#!/usr/bin/python3
|
|
from cv_usb_util.cv_usb import cv_usb
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import sys
|
|
import time
|
|
import cv_usb_util.cv_usb_pkt as pkt
|
|
from glob import glob
|
|
from array import array
|
|
from XmlParser import XmlParser
|
|
from zipfile import ZipFile
|
|
from tempfile import mkdtemp
|
|
from singleton import SingleInstance
|
|
FORMAT = '%(levelname)s: %(message)s'
|
|
logging.basicConfig(level=logging.INFO, format=FORMAT)
|
|
parser = argparse.ArgumentParser(description='Create CVITEK device image')
|
|
|
|
header_size = 64
|
|
max_chunk_size = 100 * 1024 * 1024
|
|
uboot_vidpid = ""
|
|
uboot_cvi_vidpid = ""
|
|
|
|
|
|
def parse_Args():
|
|
cur_dir = os.path.abspath(os.getcwd())
|
|
parser.add_argument(
|
|
'--image_dir',
|
|
metavar='path',
|
|
type=str,
|
|
default=cur_dir,
|
|
help='the folder path to dir inclued fip,rootfs kernel and xml')
|
|
parser.add_argument(
|
|
'--location',
|
|
metavar='',
|
|
type=str)
|
|
parser.add_argument(
|
|
'--pid',
|
|
metavar='1001',
|
|
default='1001',
|
|
type=str)
|
|
parser.add_argument("--zipfile",
|
|
metavar="path to upgrade.zip",
|
|
type=str,
|
|
help="the path of upgrade.zip")
|
|
parser.add_argument("-v",
|
|
"--verbose",
|
|
help="increase output verbosity",
|
|
action="store_true")
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument('--serial', action='store_true', default=False)
|
|
group.add_argument('--libusb', action='store_true', default=False)
|
|
|
|
parser.add_argument("--mac",
|
|
metavar="mac address",
|
|
type=str,
|
|
help="set mac address")
|
|
|
|
args = parser.parse_args()
|
|
if args.zipfile:
|
|
args.image_dir = mkdtemp()
|
|
with ZipFile(args.zipfile, 'r') as zipObj:
|
|
zipObj.extractall(args.image_dir)
|
|
if args.verbose:
|
|
logging.debug("Enable more verbose output")
|
|
logging.getLogger().setLevel(level=logging.DEBUG)
|
|
|
|
return args
|
|
|
|
|
|
def usage():
|
|
parser.print_usage()
|
|
|
|
|
|
def resource_path(relative_path):
|
|
""" Get absolute path to resource, works for dev and for PyInstaller """
|
|
try:
|
|
# PyInstaller creates a temp folder and stores path in _MEIPASS
|
|
base_path = sys._MEIPASS
|
|
except Exception:
|
|
base_path = os.path.dirname(os.path.realpath(__file__))
|
|
return os.path.join(base_path, relative_path)
|
|
|
|
|
|
def changeOffset(fd, offset):
|
|
last_pos = fd.tell()
|
|
"""
|
|
Since we cannot send cmd to device due to security issue. We can
|
|
only modify the header information for changing the offset we
|
|
want to program.
|
|
"""
|
|
# Get Chunk header
|
|
chunk_header = array('I')
|
|
chunk_header.fromfile(fd, 64)
|
|
chunk_header[2] = offset
|
|
# Modify header according to the partition.xml
|
|
fd.seek(last_pos)
|
|
fd.write(chunk_header)
|
|
fd.seek(last_pos)
|
|
|
|
|
|
def set_macaddress(usb, libusb, mac):
|
|
global uboot_vidpid
|
|
global uboot_cvi_vidpid
|
|
|
|
if not libusb:
|
|
usb.restart()
|
|
logging.info("set macaddress... ")
|
|
usb.query([uboot_vidpid, uboot_cvi_vidpid])
|
|
time.sleep(0.2)
|
|
|
|
# Send setenv
|
|
cmd = array('B', [ord(c) for c in "setenv ethaddr "])
|
|
for c in [ord(ch) for ch in mac]:
|
|
cmd.append(c)
|
|
usb.send_req_data(pkt.CV_USB_PRG_CMD, 0, len(cmd) + 8, cmd)
|
|
|
|
# Send savenv
|
|
cmd = array('B', [ord(c) for c in "saveenv"])
|
|
usb.send_req_data(pkt.CV_USB_PRG_CMD, 0, len(cmd) + 8, cmd)
|
|
# Break command
|
|
# usb.send_req_data(pkt.CV_USB_BREAK, 0x04003000, 0, None)
|
|
|
|
|
|
def reboot_device(usb, libusb):
|
|
global uboot_vidpid
|
|
global uboot_cvi_vidpid
|
|
|
|
# if not libusb:
|
|
# usb.restart()
|
|
# usb.query([uboot_vidpid,uboot_cvi_vidpid])
|
|
# time.sleep(0.2)
|
|
|
|
usb.send_req_data(pkt.CVI_USB_REBOOT, 0x04003000, 0, None)
|
|
|
|
logging.info("reboot device done")
|
|
|
|
|
|
def main():
|
|
args = parse_Args()
|
|
image_dir = args.image_dir
|
|
location = args.location
|
|
pid = args.pid
|
|
# location != None is usb_mult_dl
|
|
if(location is None):
|
|
try:
|
|
me = SingleInstance()
|
|
except Exception:
|
|
print("%d" % me)
|
|
exit(-1)
|
|
xml = glob(os.path.join(image_dir, "partition*.xml"))
|
|
if len(xml) != 1:
|
|
logging.error("Cannot get correct partition xml in %s", image_dir)
|
|
usage()
|
|
return
|
|
|
|
xmlParser = XmlParser(xml[0])
|
|
parts = xmlParser.parse(image_dir)
|
|
fip_path = os.path.join(image_dir, "fip.bin")
|
|
if not os.path.isfile(fip_path):
|
|
logging.error("Cannot find fip.bin in %s", image_dir)
|
|
cv_dl_magic = open(resource_path('cv_dl_magic.bin'), 'rb')
|
|
cv_dl_magic_size = os.path.getsize(resource_path('cv_dl_magic.bin'))
|
|
logging.info("CV1835 USB download start... ")
|
|
|
|
if (not args.serial and not args.libusb) or args.serial:
|
|
driver = "pyserial"
|
|
else:
|
|
driver = "libusb"
|
|
logging.info("Using %s" % driver)
|
|
usb = cv_usb(driver)
|
|
logging.info("Connecting to ROM code... ")
|
|
usb.query([pkt.rom_vidpid, pkt.rom_cvi_vidpid])
|
|
usb.send_chunk(cv_dl_magic, cv_dl_magic_size, 0x4003000, 0, Type="magic")
|
|
logging.info("done")
|
|
|
|
logging.info("Send fip.bin...")
|
|
usb.send_file(fip_path, 0x0C040000, 0)
|
|
logging.info("done")
|
|
|
|
# Set SRAM flag
|
|
logging.info("Send magic number for USB boot... ")
|
|
flag = array('B', [ord(c) for c in "1NGM"])
|
|
usb.send_req_data(pkt.CV_USB_NONE, 0x0E00FC00, 12, flag)
|
|
logging.info("done")
|
|
|
|
logging.info("Send magic number for USB download... ")
|
|
flag = array('B')
|
|
flag = array('B', [ord(c) for c in "3NGM"])
|
|
usb.send_req_data(pkt.CV_USB_NONE, 0x0E00FC08, 12, flag)
|
|
logging.info("done")
|
|
|
|
flag = array('B')
|
|
flag = array('B', [int(c) for c in pid])
|
|
usb.send_req_data(pkt.CV_USB_NONE, 0x0E00FFFC, 12, flag)
|
|
logging.info("set uboot pid")
|
|
|
|
usb.send_req_data(pkt.CV_USB_BREAK, 0x04003000, 0, None)
|
|
files = []
|
|
prog_parts = []
|
|
if xmlParser.getStorage() == "emmc":
|
|
files.append(fip_path)
|
|
prog_parts.append({}) # Add empty dict for fip
|
|
|
|
uboot_vidpid = "VID:PID=30B1:" + pid
|
|
uboot_cvi_vidpid = "VID:PID=3346:" + pid
|
|
usb.query([uboot_vidpid, uboot_cvi_vidpid])
|
|
|
|
for p in parts:
|
|
if p['file_size'] != 0:
|
|
files.append(p['file_path'])
|
|
prog_parts.append(p)
|
|
|
|
for i, f in enumerate(files):
|
|
if(location is not None):
|
|
# For UI Tool
|
|
print("SEND FILE %s " % files[i] + "LOCATION=" + location + "\r\n")
|
|
else:
|
|
logging.info("Send %s " % files[i])
|
|
|
|
if i == 0:
|
|
usb.send_file(f, 0x100090000, 0)
|
|
usb.send_req_data(pkt.CV_USB_BREAK, 0x04003000, 0, None)
|
|
usb.query([uboot_vidpid, uboot_cvi_vidpid])
|
|
time.sleep(0.02)
|
|
else:
|
|
if (driver == "pyserial"):
|
|
usb.restart()
|
|
logging.info("Connecting to u-boot... ")
|
|
usb.query([uboot_vidpid, uboot_cvi_vidpid])
|
|
time.sleep(1)
|
|
fd = open(f, 'r+b')
|
|
usb.send_chunk(fd, header_size, 0x100080000, 0)
|
|
fd.seek(0)
|
|
header = array('I')
|
|
header.fromfile(fd, int(header_size / 4))
|
|
chunk_header_sz = header[2]
|
|
cnt = header[3]
|
|
file_size = header[4]
|
|
remain_file_size = file_size
|
|
offset = prog_parts[i]["offset"]
|
|
for j in range(cnt):
|
|
if (j > 0 and driver == "pyserial"):
|
|
usb.restart()
|
|
logging.info("Connecting to u-boot... ")
|
|
usb.query([pkt.uboot_vidpid, pkt.uboot_cvi_vidpid])
|
|
time.sleep(0.02)
|
|
send_size = min(remain_file_size, max_chunk_size + chunk_header_sz)
|
|
# location != None is usb_mult_dl
|
|
if(location is None):
|
|
changeOffset(fd, offset)
|
|
usb.send_chunk(
|
|
fd,
|
|
send_size,
|
|
0x100090000,
|
|
0,
|
|
)
|
|
logging.info("CVI_USB_PROGRAME")
|
|
usb.send_req_data(pkt.CVI_USB_PROGRAME, 0x04003000, 0, None)
|
|
remain_file_size -= send_size
|
|
offset += max_chunk_size
|
|
if file_size == fd.tell():
|
|
break
|
|
fd.close()
|
|
logging.info("Image download finished, waiting for reboot!")
|
|
|
|
if args.mac:
|
|
set_macaddress(usb, driver == "libusb", args.mac)
|
|
reboot_device(usb, driver == "libusb")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|