diff options
author | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2019-05-29 00:13:23 +0200 |
---|---|---|
committer | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2019-05-29 00:13:23 +0200 |
commit | 9a703092e4119ca385ca7faa8e6c807b6b7e7d42 (patch) | |
tree | 859d0a4cab12eca7ce09e7c18eeecabab10c7b81 | |
parent | 9d8589648749a005ee9c11cba3783b4524464cdc (diff) |
usb-control: Factor out product string.
In order to bring back the functionality of the
telaviv.py script, which has been remove in a previous
commit, this commit factors out the common code into
cp210x_controller.py.
Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
-rw-r--r-- | usb-control/cp210x_controller.py | 193 | ||||
-rwxr-xr-x | usb-control/haikou.py | 187 | ||||
-rwxr-xr-x | usb-control/telaviv.py | 15 |
3 files changed, 212 insertions, 183 deletions
diff --git a/usb-control/cp210x_controller.py b/usb-control/cp210x_controller.py new file mode 100644 index 0000000..5195f07 --- /dev/null +++ b/usb-control/cp210x_controller.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python + +__copyright__ = 'Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH' +__license__ = 'MIT' + +import argparse +import usb.core +import usb.util +import sys +import time + +VENDOR_ID = 0x10c4 +PRODUCT_ID = 0xea60 + +REQTYPE_HOST_TO_DEVICE = 0x40 +REQTYPE_DEVICE_TO_HOST = 0xc0 + +CP210X_VENDOR_SPECIFIC = 0xFF + +CP210X_WRITE_LATCH = 0x37E1 +CP210X_READ_LATCH = 0x00C2 +CP210X_GET_MDMSTS = 0x8 + +# Power supply GPIO +GPIO_POWER = 0 +VALUE_POWER_RELEASE = 0 +VALUE_POWER_PRESS = 1 + +# BIOS disable GPIO +GPIO_BIOS = 1 +VALUE_BIOS_NORMAL = 0 +VALUE_BIOS_DISABLE = 1 + +# Power state +POWERSTATE_ON = 0 +POWERSTATE_OFF = 1 + +def set_gpio(dev, gpio, value): + # the latch register has 16 bit. the upper 8 bits are the gpio value, + # the lower 8 bit are the write mask. + val = (value << (8 + gpio)) | (1 << gpio); + dev.ctrl_transfer(bmRequestType = REQTYPE_HOST_TO_DEVICE, + bRequest = CP210X_VENDOR_SPECIFIC, + wValue = CP210X_WRITE_LATCH, + wIndex = val) + +def get_gpio(dev, gpio): + # Read 1 byte from latch register + data = dev.ctrl_transfer(bmRequestType = REQTYPE_DEVICE_TO_HOST, + bRequest = CP210X_VENDOR_SPECIFIC, + wValue = CP210X_READ_LATCH, + data_or_wLength = 1) + return not not (data[0] & (1 << gpio)) + +def toggle_power(dev): + # We emulate a power button press for 300 ms + set_gpio(dev, GPIO_POWER, VALUE_POWER_PRESS) + time.sleep(1) + set_gpio(dev, GPIO_POWER, VALUE_POWER_RELEASE) + +def get_powerstate(dev): + # Reading the latch would be useless, but we have CTS connected to 3V3 + # Get modem status + data = dev.ctrl_transfer(bmRequestType = REQTYPE_DEVICE_TO_HOST, + bRequest = CP210X_GET_MDMSTS, + wValue = 0, + wIndex = 0, + data_or_wLength = 1); + # Check CTS line + return ((data[0] >> 4) & 1) + +def get_bootmode(dev): + # We can only check if we pull the line low + return get_gpio(dev, GPIO_BIOS) + +def create_parser(): + parser = argparse.ArgumentParser(description= + 'Controls power and BIOS disable state of the Haikou baseboard') + + # Generic arguments (for identifying the USB device) + parser.add_argument('--ignore-product-string', '-i', + action='store_true', + dest='ignore_product_string', + help='ignore product string') + + parser.add_argument('--serial', '-s', + action='store', + dest='serialnumber', + type=str, + help='defines the serialnumber to use') + + # Arguments to set the bootmode + parser_bootmode_group = parser.add_mutually_exclusive_group() + parser_bootmode_group.add_argument('--normal-boot', '-n', + action='store_true', + dest='normal_boot', + help='activate Normal Boot') + parser_bootmode_group.add_argument('--bios-disable', '-b', + action='store_true', + dest='bios_disable', + help='activate BIOS Disable') + + # Commands + subparsers = parser.add_subparsers(help='command to perform', + dest='subcommand') + subparsers.add_parser('list', + help='lists serial numbers of attached Haikou Baseboards') + subparsers.add_parser('on', + help='turn on attached Haikou Baseboards') + subparsers.add_parser('off', + help='turn off attached Haikou Baseboards') + subparsers.add_parser('cycle', + help='power cycle attached Haikou Baseboards') + subparsers.add_parser('toggle', + help='emulate power button press on attached Haikou Baseboards') + subparsers.add_parser('status', + help='show status of attached Haikou Baseboards') + + return parser + +def find_board_list(product_string, serialnumber): + try: + kwargs = dict() + kwargs['idVendor'] = VENDOR_ID + kwargs['idProduct'] = PRODUCT_ID + if product_string != None: + kwargs['product'] = product_string + if serialnumber: + kwargs['serial_number'] = args.serialnumber + kwargs['find_all'] = True + + # Find the devices matching the specified requirements + dev_it = usb.core.find(**kwargs) + + # Convert iterator to list + devs = list(dev_it) + + return devs + + except ValueError, e: + if 'langid' in e.message: + raise usb.core.USBError(e.message + "\n" + + "This may be a permission issue. See: \n" + + "https://github.com/pyusb/pyusb/issues/139") + +def cp210x_controller(product_string): + # Create the argument parser + parser = create_parser() + + # Apply the parser + args = parser.parse_args() + + # Collect list of potential devices + if args.ignore_product_string == True: + product_string = None + devs = find_board_list(product_string, args.serialnumber) + + if args.subcommand == 'list': + print "Found %d Baseboard%s:" % (len(devs), "s"[len(devs) == 1:]) + for idx, dev in enumerate(devs): + print "%d: %s %s" % (idx, dev.serial_number, dev.product) + sys.exit() + + + for dev in devs: + if args.bios_disable: + set_gpio(dev, GPIO_BIOS, VALUE_BIOS_DISABLE) + elif args.normal_boot: + set_gpio(dev, GPIO_BIOS, VALUE_BIOS_NORMAL) + + if args.subcommand == 'on': + if get_powerstate(dev) == POWERSTATE_OFF: + toggle_power(dev) + elif args.subcommand == 'off': + if get_powerstate(dev) == POWERSTATE_ON: + toggle_power(dev) + elif args.subcommand == 'cycle': + if get_powerstate(dev) == POWERSTATE_ON: + toggle_power(dev) + time.sleep(1) + toggle_power(dev) + elif args.subcommand == 'toggle': + toggle_power(dev) + elif args.subcommand == 'status': + powerstate = get_powerstate(dev) + bootmode = get_bootmode(dev) + print "Board is {} ({})".format( + ("ON" if powerstate == POWERSTATE_ON else "OFF"), + ("BIOS disabled" if bootmode == VALUE_BIOS_DISABLE else "Normal boot (if not overruled by on-board switch)")) + +if __name__ == '__main__': + cp210x_controller(None) + diff --git a/usb-control/haikou.py b/usb-control/haikou.py index e334530..ef9f401 100755 --- a/usb-control/haikou.py +++ b/usb-control/haikou.py @@ -1,194 +1,15 @@ #!/usr/bin/env python + """Controls power button and BIOS Disable of the Haikou Baseboard """ -__copyright__ = 'Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH' +__copyright__ = 'Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH' __license__ = 'MIT' -import argparse -import usb.core -import usb.util -import sys -import time +import cp210x_controller -VENDOR_ID = 0x10c4 -PRODUCT_ID = 0xea60 PRODUCT_STRING = "Haikou Baseboard" -REQTYPE_HOST_TO_DEVICE = 0x40 -REQTYPE_DEVICE_TO_HOST = 0xc0 - -CP210X_VENDOR_SPECIFIC = 0xFF - -CP210X_WRITE_LATCH = 0x37E1 -CP210X_READ_LATCH = 0x00C2 -CP210X_GET_MDMSTS = 0x8 - -# Power supply GPIO -GPIO_POWER = 0 -VALUE_POWER_RELEASE = 0 -VALUE_POWER_PRESS = 1 - -# BIOS disable GPIO -GPIO_BIOS = 1 -VALUE_BIOS_NORMAL = 0 -VALUE_BIOS_DISABLE = 1 - -# Power state -POWERSTATE_ON = 0 -POWERSTATE_OFF = 1 - -def set_gpio(dev, gpio, value): - # the latch register has 16 bit. the upper 8 bits are the gpio value, - # the lower 8 bit are the write mask. - val = (value << (8 + gpio)) | (1 << gpio); - dev.ctrl_transfer(bmRequestType = REQTYPE_HOST_TO_DEVICE, - bRequest = CP210X_VENDOR_SPECIFIC, - wValue = CP210X_WRITE_LATCH, - wIndex = val) - -def get_gpio(dev, gpio): - # Read 1 byte from latch register - data = dev.ctrl_transfer(bmRequestType = REQTYPE_DEVICE_TO_HOST, - bRequest = CP210X_VENDOR_SPECIFIC, - wValue = CP210X_READ_LATCH, - data_or_wLength = 1) - return not not (data[0] & (1 << gpio)) - -def toggle_power(dev): - # We emulate a power button press for 300 ms - set_gpio(dev, GPIO_POWER, VALUE_POWER_PRESS) - time.sleep(1) - set_gpio(dev, GPIO_POWER, VALUE_POWER_RELEASE) - -def get_powerstate(dev): - # Reading the latch would be useless, but we have CTS connected to 3V3 - # Get modem status - data = dev.ctrl_transfer(bmRequestType = REQTYPE_DEVICE_TO_HOST, - bRequest = CP210X_GET_MDMSTS, - wValue = 0, - wIndex = 0, - data_or_wLength = 1); - # Check CTS line - return ((data[0] >> 4) & 1) - -def get_bootmode(dev): - # We can only check if we pull the line low - return get_gpio(dev, GPIO_BIOS) - -def create_parser(): - parser = argparse.ArgumentParser(description= - 'Controls power and BIOS disable state of the Haikou baseboard') - - # Generic arguments (for identifying the USB device) - parser.add_argument('--ignore-product-string', '-i', - action='store_true', - dest='ignore_product_string', - help='ignore product string') - - parser.add_argument('--serial', '-s', - action='store', - dest='serialnumber', - type=str, - help='defines the serialnumber to use') - - # Arguments to set the bootmode - parser_bootmode_group = parser.add_mutually_exclusive_group() - parser_bootmode_group.add_argument('--normal-boot', '-n', - action='store_true', - dest='normal_boot', - help='activate Normal Boot') - parser_bootmode_group.add_argument('--bios-disable', '-b', - action='store_true', - dest='bios_disable', - help='activate BIOS Disable') - - # Commands - subparsers = parser.add_subparsers(help='command to perform', - dest='subcommand') - subparsers.add_parser('list', - help='lists serial numbers of attached Haikou Baseboards') - subparsers.add_parser('on', - help='turn on attached Haikou Baseboards') - subparsers.add_parser('off', - help='turn off attached Haikou Baseboards') - subparsers.add_parser('cycle', - help='power cycle attached Haikou Baseboards') - subparsers.add_parser('toggle', - help='emulate power button press on attached Haikou Baseboards') - subparsers.add_parser('status', - help='show status of attached Haikou Baseboards') - - return parser - -def find_board_list(serialnumber, ignore_product_string): - try: - kwargs = dict() - kwargs['idVendor'] = VENDOR_ID - kwargs['idProduct'] = PRODUCT_ID - if ignore_product_string != True: - kwargs['product'] = PRODUCT_STRING - if serialnumber: - kwargs['serial_number'] = args.serialnumber - kwargs['find_all'] = True - - # Find the devices matching the specified requirements - dev_it = usb.core.find(**kwargs) - - # Convert iterator to list - devs = list(dev_it) - - return devs - - except ValueError, e: - if 'langid' in e.message: - raise usb.core.USBError(e.message + "\n" + - "This may be a permission issue. See: \n"+ - "https://github.com/walac/pyusb/issues/139") - -def main(): - # Create the argument parser - parser = create_parser() - - # Apply the parser - args = parser.parse_args() - - # Collect list of potential devices - devs = find_board_list(args.serialnumber, args.ignore_product_string) - - if args.subcommand == 'list': - print "Found %d Baseboard%s:" % (len(dev),"s"[len(dev)==1:]) - for idx,cfg in enumerate(dev): - print "%d: %s" % (idx, cfg.serial_number) - sys.exit() - - - for dev in devs: - if args.bios_disable: - set_gpio(dev, GPIO_BIOS, VALUE_BIOS_DISABLE) - elif args.normal_boot: - set_gpio(dev, GPIO_BIOS, VALUE_BIOS_NORMAL) - - if args.subcommand == 'on': - if get_powerstate(dev) == POWERSTATE_OFF: - toggle_power(dev) - elif args.subcommand == 'off': - if get_powerstate(dev) == POWERSTATE_ON: - toggle_power(dev) - elif args.subcommand == 'cycle': - if get_powerstate(dev) == POWERSTATE_ON: - toggle_power(dev) - time.sleep(1) - toggle_power(dev) - elif args.subcommand == 'toggle': - toggle_power(dev) - elif args.subcommand == 'status': - powerstate = get_powerstate(dev) - bootmode = get_bootmode(dev) - print "Board is {} ({})".format( - ("ON" if powerstate == POWERSTATE_ON else "OFF"), - ("BIOS disabled" if bootmode == VALUE_BIOS_DISABLE else "Normal boot (if not overruled by on-board switch)")) - if __name__ == '__main__': - main() + cp210x_controller.cp210x_controller(PRODUCT_STRING) diff --git a/usb-control/telaviv.py b/usb-control/telaviv.py new file mode 100755 index 0000000..b7576bd --- /dev/null +++ b/usb-control/telaviv.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +"""Controls power button and BIOS Disable of the Haikou Baseboard +""" + +__copyright__ = 'Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH' +__license__ = 'MIT' + +import cp210x_controller + +PRODUCT_STRING = "Tel-Aviv" + +if __name__ == '__main__': + cp210x_controller.cp210x_controller(PRODUCT_STRING) + |