Repository navigation
serial: add an option to resynchronize with the controller on open - #996
Conversation
| await exchange(hci.HCI_Reset_Command(), bytes(RESYNC_PADDING_SIZE)) | ||
| # That completion can be for an earlier reset. Anything still pending arrives | ||
| # before the completion of the next command. | ||
| await exchange(hci.HCI_Read_Local_Supported_Commands_Command()) |
There was a problem hiding this comment.
It would be slightly more efficient to use the HCI_Read_Local_Version_Information command, which has a shorter response than HCI_Read_Local_Supported_Commands_Command.
There was a problem hiding this comment.
Done: the resync now sends HCI_Read_Local_Version_Information (serial.py:118).
| return | ||
| self._discarded += data | ||
| match = self._awaited.search(self._discarded) | ||
| if match and len(self._discarded) >= match.start() + 3 + match[1][0]: |
There was a problem hiding this comment.
If we use HCI_Read_Local_Version_Information_Command, the regex can take care of matching all the bytes (04, 0e, 03, XX, 01, 10 + 9 bytes).
There was a problem hiding this comment.
Done: the pattern now matches the whole event (serial.py:105), and the separate length check is gone. The length byte is 0x0c rather than 03, since Num_HCI_Command_Packets and the op code count toward it along with the 9 bytes of return parameters.
| self._discarded.clear() | ||
| self._answered.clear() | ||
| self._awaited = re.compile( | ||
| rb'\x04\x0e(.).' + command.op_code.to_bytes(2, 'little'), re.DOTALL |
There was a problem hiding this comment.
See comment above about including the length byte in the match
There was a problem hiding this comment.
Done: the HCI_Reset completion is matched with its length byte 0x04 (serial.py:115).
A process that stops part way through writing a command leaves the controller waiting for the rest of it. The controller then reads the next host's HCI_Reset as that payload, and power_on() waits forever for a response. Add a "resync" option to the serial transport moniker, off by default. On open it writes 258 zero bytes, enough to complete a pending command or SCO packet, then an HCI_Reset. Once a reset completes, it sends HCI_Read_Local_Version_Information and discards input until that command completes: the first reset completion can be for an earlier reset, and anything still pending arrives before the second command's. A command counts as complete once its whole Command Complete event, length byte and return parameters included, has been received. If the two commands get no reply within 2 s, the open fails. Not every controller accepts the padding, which is why it is an option. The padding goes out in 64-byte writes: through a J-Link OB virtual COM port, the same bytes sent as one write left the controller hung. Refs google#956. Signed-off-by: Arkadiusz Grzelka <devitwise@gmail.com>
eaac2dd to
75da3b4
Compare
Fixes #956.
This is the optional resync discussed in #956, as a
resyncflag on the serial moniker, off by default:Tested on an nRF7002 DK running Zephyr's hci_uart sample behind its J-Link OB virtual COM port. With the controller left waiting for the rest of a command, a plain
power_on()hung; withresyncit completed. A controller left with a partial HCI_Reset header (01 03 0c) also completed withresync.