From e222ffd3a2922800a041cb20c319381d8010fc7d Mon Sep 17 00:00:00 2001 From: Jonathan Perret Date: Sat, 7 Dec 2024 22:15:55 +0100 Subject: [PATCH] Send dummy request before closing serial port This avoids losing the last sent data with some USB/serial drivers. --- .../python/main/ayab/engine/engine_fsm.py | 26 +++++++++++++++++-- src/main/python/main/ayab/engine/output.py | 4 +++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/python/main/ayab/engine/engine_fsm.py b/src/main/python/main/ayab/engine/engine_fsm.py index da76db89..0f41814d 100644 --- a/src/main/python/main/ayab/engine/engine_fsm.py +++ b/src/main/python/main/ayab/engine/engine_fsm.py @@ -51,6 +51,7 @@ class State(Enum): REQUEST_TEST = auto() CONFIRM_TEST = auto() RUN_TEST = auto() + DISCONNECT = auto() FINISHED = auto() @@ -196,8 +197,18 @@ def _API6_run_knit(control: Control, operation: Operation) -> Output: if token == Token.reqLine: pattern_finished = control.cnf_line_API6(param) if pattern_finished: - control.state = State.FINISHED - return Output.KNITTING_FINISHED + # When closing the serial port, the final bytes written + # may be dropped by the driver + # (see https://github.com/serialport/serialport-rs/issues/117). + # This may cause the final `cnfLine` response to get lost and the + # firmware to get stuck knitting the previous row + # (see https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/662). + # To avoid this, before closing the port, we send a `reqInfo` message + # to the firmware and wait for the response. + control.com.req_info() + control.state = State.DISCONNECT + control.logger.debug("State DISCONNECT") + return Output.DISCONNECTING_FROM_MACHINE else: return Output.NEXT_LINE # else @@ -237,6 +248,17 @@ def _API6_run_test(control: Control, operation: Operation) -> Output: control.check_serial_API6() return Output.NONE + @staticmethod + def _API6_disconnect(control: Control, operation: Operation) -> Output: + token, param = control.check_serial_API6() + if token == Token.cnfInfo: + # We received a response to our final `reqInfo` request, + # it is now safe to close the port. + control.state = State.FINISHED + return Output.KNITTING_FINISHED + # else + return Output.NONE + @staticmethod def _API6_finished(control: Control, operation: Operation) -> Output: control.logger.debug("State FINISHED") diff --git a/src/main/python/main/ayab/engine/output.py b/src/main/python/main/ayab/engine/output.py index 972516de..437c9596 100644 --- a/src/main/python/main/ayab/engine/output.py +++ b/src/main/python/main/ayab/engine/output.py @@ -33,6 +33,7 @@ class Output(Enum): ERROR_INVALID_SETTINGS = auto() ERROR_SERIAL_PORT = auto() CONNECTING_TO_MACHINE = auto() + DISCONNECTING_FROM_MACHINE = auto() INITIALIZING_FIRMWARE = auto() WAIT_FOR_INIT = auto() ERROR_WRONG_API = auto() @@ -65,6 +66,9 @@ def _none(self) -> None: def _connecting_to_machine(self) -> None: self.emit_notification("Connecting to machine...", False) + def _disconnecting_from_machine(self) -> None: + self.emit_notification("Disconnecting from machine...") + def _initializing_firmware(self) -> None: self.emit_notification("Initializing firmware")