ecu-tests/docs/04_lin_interface_call_flow.md

90 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 0x000x3F (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.