From 1ad7f7b75eb4cc1f0e37f18768f532642eecb427 Mon Sep 17 00:00:00 2001 From: Jevgeni Kiski Date: Fri, 17 Apr 2020 23:13:51 +0300 Subject: [PATCH] Better command lock. Connect does not use lock. --- nextion/client.py | 103 ++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/nextion/client.py b/nextion/client.py index fa9389a..f3f0106 100644 --- a/nextion/client.py +++ b/nextion/client.py @@ -147,10 +147,10 @@ async def connect(self) -> None: logger.debug("Flash size: %s", data[6]) try: - await self.command("bkcmd=3", attempts=1) + await self._command("bkcmd=3", attempts=1) except CommandTimeout as e: pass # it is fine - self._sleeping = await self.get("sleep") + self._sleeping = await self._command("get sleep") logger.info("Successfully connected to the device") except ConnectionFailed: @@ -187,8 +187,9 @@ async def set(self, key, value, timeout=IO_TIMEOUT): else: return await self.command("%s=%s" % (key, out_value), timeout=timeout) - async def command(self, command, timeout=IO_TIMEOUT, attempts=None): + async def _command(self, command, timeout=IO_TIMEOUT, attempts=None): assert attempts is None or attempts > 0 + attempts_remained = attempts or self._reconnect_attempts last_exception = None while attempts_remained > 0: @@ -201,62 +202,66 @@ async def command(self, command, timeout=IO_TIMEOUT, attempts=None): logger.error("Reconnect failed") await asyncio.sleep(1) continue - async with self._command_lock: - try: - while True: - logger.debug( - "Dropping dangling: %s", self._connection.read_no_wait() - ) - except asyncio.QueueEmpty: - pass - last_exception = None - self._connection.write(command) + try: + while True: + logger.debug( + "Dropping dangling: %s", self._connection.read_no_wait() + ) + except asyncio.QueueEmpty: + pass - result = None - data = None - finished = False + last_exception = None + self._connection.write(command) - while not finished: - try: - response = await self._read(timeout=timeout) - except asyncio.TimeoutError as e: - logger.error('Command "%s" timeout.', command) - last_exception = CommandTimeout( - 'Command "%s" response was not received' % command - ) - await asyncio.sleep(IO_TIMEOUT) - break + result = None + data = None + finished = False - res_len = len(response) - if res_len == 0: + while not finished: + try: + response = await self._read(timeout=timeout) + except asyncio.TimeoutError as e: + logger.error('Command "%s" timeout.', command) + last_exception = CommandTimeout( + 'Command "%s" response was not received' % command + ) + await asyncio.sleep(IO_TIMEOUT) + break + + res_len = len(response) + if res_len == 0: + finished = True + elif res_len == 1: # is response code + response_code = response[0] + if response_code == 0x01: # success + result = True finished = True - elif res_len == 1: # is response code - response_code = response[0] - if response_code == 0x01: # success - result = True - finished = True - else: - raise CommandFailed(command, response_code) else: - type_ = response[0] - raw = response[1:] - if type_ == ResponseType.PAGE: # Page ID - data = raw[1] - elif type_ == ResponseType.STRING: # string - data = raw.decode() - elif type_ == ResponseType.NUMBER: # number - data = struct.unpack("i", raw)[0] - else: - logger.error( - "Unknown data received: %s" % binascii.hexlify(response) - ) - else: # this will run if loop ended successfully - return data if data is not None else result + raise CommandFailed(command, response_code) + else: + type_ = response[0] + raw = response[1:] + if type_ == ResponseType.PAGE: # Page ID + data = raw[1] + elif type_ == ResponseType.STRING: # string + data = raw.decode() + elif type_ == ResponseType.NUMBER: # number + data = struct.unpack("i", raw)[0] + else: + logger.error( + "Unknown data received: %s" % binascii.hexlify(response) + ) + else: # this will run if loop ended successfully + return data if data is not None else result if last_exception: raise last_exception + async def command(self, command, timeout=IO_TIMEOUT, attempts=None): + async with self._command_lock: + return await self._command(command, timeout=timeout, attempts=attempts) + async def sleep(self): if self._sleeping: return