"""Mock implementation of the BabyLIN SDK wrapper API used by our adapter. This module provides create_BabyLIN() returning an object with BLC_* methods, so the real adapter can be exercised without hardware. Design notes: - We simulate a single device with one channel and an RX queue per channel. - Transmit (BLC_mon_set_xmit) echoes payload into the RX queue to mimic loopback. - Master request (BLC_sendRawMasterRequest) enqueues a deterministic response so tests can validate request/response logic without randomness. """ from dataclasses import dataclass from typing import List BL_OK = 0 # Success code matching the real SDK convention @dataclass class BLC_FRAME: """Minimal frame structure to mirror the SDK's BLC_FRAME used by the adapter.""" frameId: int lenOfData: int frameData: bytes class _MockChannel: """Represents a BabyLIN channel with a simple RX queue.""" def __init__(self): self.rx: List[BLC_FRAME] = [] # FIFO for received frames class _MockBL: """BabyLIN mock exposing the subset of BLC_* APIs our adapter calls.""" def __init__(self): self.BL_OK = BL_OK self._ports = ["MOCK_PORT"] # Simulate one discoverable device self._handle = object() # Opaque handle placeholder self._channels = [_MockChannel()] # Single channel system # ----------------------------- # Discovery/open/close # ----------------------------- def BLC_getBabyLinPorts(self, timeout_ms: int): """Return a list of mock ports; timeout not used in mock.""" return list(self._ports) def BLC_openPort(self, port: str): """Return an opaque handle for the given port name.""" return self._handle def BLC_closeAll(self): """Pretend to close; always succeeds.""" return BL_OK # ----------------------------- # SDF and channel handling # ----------------------------- def BLC_loadSDF(self, handle, sdf_path: str, download: int): """No-op in mock; assume success.""" return BL_OK def BLC_getChannelCount(self, handle): """Report number of channels (1 in mock).""" return len(self._channels) def BLC_getChannelHandle(self, handle, idx: int): """Return the channel object acting as its own handle.""" return self._channels[idx] def BLC_sendCommand(self, channel, command: str): """Accept any command (e.g., start schedule); always succeed.""" return BL_OK # ----------------------------- # Transmit/Receive primitives # ----------------------------- def BLC_mon_set_xmit(self, channel: _MockChannel, frame_id: int, data: bytes, slot_time: int): """Echo transmitted payload back to RX to simulate a bus loopback.""" channel.rx.append(BLC_FRAME(frameId=frame_id, lenOfData=len(data), frameData=bytes(data))) return BL_OK def BLC_getNextFrameTimeout(self, channel: _MockChannel, timeout_ms: int): """Pop next frame from RX queue; return None on timeout (empty queue).""" if channel.rx: return channel.rx.pop(0) # Simulate timeout -> real wrapper may raise; we return None for simplicity return None def BLC_sendRawMasterRequest(self, channel: _MockChannel, frame_id: int, payload_or_length): """Simulate a slave response for a master request. Supports two call forms to mirror SDK variations: - (channel, frame_id, bytes): use bytes as the response payload - (channel, frame_id, length): synthesize payload with a deterministic pattern """ if isinstance(payload_or_length, (bytes, bytearray)): data = bytes(payload_or_length) else: length = int(payload_or_length) # Deterministic pattern: response[i] = (frame_id + i) & 0xFF data = bytes(((frame_id + i) & 0xFF) for i in range(max(0, min(8, length)))) # Enqueue the response frame as if the slave published it on the bus channel.rx.append(BLC_FRAME(frameId=frame_id, lenOfData=len(data), frameData=data)) return BL_OK def BLC_getDetailedErrorString(self, rc: int): """Provide a friendly error string for non-OK return codes.""" return f"Mock error rc={rc}" def create_BabyLIN(): """Factory method matching the real SDK to construct the mock instance.""" return _MockBL()