Rewrite eepprog.py using the Click framework
This commit is contained in:
parent
f00e52cc4c
commit
cedb5bfe81
|
|
@ -1,137 +1,64 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import click
|
||||||
import getopt
|
|
||||||
import serial
|
|
||||||
|
|
||||||
# Global variables for program parameters
|
from helpers import CliContext, Logger, EepromProgrammer
|
||||||
verbose = False
|
|
||||||
serial_device = "/dev/ttyUSB0"
|
|
||||||
serial_baudrate = 9600
|
|
||||||
command = ""
|
|
||||||
|
|
||||||
# Valid commands
|
|
||||||
valid_commands = ("test")
|
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
@click.group()
|
||||||
"""Prints help text."""
|
@click.option('--device', '-d', default='/dev/ttyUSB0', show_default=True,
|
||||||
|
metavar='DEVICE', help="Set the serial device")
|
||||||
|
@click.option('--baud', '-b', default=38400, show_default=True,
|
||||||
|
metavar='BAUDRATE', help="Set the baud rate of the serial device")
|
||||||
|
@click.option('--verbose', '-v', is_flag=True, help='Print debug output')
|
||||||
|
@click.pass_context
|
||||||
|
def eepprog(ctx: click.Context, device: str, baud: int, verbose: bool):
|
||||||
|
# Create dependencies
|
||||||
|
logger = Logger(verbose=verbose)
|
||||||
|
eeprom_programmer = EepromProgrammer(logger=logger, device=device, baudrate=baud)
|
||||||
|
|
||||||
print(f"""
|
logger.debug("Creating CLI context (device: {}, bauds: {})".format(device, baud))
|
||||||
Usage: {sys.argv[0]} [OPTIONS] COMMAND [ARGS]
|
|
||||||
|
|
||||||
Commands:
|
# Create CLI context
|
||||||
test first test command...
|
ctx.obj = CliContext(
|
||||||
|
logger=logger,
|
||||||
|
eeprom_programmer=eeprom_programmer,
|
||||||
|
)
|
||||||
|
|
||||||
Options:
|
# Define clean up functions
|
||||||
-h, --help show this help message and exit
|
ctx.call_on_close(eeprom_programmer.close)
|
||||||
-v, --verbose be verbose
|
|
||||||
-d DEVICE, --device=DEVICE use DEVICE as serial device
|
|
||||||
(default: /dev/ttyUSB0)
|
|
||||||
"""[1:-1])
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
@eepprog.command('hello', short_help='Say hello. :)')
|
||||||
"""Parse command line arguments and set global variables."""
|
@click.pass_obj
|
||||||
|
def hello(context: CliContext):
|
||||||
|
"""
|
||||||
|
Say hello. :)
|
||||||
|
|
||||||
# Global variables for program options (yes, yes, I know...)
|
Just a test command that tests the logger.
|
||||||
global verbose, serial_device, serial_baudrate, command
|
"""
|
||||||
|
context.logger.debug('hello hello', 413, 'hellooo')
|
||||||
try:
|
context.logger.info('hello!')
|
||||||
# Try to parse argument strings
|
context.logger.info('the same', click.style('but in green!', fg='green'))
|
||||||
optlist, args = getopt.gnu_getopt(
|
context.logger.warn('this is fine')
|
||||||
sys.argv[1:],
|
context.logger.error('ohno')
|
||||||
"hvd:",
|
context.logger.error('error, but a friendly one :)', fg='green')
|
||||||
["help", "verbose", "device="]
|
context.logger.success('yay!')
|
||||||
)
|
|
||||||
except getopt.GetoptError as err:
|
|
||||||
# Invalid option, print help and exit
|
|
||||||
print(err, "\n")
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
# Parse all the options
|
|
||||||
for opt, val in optlist:
|
|
||||||
if opt == "-h" or opt == "--help":
|
|
||||||
# Print help
|
|
||||||
usage()
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
elif opt == "-v" or opt == "--verbose":
|
|
||||||
# Verbose
|
|
||||||
verbose = True
|
|
||||||
|
|
||||||
elif opt == "-d" or opt == "--device":
|
|
||||||
# Set device filename
|
|
||||||
serial_device = val
|
|
||||||
|
|
||||||
else:
|
|
||||||
assert False, "unhandled option"
|
|
||||||
|
|
||||||
# Parse command argument
|
|
||||||
if len(args) == 0:
|
|
||||||
print("missing command\n")
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
else:
|
|
||||||
# Get command and remove argument
|
|
||||||
command = args.pop(0)
|
|
||||||
|
|
||||||
# Check if command is valid
|
|
||||||
if command not in valid_commands:
|
|
||||||
print("invalid command '" + command + "'\n")
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
# Check if command has valid arguments
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
|
|
||||||
def setup_serial():
|
@eepprog.command('test', short_help="Send INIT command to the programmer and read answer")
|
||||||
"""Setup serial device."""
|
@click.pass_obj
|
||||||
|
def test(context: CliContext):
|
||||||
|
"""
|
||||||
|
Send an 'INIT' command to the programmer and read the answer.
|
||||||
|
|
||||||
if verbose:
|
Test command for debugging.
|
||||||
print(f"setting up serial device '{serial_device}' with baudrate "
|
"""
|
||||||
f"{serial_baudrate}")
|
context.eeprom_programmer.test()
|
||||||
|
|
||||||
# Setup serial device
|
# TODO command: list-devices -> serial.tools.list_ports
|
||||||
ser = serial.Serial(serial_device, serial_baudrate)
|
# TODO shell: Run an interactive shell
|
||||||
return ser
|
|
||||||
|
|
||||||
|
|
||||||
def command_test(ser):
|
if __name__ == '__main__':
|
||||||
"""Command 'test': Does some testing."""
|
eepprog()
|
||||||
|
|
||||||
if verbose:
|
|
||||||
print("running command 'test' ...")
|
|
||||||
|
|
||||||
# Write a test command
|
|
||||||
# TODO do a HELLO first
|
|
||||||
ser.write(b"TESTREAD\n")
|
|
||||||
|
|
||||||
# Just read some stuff
|
|
||||||
while True:
|
|
||||||
print("read: ", ser.readline(80))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main function. Does the thing."""
|
|
||||||
|
|
||||||
# Parse program arguments
|
|
||||||
parse_args()
|
|
||||||
|
|
||||||
# Setup serial device
|
|
||||||
ser = setup_serial()
|
|
||||||
|
|
||||||
# Run command
|
|
||||||
if command == "test":
|
|
||||||
command_test(ser)
|
|
||||||
else:
|
|
||||||
assert False, "unhandled command"
|
|
||||||
|
|
||||||
# Close serial device
|
|
||||||
ser.close()
|
|
||||||
|
|
||||||
|
|
||||||
# Run program
|
|
||||||
main()
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
from . import Logger, EepromProgrammer
|
||||||
|
|
||||||
|
|
||||||
|
class CliContext:
|
||||||
|
logger: Logger
|
||||||
|
eeprom_programmer: EepromProgrammer
|
||||||
|
|
||||||
|
def __init__(self, logger: Logger, eeprom_programmer: EepromProgrammer):
|
||||||
|
self.logger = logger
|
||||||
|
self.eeprom_programmer = eeprom_programmer
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
from serial import Serial
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from . import Logger
|
||||||
|
|
||||||
|
|
||||||
|
class EepromProgrammer:
|
||||||
|
# Dependencies
|
||||||
|
logger: Logger
|
||||||
|
serial: Optional[Serial]
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
_device_file: str
|
||||||
|
_baudrate: int
|
||||||
|
|
||||||
|
def __init__(self, logger: Logger, device: str, baudrate):
|
||||||
|
self.logger = logger
|
||||||
|
self.serial = None
|
||||||
|
|
||||||
|
self._device_file = device
|
||||||
|
self._baudrate = baudrate
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
def open(self):
|
||||||
|
"""
|
||||||
|
Open and setup serial port.
|
||||||
|
"""
|
||||||
|
assert self.serial is None, 'Serial port is already opened!'
|
||||||
|
|
||||||
|
self.logger.debug("Setting up serial device '{}' with baudrate {}".format(self._device_file, self._baudrate))
|
||||||
|
self.serial = Serial(self._device_file, self._baudrate)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.serial is None:
|
||||||
|
self.logger.debug("Serial port is already closed")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.logger.debug("Closing serial port")
|
||||||
|
self.serial.close()
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
def test(self):
|
||||||
|
# Open serial port
|
||||||
|
if self.serial is None:
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
# Write a test command
|
||||||
|
self.logger.info("Sending 'INIT' ...")
|
||||||
|
self.serial.write(b"INIT\n")
|
||||||
|
|
||||||
|
# Just read some stuff
|
||||||
|
self.logger.info("Read line: ", self.serial.readline(80))
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
from typing import Any
|
||||||
|
import click
|
||||||
|
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
verbose: bool
|
||||||
|
|
||||||
|
def __init__(self, verbose: bool = False):
|
||||||
|
self.verbose = verbose
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _log(prefix: str = 'LOG', message: Any = '', nl: bool = True, **kwargs) -> None:
|
||||||
|
text = '{}: {}'.format(prefix, message) if message else ''
|
||||||
|
click.secho(text, nl=nl, **kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _join(*args, delimiter: str = ' ') -> str:
|
||||||
|
return delimiter.join([str(arg) for arg in args])
|
||||||
|
|
||||||
|
def debug(self, *args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Write a message to stdout only if the '--verbose' option is set (in gray).
|
||||||
|
"""
|
||||||
|
if self.verbose:
|
||||||
|
kwargs.setdefault('fg', 'bright_black')
|
||||||
|
self._log('DEBUG', self._join(*args), **kwargs)
|
||||||
|
|
||||||
|
def info(self, *args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Write a message to stdout (in white).
|
||||||
|
"""
|
||||||
|
kwargs.setdefault('fg', 'white')
|
||||||
|
self._log('INFO', self._join(*args), **kwargs)
|
||||||
|
|
||||||
|
def warn(self, *args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Write a warning message to stderr (in yellow).
|
||||||
|
"""
|
||||||
|
kwargs.setdefault('fg', 'yellow')
|
||||||
|
self._log('WARNING', self._join(*args), **kwargs)
|
||||||
|
|
||||||
|
def error(self, *args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Write an error message to stderr (in red).
|
||||||
|
"""
|
||||||
|
kwargs.setdefault('fg', 'red')
|
||||||
|
self._log('ERROR', self._join(*args), err=True, **kwargs)
|
||||||
|
|
||||||
|
def success(self, *args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Write a success message stdout (in green).
|
||||||
|
"""
|
||||||
|
kwargs.setdefault('fg', 'green')
|
||||||
|
self._log('SUCCESS', self._join(*args), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
logger = Logger()
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from .CliContext import CliContext
|
||||||
|
from .Logger import Logger
|
||||||
|
from .EepromProgrammer import EepromProgrammer
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
click~=7.0
|
||||||
|
pyserial~=3.4
|
||||||
Loading…
Reference in New Issue