# LIN Interface Call Flow This document explains how LIN operations flow through the abstraction for the Mock, MUM, and legacy BabyLIN adapters. ## Contract (base) File: `ecu_framework/lin/base.py` - `connect()` / `disconnect()` - `send(frame: LinFrame)` - `receive(id: int | None = None, timeout: float = 1.0) -> LinFrame | None` - `request(id: int, length: int, timeout: float = 1.0) -> LinFrame | None` - `flush()` `LinFrame` validates: - ID is 0x00–0x3F (6-bit LIN ID) - Data length ≤ 8 bytes ## Mock adapter flow File: `ecu_framework/lin/mock.py` - `connect()`: initialize buffers and state - `send(frame)`: enqueues the frame and (for echo behavior) schedules it for RX - `receive(timeout)`: waits up to timeout for a frame in RX buffer - `request(id, length, timeout)`: synthesizes a deterministic response of the given length for predictability - `disconnect()`: clears state Use cases: - Fast local dev, deterministic responses, no hardware - Timeout and boundary behavior validation ## MUM adapter flow (Melexis Universal Master) File: `ecu_framework/lin/mum.py` The MUM is a networked LIN master (default IP `192.168.7.2`) with built-in power control on `power_out0`. It is **master-driven**: there is no passive listen — to read a slave-published frame, the master triggers a header on that frame ID. Diagnostic frames (BSM-SNPD, service ID 0xB5) require LIN 1.x **Classic** checksum and are sent through the transport layer's `ld_put_raw`, not the regular `send_message`. - `connect()`: lazy-imports `pymumclient` + `pylin`; opens MUM (`MelexisUniversalMaster.open_all(host)`), gets the LIN device (`linmaster`) and power device (`power_control`), runs `linmaster.setup()`, builds `LinBusManager` + `LinDevice22`, sets `lin_dev.baudrate`, fetches the transport layer (`get_device("bus/transport_layer")`), and finally `power_control.power_up()` followed by a `boot_settle_seconds` sleep - `send(frame)`: `lin_dev.send_message(master_to_slave=True, frame_id, data_length, data)` - `receive(id, timeout)`: `lin_dev.send_message(master_to_slave=False, frame_id=id, data_length=frame_lengths.get(id, default_data_length))` — pylin returns the response bytes (or raises on timeout, which we treat as `None`). `id=None` raises `NotImplementedError` because the MUM cannot listen passively. - `disconnect()`: best-effort `power_control.power_down()` followed by `linmaster.teardown()` - MUM-only extras: `send_raw(bytes)` (Classic checksum via `ld_put_raw`), `power_up()`, `power_down()`, `power_cycle(wait)` Configuration: - `interface.host` is required; `interface.lin_device` and `interface.power_device` default to MUM conventions - `interface.bitrate` is the actual LIN baudrate the MUM drives - `interface.frame_lengths` lets you map slave frame IDs to their fixed data lengths so `receive(id)` can fetch the correct number of bytes; built-in defaults cover ALM_Status (4) and ALM_Req_A (8) ## BabyLIN adapter flow (SDK wrapper) File: `ecu_framework/lin/babylin.py` - `connect()`: import SDK `BabyLIN_library.py`, discover ports, open first, optionally `BLC_loadSDF`, get channel handle, and `BLC_sendCommand("start schedule N;")` - `send(frame)`: calls `BLC_mon_set_xmit(channelHandle, frameId, data, slotTime=0)` - `receive(timeout)`: calls `BLC_getNextFrameTimeout(channelHandle, timeout_ms)` and converts returned `BLC_FRAME` to `LinFrame` - `request(id, length, timeout)`: prefers `BLC_sendRawMasterRequest(channel, id, length)`; falls back to `(channel, id, bytes)`; if unavailable, sends a header and waits on `receive()` - `disconnect()`: calls `BLC_closeAll()` - Error handling: uses `BLC_getDetailedErrorString` (if available) Configuration: - `interface.sdf_path` locates the SDF to load - `interface.schedule_nr` sets the schedule to start upon connect - `interface.channel` selects the channel index ## Edge considerations - Ensure the correct architecture (x86/x64) of the DLL matches Python - Channel/bitrate must match your network configuration - Some SDKs require initialization/scheduling steps before transmit/receive - Time synchronization and timestamp units vary per SDK — convert as needed Note on master requests: - Our mock wrapper returns a deterministic byte pattern when called with the `length` signature. - When only the bytes signature is available, zeros of the requested length are used in tests.