|
|
|
|
|
|
|
|
|
|
|
#!/usr/bin/env python |
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
|
|
|
import argparse |
|
|
|
|
|
import logging |
|
|
|
|
|
|
|
|
|
|
|
from pylibftdi import BitBangDevice |
|
|
|
|
|
from pylibftdi._base import FtdiError |
|
|
|
|
|
from pylibftdi.device import Driver |
|
|
|
|
|
import six |
|
|
|
|
|
|
|
|
|
|
|
__author__ = "Nate Bohman" |
|
|
|
|
|
__credits__ = ["Nate Bohman"] |
|
|
|
|
|
__license__ = "LGPL" |
|
|
|
|
|
__maintainer__ = "Nate Bohman" |
|
|
|
|
|
__email__ = "natrinicle@gmail.com" |
|
|
|
|
|
__status__ = "Development" |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) # pylint: disable=invalid-name |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FAR_LED = {"ON": 0, "MID": 1, "OFF": 21} |
|
|
|
|
|
NEAR_LED = {"ON": 0, "MID": 2, "OFF": 42} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_led(serial_num=None, far_led=None, near_led=None): |
|
|
|
|
|
"""Set the LEDs on an FTDI BitBanged device. |
|
|
|
|
|
|
|
|
|
|
|
:param serial_num: (optional) Serial number of the FTDI |
|
|
|
|
|
device or None to use the first |
|
|
|
|
|
available device. |
|
|
|
|
|
:param far_led: (optional) Set the LED furthest from the USB |
|
|
|
|
|
connector to ON, MID, or OFF. |
|
|
|
|
|
:param near_led: (optional) Set the LED closest to the USB |
|
|
|
|
|
connector to ON, MID, or OFF. |
|
|
|
|
|
:type serial_num: :class:`str` or None |
|
|
|
|
|
:type far_led: :class:`str` |
|
|
|
|
|
:type near_led: :class:`str` |
|
|
|
|
|
""" |
|
|
|
|
|
if serial_num is not None: |
|
|
|
|
|
assert isinstance(serial_num, (six.string_types)) |
|
|
|
|
|
if far_led is not None: |
|
|
|
|
|
far_led = FAR_LED.get(far_led.upper()) |
|
|
|
|
|
assert isinstance(far_led, (int)) |
|
|
|
|
|
if near_led is not None: |
|
|
|
|
|
near_led = NEAR_LED.get(near_led.upper()) |
|
|
|
|
|
assert isinstance(near_led, (int)) |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
with BitBangDevice(serial_num) as bb: |
|
|
|
|
|
if far_led is None: |
|
|
|
|
|
# Binary bitwise and the current state against the |
|
|
|
|
|
# bits that are significant to the far_led. |
|
|
|
|
|
far_led = bb.read_pins() & 21 |
|
|
|
|
|
if near_led is None: |
|
|
|
|
|
# Binary bitwise and the current state against the |
|
|
|
|
|
# bits that are significant to the near_led. |
|
|
|
|
|
near_led = bb.read_pins() & 42 |
|
|
|
|
|
|
|
|
|
|
|
serial = Driver().list_devices()[bb.device_index][2].decode() |
|
|
|
|
|
|
|
|
|
|
|
log_msg = "Setting {} far led to {}, near_led to {}".format( |
|
|
|
|
|
serial, |
|
|
|
|
|
[key for key in FAR_LED if FAR_LED[key] == far_led][0], |
|
|
|
|
|
[key for key in NEAR_LED if NEAR_LED[key] == near_led][0], |
|
|
|
|
|
) |
|
|
|
|
|
logger.info(log_msg) |
|
|
|
|
|
bb.port = far_led | near_led |
|
|
|
|
|
except FtdiError as e: |
|
|
|
|
|
if "usb_open() failed" in str(e): |
|
|
|
|
|
err_msg = "".join( |
|
|
|
|
|
[ |
|
|
|
|
|
"Could not open any FTDI devices. Check permissions and ", |
|
|
|
|
|
"potentially add the following to udev rules " |
|
|
|
|
|
'\'SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ', |
|
|
|
|
|
'ATTRS{idProduct}=="6001", MODE="0666"\' ', |
|
|
|
|
|
"or ensure the LED dongle is attached to the system.", |
|
|
|
|
|
] |
|
|
|
|
|
) |
|
|
|
|
|
raise EnvironmentError((-4, err_msg)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure_logging(logger, verbosity): |
|
|
|
|
|
"""Take an int and configures logger levels accordingly where 0 = ERROR and 3 = DEBUG. |
|
|
|
|
|
|
|
|
|
|
|
:param logger: Logger object to configure. |
|
|
|
|
|
:param verbosity: Integer coresponding to logging level from 0 being ERROR and 3 being DEBUG. |
|
|
|
|
|
:type logger: :class:`logging.Logger` |
|
|
|
|
|
:type verbosity: :class:`int` |
|
|
|
|
|
""" |
|
|
|
|
|
assert isinstance(logger, (logging.Logger)) |
|
|
|
|
|
assert isinstance(verbosity, (int)) |
|
|
|
|
|
|
|
|
|
|
|
# The messages that display are controlled by the -v or -vv arguments in parse_arguments with |
|
|
|
|
|
# defaults being error or worse. A single v includes warning messages, a double v includes info |
|
|
|
|
|
# messages, and a triple v includes debug messages. Triple v also changes the log_format to |
|
|
|
|
|
# include the module, function name, and line number where logger was called from. |
|
|
|
|
|
# |
|
|
|
|
|
# Verbosity |
|
|
|
|
|
# parser.add_argument("-v", "--verbose", dest="verbose", action="count", default=0,) |
|
|
|
|
|
|
|
|
|
|
|
log_levels = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] |
|
|
|
|
|
log_level = log_levels[ |
|
|
|
|
|
min(len(log_levels) - 1, verbosity) |
|
|
|
|
|
] # capped to number of levels |
|
|
|
|
|
if log_level > logging.DEBUG: |
|
|
|
|
|
log_format = "%(asctime)s %(levelname)s %(message)s" |
|
|
|
|
|
else: |
|
|
|
|
|
log_format = ( |
|
|
|
|
|
"%(asctime)s %(levelname)s %(module)s %(funcName)s:%(lineno)s %(message)s" |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(format=log_format) |
|
|
|
|
|
logger.setLevel(level=log_level) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_args(): |
|
|
|
|
|
"""Parse Arguments for set_led.""" |
|
|
|
|
|
parser = argparse.ArgumentParser( |
|
|
|
|
|
description="Set PureStorage Front Panel LED module states." |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
# Base information (usernames, passwords, etc...) |
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
"-s", |
|
|
|
|
|
"--serial-num", |
|
|
|
|
|
dest="serial_num", |
|
|
|
|
|
action="store", |
|
|
|
|
|
required=False, |
|
|
|
|
|
help="Serial Number of LED module if more than one installed.", |
|
|
|
|
|
) |
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
"-f", |
|
|
|
|
|
"--far-led", |
|
|
|
|
|
dest="far_led", |
|
|
|
|
|
action="store", |
|
|
|
|
|
required=False, |
|
|
|
|
|
type=str, |
|
|
|
|
|
help="State to set the LED furthest from the USB connector (ON, MID, OFF).", |
|
|
|
|
|
) |
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
"-n", |
|
|
|
|
|
"--near-led", |
|
|
|
|
|
dest="near_led", |
|
|
|
|
|
action="store", |
|
|
|
|
|
required=False, |
|
|
|
|
|
type=str, |
|
|
|
|
|
help="State to set the LED closest to the USB connector (ON, MID, OFF).", |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
# Verbosity |
|
|
|
|
|
parser.add_argument("-v", "--verbose", dest="verbose", action="count", default=0) |
|
|
|
|
|
|
|
|
|
|
|
# Positional arguments |
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args() |
|
|
|
|
|
|
|
|
|
|
|
# Configure logging |
|
|
|
|
|
configure_logging(logger=logger, verbosity=args.verbose) |
|
|
|
|
|
|
|
|
|
|
|
return args |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
|
"""Main function that is called when script directly called.""" |
|
|
|
|
|
args = parse_args() |
|
|
|
|
|
set_led(serial_num=args.serial_num, far_led=args.far_led, near_led=args.near_led) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
main() |