From 63778b7d9dc627ce35ceca3e9145bdcf984c3c2a Mon Sep 17 00:00:00 2001 From: Hayden Roche Date: Fri, 1 Sep 2023 08:39:16 -0700 Subject: [PATCH] Align serial and I2C reset with note-c. The "source of truth" for how to properly reset comms with the Notecard is in note-c. This commit adjusts the `OpenI2C` and `OpenSerial` `Reset` methods so that they implement the same logic as their note-c counterparts. --- notecard/notecard.py | 69 ++++++++++++++++++++++++++++++++++--------- test/test_notecard.py | 18 ++++++----- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/notecard/notecard.py b/notecard/notecard.py index 2c6fff0..d36f2b6 100644 --- a/notecard/notecard.py +++ b/notecard/notecard.py @@ -255,25 +255,49 @@ def _read_byte_circuitpython(self): @serial_lock def Reset(self): """Reset the Notecard.""" + notecard_ready = False for i in range(10): try: + # Send a newline to the Notecard to terminate any partial + # request that might be sitting in its input buffer. self.uart.write(b'\n') except: + # Wait 500 ms and before trying to send the newline again. + time.sleep(.5) continue - time.sleep(0.5) - somethingFound = False - nonControlCharFound = False - while True: + + something_found = False + non_control_char_found = False + # Drain serial for 500 ms. + start = start_timeout() + while not has_timed_out(start, 0.5): data = self._read_byte() - if (data is None) or (data == b''): - break - somethingFound = True - if data[0] >= 0x20: - nonControlCharFound = True - if somethingFound and not nonControlCharFound: + # If data was read from the Notecard, inspect what we received. + # If it isn't a \n or \r, the host and the Notecard aren't + # synced up yet, and we'll need to retransmit the \n and try + # again. + while data is not None and data != b'': + something_found = True + if data[0] != ord('\n') and data[0] != ord('\r'): + non_control_char_found = True + + data = self._read_byte() + + # If there was no data read from the Notecard, wait 1 ms and try + # again. Keep doing this for 500 ms. + time.sleep(.001) + + # If we received anything other than newlines from the Notecard, we + # aren't in sync, yet. + if something_found and not non_control_char_found: + notecard_ready = True break - else: - raise Exception('Notecard not responding') + + # Wait 500 ms before trying again. + time.sleep(.5) + + if not notecard_ready: + raise Exception('Failed to reset Notecard.') def __init__(self, uart_id, debug=False): """Initialize the Notecard before a reset.""" @@ -408,8 +432,25 @@ def _transact(self, req, rsp_expected): @i2c_lock def Reset(self): """Reset the Notecard.""" - # Read from the Notecard until there's nothing left to read. - self._receive(0, .001, False) + # Send a newline to the Notecard to terminate any partial request that + # might be sitting in its input buffer. + self._transmit(b'\n') + + time.sleep(CARD_REQUEST_SEGMENT_DELAY_MS / 1000) + + # Read from the Notecard until there's nothing left, retrying a max of 3 + # times. + retries = 3 + while retries > 0: + try: + self._receive(0, .001, False) + except: + retries -= 1 + else: + break + + if retries == 0: + raise Exception('Failed to reset Notecard.') def _linux_write(self, length, data): msgs = [I2C.Message(length + data)] diff --git a/test/test_notecard.py b/test/test_notecard.py index 9c209bf..1a31ad7 100644 --- a/test/test_notecard.py +++ b/test/test_notecard.py @@ -18,7 +18,9 @@ def get_serial_and_port(): port.read.side_effect = [b'\r', b'\n', None] port.readline.return_value = "\r\n" - nCard = notecard.OpenSerial(port) + # Patch the Reset method so that we don't actually call it during __init__. + with patch('notecard.notecard.OpenSerial.Reset'): + nCard = notecard.OpenSerial(port) return (nCard, port) @@ -28,7 +30,9 @@ def get_i2c_and_port(): port = periphery.I2C("dev/i2c-foo") port.try_lock.return_value = True - nCard = notecard.OpenI2C(port, 0x17, 255) + # Patch the Reset method so that we don't actually call it during __init__. + with patch('notecard.notecard.OpenI2C.Reset'): + nCard = notecard.OpenI2C(port, 0x17, 255) return (nCard, port) @@ -395,11 +399,11 @@ def test_open_serial(self): assert nCard.uart is not None def test_debug_mode_on_serial(self): - serial = Mock() # noqa: F811 - port = serial.Serial("/dev/tty.foo", 9600) - port.read.side_effect = [b'\r', b'\n', None] - - nCard = notecard.OpenSerial(port, debug=True) + # Patch the Reset method so that we don't actually call it during + # __init__. + with patch('notecard.notecard.OpenSerial.Reset'): + port = MagicMock() + nCard = notecard.OpenSerial(port, debug=True) assert nCard._debug