summaryrefslogtreecommitdiff
path: root/kvmd/plugins
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2020-06-05 05:25:27 +0300
committerDevaev Maxim <[email protected]>2020-06-05 05:25:27 +0300
commitb9e53a00f82a1ebac32848c832d7af2ae0a45c03 (patch)
treec27b54b70744dc06617aac7cff282051d8215d64 /kvmd/plugins
parent9e60f24c54e50b6d39ec28db53310748ce87df6f (diff)
suppressed serial hid spam
Diffstat (limited to 'kvmd/plugins')
-rw-r--r--kvmd/plugins/hid/serial.py154
1 files changed, 94 insertions, 60 deletions
diff --git a/kvmd/plugins/hid/serial.py b/kvmd/plugins/hid/serial.py
index 6a6c83ac..c9705543 100644
--- a/kvmd/plugins/hid/serial.py
+++ b/kvmd/plugins/hid/serial.py
@@ -30,6 +30,7 @@ import struct
import errno
import time
+from typing import List
from typing import Dict
from typing import AsyncGenerator
@@ -47,6 +48,7 @@ from ... import gpio
from ...yamlconf import Option
from ...validators.basic import valid_bool
+from ...validators.basic import valid_int_f0
from ...validators.basic import valid_int_f1
from ...validators.basic import valid_float_f01
@@ -59,6 +61,22 @@ from . import BaseHid
# =====
+class _RequestError(Exception):
+ def __init__(self, msg: str, online: bool=False) -> None:
+ super().__init__(msg)
+ self.msg = msg
+ self.online = online
+
+
+class _FatalRequestError(_RequestError):
+ pass
+
+
+class _TempRequestError(_RequestError):
+ pass
+
+
+# =====
class _BaseEvent:
def make_command(self) -> bytes:
raise NotImplementedError
@@ -141,6 +159,7 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
read_retries: int,
common_retries: int,
retries_delay: float,
+ errors_threshold: int,
noop: bool,
) -> None:
@@ -155,6 +174,7 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
self.__read_retries = read_retries
self.__common_retries = common_retries
self.__retries_delay = retries_delay
+ self.__errors_threshold = errors_threshold
self.__noop = noop
self.__reset_wip = False
@@ -177,13 +197,14 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
"reset_pin": Option(-1, type=valid_gpio_pin),
"reset_delay": Option(0.1, type=valid_float_f01),
- "device": Option("", type=valid_abs_path, unpack_as="device_path"),
- "speed": Option(115200, type=valid_tty_speed),
- "read_timeout": Option(2.0, type=valid_float_f01),
- "read_retries": Option(10, type=valid_int_f1),
- "common_retries": Option(100, type=valid_int_f1),
- "retries_delay": Option(0.1, type=valid_float_f01),
- "noop": Option(False, type=valid_bool),
+ "device": Option("", type=valid_abs_path, unpack_as="device_path"),
+ "speed": Option(115200, type=valid_tty_speed),
+ "read_timeout": Option(2.0, type=valid_float_f01),
+ "read_retries": Option(10, type=valid_int_f1),
+ "common_retries": Option(100, type=valid_int_f1),
+ "retries_delay": Option(0.1, type=valid_float_f01),
+ "errors_threshold": Option(5, type=valid_int_f0),
+ "noop": Option(False, type=valid_bool),
}
def start(self) -> None:
@@ -311,68 +332,81 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
def __process_request(self, tty: serial.Serial, request: bytes) -> None: # pylint: disable=too-many-branches
logger = get_logger()
+ errors: List[str] = []
+ runtime_errors = False
- common_error_occured = False
common_retries = self.__common_retries
read_retries = self.__read_retries
while common_retries and read_retries:
- if not self.__noop:
- if tty.in_waiting:
- tty.read(tty.in_waiting)
- assert tty.write(request) == len(request)
- response = tty.read(4)
- else:
- response = b"\x33\x20" # Magic + OK
- response += struct.pack(">H", self.__make_crc16(response))
-
- if len(response) < 4:
- logger.error("No response from HID: request=%r", request)
- read_retries -= 1
- else:
+ response = self.__send_request(tty, request)
+ try:
+ if len(response) < 4:
+ read_retries -= 1
+ raise _TempRequestError(f"No response from HID: request={request!r}")
+
assert len(response) == 4, response
if self.__make_crc16(response[-4:-2]) != struct.unpack(">H", response[-2:])[0]:
- logger.error("Invalid response CRC; requesting response again ...")
request = self.__make_request(b"\x02\x00\x00\x00\x00") # Repeat an answer
+ raise _TempRequestError("Invalid response CRC; requesting response again ...")
+
+ code = response[1]
+ if code == 0x48: # Request timeout # pylint: disable=no-else-raise
+ raise _TempRequestError(f"Got request timeout from HID: request={request!r}")
+ elif code == 0x40: # CRC Error
+ raise _TempRequestError(f"Got CRC error of request from HID: request={request!r}")
+ elif code == 0x45: # Unknown command
+ raise _FatalRequestError(f"HID did not recognize the request={request!r}", online=True)
+ elif code == 0x24: # Rebooted?
+ raise _FatalRequestError("No previous command state inside HID, seems it was rebooted", online=True)
+ elif code == 0x20: # Done
+ self.__state_flags.update(online=True)
+ return
+ elif code & 0x80: # Pong with leds
+ self.__state_flags.update(
+ online=True,
+ caps=bool(code & 0b00000001),
+ scroll=bool(code & 0x00000010),
+ num=bool(code & 0x00000100),
+ )
+ return
+ else:
+ raise _TempRequestError(f"Invalid response from HID: request={request!r}; code=0x{code:02X}")
+
+ except _RequestError as err:
+ common_retries -= 1
+ self.__state_flags.update(online=err.online)
+
+ if runtime_errors:
+ logger.error(err.msg)
else:
- code = response[1]
- if code == 0x48: # Request timeout
- logger.error("Got request timeout from HID: request=%r", request)
- elif code == 0x40: # CRC Error
- logger.error("Got CRC error of request from HID: request=%r", request)
- elif code == 0x45: # Unknown command
- logger.error("HID did not recognize the request=%r", request)
- self.__state_flags.update(online=True)
- return
- elif code == 0x24: # Rebooted?
- logger.error("No previous command state inside HID, seems it was rebooted")
- self.__state_flags.update(online=True)
- return
- elif code == 0x20: # Done
- if common_error_occured:
- logger.info("Success!")
- self.__state_flags.update(online=True)
- return
- elif code & 0x80: # Pong with leds
- self.__state_flags.update(
- online=True,
- caps=bool(code & 0b00000001),
- scroll=bool(code & 0x00000010),
- num=bool(code & 0x00000100),
- )
- return
- else:
- logger.error("Invalid response from HID: request=%r; code=0x%x", request, code)
-
- common_error_occured = True
- common_retries -= 1
- self.__state_flags.update(online=False)
-
- if common_retries and read_retries:
- logger.error("Retries left: common_retries=%d; read_retries=%d", common_retries, read_retries)
- time.sleep(self.__retries_delay)
-
- logger.error("Can't process HID request due many errors: %r", request)
+ errors.append(err.msg)
+ if len(errors) > self.__errors_threshold:
+ for msg in errors:
+ logger.error(msg)
+ errors = []
+ runtime_errors = True
+
+ if isinstance(err, _FatalRequestError):
+ break
+ if common_retries and read_retries:
+ time.sleep(self.__retries_delay)
+
+ for msg in errors:
+ logger.error(msg)
+ if not (common_retries and read_retries):
+ logger.error("Can't process HID request due many errors: %r", request)
+
+ def __send_request(self, tty: serial.Serial, request: bytes) -> bytes:
+ if not self.__noop:
+ if tty.in_waiting:
+ tty.read(tty.in_waiting)
+ assert tty.write(request) == len(request)
+ response = tty.read(4)
+ else:
+ response = b"\x33\x20" # Magic + OK
+ response += struct.pack(">H", self.__make_crc16(response))
+ return response
def __make_request(self, command: bytes) -> bytes:
request = b"\x33" + command