handle errors and retry logic better

This commit is contained in:
xenia 2021-05-12 16:32:02 -04:00
parent 9d9a625b08
commit ee8ec92c67
1 changed files with 65 additions and 9 deletions

View File

@ -1,9 +1,11 @@
import argparse import argparse
import asyncio import asyncio
import contextlib import contextlib
import errno
import re import re
import sys import sys
import termios import termios
import traceback
import tty import tty
from types import TracebackType from types import TracebackType
from typing import Any, List, Optional, Tuple, Type from typing import Any, List, Optional, Tuple, Type
@ -76,9 +78,33 @@ async def megacom(tty: str, baud: int, mode: str) -> None:
bytesize = MODE_LOOKUP["bytesize"][m.group(1)] bytesize = MODE_LOOKUP["bytesize"][m.group(1)]
parity = MODE_LOOKUP["parity"][m.group(2)] parity = MODE_LOOKUP["parity"][m.group(2)]
stopbits = MODE_LOOKUP["stopbits"][m.group(3)] stopbits = MODE_LOOKUP["stopbits"][m.group(3)]
printed_fnf = False
while True:
try:
(serialin, serialout) = await serial_asyncio.open_serial_connection( (serialin, serialout) = await serial_asyncio.open_serial_connection(
loop=asyncio.get_event_loop(), url=tty, baudrate=baud, bytesize=bytesize, parity=parity, loop=asyncio.get_event_loop(), url=tty, baudrate=baud, bytesize=bytesize,
stopbits=stopbits) parity=parity, stopbits=stopbits)
break
except serial.SerialException as e:
if e.errno == errno.ENOENT:
# the device could not be plugged in yet.. just wait
if not printed_fnf:
printed_fnf = True
stdout.write(f"waiting for {tty} to become available...\r\n".encode())
await stdout.drain()
else:
# permanent failure
stdout.write(f"failed to open port because: {e}\r\n".encode())
await stdout.drain()
return
except Exception as e:
# permanant failure
stdout.write(f"failed to open port because: {e}\r\n".encode())
await stdout.drain()
return
await asyncio.sleep(2)
stdout.write(f"megacom connected to {tty}:{baud}:{mode}\r\n".encode()) stdout.write(f"megacom connected to {tty}:{baud}:{mode}\r\n".encode())
await stdout.drain() await stdout.drain()
@ -113,21 +139,51 @@ async def megacom(tty: str, baud: int, mode: str) -> None:
stdin_to_serial = asyncio.create_task(connect_pipe(stdin, serialout, True)) stdin_to_serial = asyncio.create_task(connect_pipe(stdin, serialout, True))
serial_to_stdout = asyncio.create_task(connect_pipe(serialin, stdout)) serial_to_stdout = asyncio.create_task(connect_pipe(serialin, stdout))
await exit_flag.wait() time_to_exit = asyncio.create_task(exit_flag.wait())
do_retry = False
def handle_done(task):
nonlocal do_retry
if task.done():
exc = task.exception()
if exc is not None:
stdout.write(f"\r\n\r\nmegacom encountered error: {exc}\r\n".encode())
if isinstance(exc, serial.SerialException):
do_retry = True
else:
task.result()
return task.done()
await asyncio.wait([time_to_exit, stdin_to_serial, serial_to_stdout], return_when=asyncio.FIRST_COMPLETED)
if handle_done(time_to_exit):
pass
elif handle_done(stdin_to_serial):
pass
elif handle_done(serial_to_stdout):
pass
stdin_to_serial.cancel() stdin_to_serial.cancel()
serial_to_stdout.cancel() serial_to_stdout.cancel()
with contextlib.suppress(asyncio.CancelledError): with contextlib.suppress(asyncio.CancelledError):
with contextlib.suppress(serial.SerialException):
await stdin_to_serial await stdin_to_serial
with contextlib.suppress(asyncio.CancelledError): with contextlib.suppress(asyncio.CancelledError):
with contextlib.suppress(serial.SerialException):
await serial_to_stdout await serial_to_stdout
if not do_retry:
stdout.write(b"\r\n\r\nmegacom is exiting\r\n") stdout.write(b"\r\n\r\nmegacom is exiting\r\n")
with contextlib.suppress(serial.SerialException):
await serialout.drain() await serialout.drain()
with contextlib.suppress(serial.SerialException):
serialout.close() serialout.close()
await stdout.drain() await stdout.drain()
if do_retry:
return await megacom(tty, baud, mode)
def main() -> None: def main() -> None:
parser = argparse.ArgumentParser(prog="megacom", parser = argparse.ArgumentParser(prog="megacom",