163 lines
4.6 KiB
Python
Executable File
163 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
##########################################################################
|
|
# Copyright (c) 2019 ETH Zurich.
|
|
# All rights reserved.
|
|
#
|
|
# This file is distributed under the terms in the attached LICENSE file.
|
|
# If you do not find this file, copies can be found by writing to:
|
|
# ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
|
|
# Attn: Systems Group.
|
|
#
|
|
# Script to control the Toradex boards over the USB UART
|
|
#
|
|
##########################################################################
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import usb
|
|
import argparse
|
|
import cmd
|
|
|
|
class AOSBoard:
|
|
BITMODE_CBUS = 0x20
|
|
SIO_SET_BITMODE_REQUEST = 0x0b
|
|
|
|
def __init__(self, dev):
|
|
self._dev = dev
|
|
|
|
def _ftdi_set_bitmode(self, bitmask):
|
|
"""
|
|
FTDIs CBUS bitmode expect the following value:
|
|
CBUS Bits
|
|
3210 3210
|
|
|------ Output Control 0->LO, 1->HI
|
|
|----------- Input/Output 0->Input, 1->Output
|
|
|
|
This script assumes:
|
|
- CBUS3 connected to RESET_EXT#
|
|
- CBUS2 connected to OE# (recovery mode)
|
|
"""
|
|
bm_request_type = usb.util.build_request_type(
|
|
usb.util.CTRL_OUT,
|
|
usb.util.CTRL_TYPE_VENDOR,
|
|
usb.util.CTRL_RECIPIENT_DEVICE
|
|
)
|
|
|
|
wValue = bitmask | (AOSBoard.BITMODE_CBUS << 32)
|
|
self._dev.ctrl_transfer(bm_request_type, AOSBoard.SIO_SET_BITMODE_REQUEST, wValue)
|
|
|
|
def on(self):
|
|
# Set CBUS3 tristate, module run...
|
|
self._ftdi_set_bitmode(0x00)
|
|
|
|
def off(self):
|
|
# Set CBUS3 low, module in reset...
|
|
self._ftdi_set_bitmode(0x80)
|
|
|
|
def reset(self):
|
|
self.off()
|
|
time.sleep(0.1)
|
|
self.on()
|
|
|
|
def enter_recovery(self):
|
|
# Set recovery bit low
|
|
self._ftdi_set_bitmode(0x40)
|
|
time.sleep(0.2)
|
|
# Set reset bit low
|
|
self._ftdi_set_bitmode(0xC0)
|
|
time.sleep(0.1)
|
|
# Set reset bit tristate
|
|
self._ftdi_set_bitmode(0x40)
|
|
time.sleep(0.01)
|
|
# Set recovery bit tristate
|
|
self._ftdi_set_bitmode(0x00)
|
|
|
|
class BoardShell(cmd.Cmd):
|
|
|
|
def __init__(self, board):
|
|
super().__init__()
|
|
self._board = board
|
|
self.prompt = "aos-ctrl> "
|
|
|
|
def do_on(self, args):
|
|
"Turn the board on."
|
|
self._board.on()
|
|
|
|
def do_off(self, args):
|
|
"Turn the board off."
|
|
self._board.off()
|
|
|
|
def do_reset(self, args):
|
|
"Reset the board."
|
|
self._board.reset()
|
|
|
|
def do_recovery(self, args):
|
|
"Reset the board and enter recovery mode."
|
|
self._board.enter_recovery()
|
|
|
|
def do_exit(self, args):
|
|
"Exit the command prompt."
|
|
return True
|
|
|
|
def postcmd(self, stop, line):
|
|
return stop
|
|
|
|
def get_usb_backend():
|
|
if sys.platform == "win32":
|
|
# On Windows we can use libusb1 in combination with usbdk
|
|
# https://github.com/libusb/libusb/wiki/Windows#Driver_Installation
|
|
import usb.backend.libusb1
|
|
libusb_path = os.environ.get("LIBUSB_PATH")
|
|
backend = usb.backend.libusb1.get_backend(find_library=lambda x: libusb_path)
|
|
if backend is None:
|
|
print("Couldn't find libusb backend. Try setting LIBUSB_PATH environment variable.", file=sys.stderr)
|
|
return None
|
|
# PyUSB doesn't expose libusb option to use usbdk
|
|
# Workaround: https://github.com/pyusb/pyusb/issues/200#issuecomment-392621726
|
|
from ctypes import c_void_p, c_int
|
|
backend.lib.libusb_set_option.argtypes = [c_void_p, c_int]
|
|
backend.lib.libusb_set_option(backend.ctx, 1)
|
|
return backend
|
|
return None
|
|
|
|
def main(args):
|
|
dev = usb.core.find(
|
|
custom_match=lambda d: \
|
|
d.idVendor == 0x0403 and
|
|
d.idProduct == 0x6001 and
|
|
(
|
|
(args.board is None) or
|
|
(d.serial_number == args.board)
|
|
),
|
|
backend=get_usb_backend()
|
|
)
|
|
|
|
if dev is None:
|
|
if args.board is None:
|
|
print("No board found.", file=sys.stderr)
|
|
else:
|
|
print("Board with serial '%s' not found." % (args.board), file=sys.stderr)
|
|
exit(1)
|
|
|
|
board = AOSBoard(dev)
|
|
|
|
shell = BoardShell(board)
|
|
if args.command is None:
|
|
shell.cmdloop()
|
|
else:
|
|
shell.onecmd(args.command)
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Controls the Toradex Colibri boards")
|
|
parser.add_argument(
|
|
"--board", "-b", metavar="SERIAL", type=str,
|
|
help="Serial of the board to control"
|
|
)
|
|
parser.add_argument(
|
|
"command", metavar="CMD", type=str, nargs='?',
|
|
help="Commands to run"
|
|
)
|
|
args = parser.parse_args()
|
|
main(args)
|