#!/usr/bin/python3
import argparse

import serial

_COMMAND_DELIMITERS = {
    "none": b'',
    "unix": b'\n',
    "dos": b'\r\n',
    "mac": b'\r',
}

parser = argparse.ArgumentParser(
    description="Write and read data from a serial port",
)
parser.add_argument("--device", "-d",
    required=True,
    help="path to the serial-port device",
)
parser.add_argument("--bytesize",
    type=int, choices=(serial.FIVEBITS, serial.SIXBITS, serial.SEVENBITS, serial.EIGHTBITS),
    default=serial.EIGHTBITS,
    help="bit-width for serial communication; default: {}".format(serial.EIGHTBITS),
)
parser.add_argument("--parity",
    type=str, choices=(serial.PARITY_NONE, serial.PARITY_EVEN, serial.PARITY_ODD, serial.PARITY_MARK, serial.PARITY_SPACE),
    default=serial.PARITY_NONE,
    help="parity-method for serial communication; default: {}".format(serial.PARITY_NONE),
)
parser.add_argument("--stopbits",
    type=float, choices=(serial.STOPBITS_ONE, serial.STOPBITS_ONE_POINT_FIVE, serial.STOPBITS_TWO),
    default=serial.STOPBITS_ONE,
    help="stop-bit separation for serial communication; default: {}".format(serial.STOPBITS_ONE),
)
parser.add_argument("--timeout", "-t",
    type=float,
    default=5.0,
    help="number of seconds for which to wait for a response; default: 5.0",
)
parser.add_argument("--baudrate", "-b",
    type=int,
    default=9600,
    help="baudrate used for communication with the serial device; default: 9600",
)
parser.add_argument("--read-buffer",
    type=int,
    default=4096,
    help="number of bytes to try to read at a time; default: 4096",
)
parser.add_argument("--continuous-read",
    action="store_true",
    help="continuously reads data until a timeout occurs or the process is interrupted",
)
parser.add_argument("--command-prefix",
    type=str, choices=tuple(_COMMAND_DELIMITERS),
    default="none",
    help="the byte-sequence to prepend to the given command; default: none",
)
parser.add_argument("--command-suffix",
    type=str, choices=tuple(_COMMAND_DELIMITERS),
    default="dos",
    help="the byte-sequence to append to the given command; default: dos (\\r\\n)",
)
parser.add_argument('command', metavar='COMMAND', nargs='*',
    type=str,
    help="the optional command to pass to the serial-port before reading results (if multiple tokens are given, they are concatenated with spaces)",
)
args = parser.parse_args()

with serial.Serial(args.device,
    baudrate=args.baudrate,
    bytesize=args.bytesize,
    parity=args.parity,
    stopbits=args.stopbits,
    timeout=args.timeout,
    write_timeout=args.timeout,
) as device:
    device.reset_input_buffer()
    device.reset_output_buffer()
    
    if args.command:
        device.write(_COMMAND_DELIMITERS[args.command_prefix] + ' '.join(args.command).encode('utf-8') + _COMMAND_DELIMITERS[args.command_suffix])
        
    if args.continuous_read:
        while True:
            data = device.read(args.read_buffer)
            if not data:
                break
            print(data.decode('utf-8'))
    else:
        data = device.read(args.read_buffer)
        if data:
            print(data.decode('utf-8'))
