Open serial connection (async). Args: boot_wait: Maximum time to wait for device boot (seconds). When ``boot_signals`` is non-empty, this is the *deadline* for the spin-poll — the helper returns as soon as any signal appears, other
(
self,
boot_wait: float = 3.0,
drain_boot: bool = True,
boot_signals: "list[str] | tuple[str, ...] | None" = None,
)
| 169 | return self._serial is not None and self._connected |
| 170 | |
| 171 | async def connect( |
| 172 | self, |
| 173 | boot_wait: float = 3.0, |
| 174 | drain_boot: bool = True, |
| 175 | boot_signals: "list[str] | tuple[str, ...] | None" = None, |
| 176 | ) -> None: |
| 177 | """Open serial connection (async). |
| 178 | |
| 179 | Args: |
| 180 | boot_wait: Maximum time to wait for device boot (seconds). When |
| 181 | ``boot_signals`` is non-empty, this is the *deadline* for the |
| 182 | spin-poll — the helper returns as soon as any signal appears, |
| 183 | otherwise it falls back to waiting the full duration (matching |
| 184 | the legacy fixed-sleep behavior so slow devices still work). |
| 185 | drain_boot: Whether to drain boot output after connecting. Lines |
| 186 | consumed while spinning for ``boot_signals`` count toward the |
| 187 | drain, so this second pass only catches leftovers. |
| 188 | boot_signals: Substrings to look for in serial output during the |
| 189 | boot wait. When a match is found, ``connect()`` returns |
| 190 | immediately instead of sleeping the full ``boot_wait``. Pass |
| 191 | an empty list to opt out of spin-polling (legacy sleep path). |
| 192 | Defaults to ``BOOT_SIGNALS_ANY`` which covers both ROM-loader |
| 193 | and Arduino ``setup()`` banners. |
| 194 | """ |
| 195 | if self._connected: |
| 196 | return |
| 197 | |
| 198 | # Create serial interface if not provided externally (defaults to fbuild) |
| 199 | if self._serial is None: |
| 200 | from ci.util.serial_interface import create_serial_interface |
| 201 | |
| 202 | self._serial = create_serial_interface( |
| 203 | port=self.port, |
| 204 | baud_rate=self.baudrate, |
| 205 | ) |
| 206 | self._owns_serial = True |
| 207 | |
| 208 | backend_name = type(self._serial).__name__ |
| 209 | if self.verbose: |
| 210 | print(f"🔌 [RPC] Connecting to {self.port} @ {self.baudrate} baud...") |
| 211 | print(f"🔌 [RPC] Using {backend_name} backend") |
| 212 | |
| 213 | await self._serial.connect() |
| 214 | self._connected = True |
| 215 | |
| 216 | if self.verbose: |
| 217 | print(f"✅ [RPC] Serial connection established") |
| 218 | |
| 219 | # Resolve default boot signals lazily so tests that don't touch |
| 220 | # serial I/O don't import the util module. |
| 221 | effective_signals: tuple[str, ...] | list[str] |
| 222 | if boot_signals is None: |
| 223 | from ci.util.boot_wait import BOOT_SIGNALS_ANY |
| 224 | |
| 225 | effective_signals = BOOT_SIGNALS_ANY |
| 226 | else: |
| 227 | effective_signals = boot_signals |
| 228 |