94 lines
3.7 KiB
Python
94 lines
3.7 KiB
Python
"""End-to-end hardware test on the MUM (Melexis Universal Master).
|
|
|
|
Powers the ECU via MUM's built-in power output, reads ALM_Status to discover
|
|
the slave's NAD, then activates the RGB LED via the master-published
|
|
ALM_Req_A frame targeting that NAD with full white at full intensity. Frame
|
|
layouts are taken from the LDF at runtime via the `ldf` fixture, so signal
|
|
names and bit positions stay in sync with `vendor/4SEVEN_color_lib_test.ldf`
|
|
without manual byte building.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from ecu_framework.config import EcuTestConfig
|
|
from ecu_framework.lin.base import LinFrame, LinInterface
|
|
|
|
|
|
pytestmark = [pytest.mark.hardware, pytest.mark.mum]
|
|
|
|
|
|
def test_mum_e2e_power_on_then_led_activate(
|
|
config: EcuTestConfig, lin: LinInterface, ldf, rp
|
|
):
|
|
"""
|
|
Title: MUM E2E - Power ECU, Read NAD, Activate RGB LED
|
|
|
|
Description:
|
|
Drives the full hardware path through the Melexis Universal Master:
|
|
the `lin` fixture has already powered the ECU via power_out0 and set
|
|
up the LIN bus. This test reads ALM_Status to discover the slave's
|
|
NAD, publishes ALM_Req_A targeting that NAD with full white at full
|
|
intensity, and re-reads ALM_Status to confirm the bus is alive.
|
|
Frame layouts come from the LDF database, not hand-coded byte
|
|
positions.
|
|
|
|
Requirements: REQ-MUM-LED-ACTIVATE
|
|
|
|
Test Steps:
|
|
1. Skip unless interface.type == 'mum'
|
|
2. Read ALM_Status; decode signals via the LDF; extract ALMNadNo
|
|
3. Build the ALM_Req_A payload via ldf.frame("ALM_Req_A").pack(...),
|
|
targeting LIDFrom=LIDTo=current_nad with full-white RGB
|
|
4. Publish ALM_Req_A via lin.send()
|
|
5. Re-read ALM_Status and confirm the bus still returns a valid frame
|
|
|
|
Expected Result:
|
|
- First ALM_Status decode yields ALMNadNo in 0x01..0xFE
|
|
- lin.send() of the LDF-packed frame succeeds
|
|
- Second ALM_Status read returns a frame (bus still alive after Tx)
|
|
"""
|
|
if config.interface.type != "mum":
|
|
pytest.skip("interface.type must be 'mum' for this test")
|
|
|
|
req_a = ldf.frame("ALM_Req_A")
|
|
status = ldf.frame("ALM_Status")
|
|
rp("ldf_path", str(ldf.path))
|
|
rp("req_a_id", f"0x{req_a.id:02X}")
|
|
rp("status_id", f"0x{status.id:02X}")
|
|
|
|
# Step 2: read ALM_Status and decode it via the LDF.
|
|
rx = lin.receive(id=status.id, timeout=1.0)
|
|
assert rx is not None, "No ALM_Status received — check MUM/ECU wiring and power"
|
|
decoded = status.unpack(bytes(rx.data))
|
|
current_nad = int(decoded["ALMNadNo"])
|
|
rp("alm_status_decoded", decoded)
|
|
rp("current_nad", f"0x{current_nad:02X}")
|
|
assert 0x01 <= current_nad <= 0xFE, (
|
|
f"ALMNadNo {current_nad:#x} is out of valid range; ECU may be unconfigured"
|
|
)
|
|
|
|
# Step 3 + 4: target the discovered NAD with full white at full intensity.
|
|
payload = req_a.pack(
|
|
AmbLightColourRed=0xFF,
|
|
AmbLightColourGreen=0xFF,
|
|
AmbLightColourBlue=0xFF,
|
|
AmbLightIntensity=0xFF,
|
|
AmbLightUpdate=0, # 0 = Immediate color update
|
|
AmbLightMode=0, # 0 = Immediate Setpoint
|
|
AmbLightDuration=0,
|
|
AmbLightLIDFrom=current_nad,
|
|
AmbLightLIDTo=current_nad,
|
|
)
|
|
rp("tx_data_hex", payload.hex())
|
|
lin.send(LinFrame(id=req_a.id, data=payload))
|
|
|
|
# Step 5: confirm bus liveness after the activation frame.
|
|
rx_after = lin.receive(id=status.id, timeout=1.0)
|
|
rp("post_status_present", rx_after is not None)
|
|
if rx_after is not None:
|
|
rp("post_status_decoded", status.unpack(bytes(rx_after.data)))
|
|
assert rx_after is not None, (
|
|
"ALM_Status not received after publishing ALM_Req_A — ECU may have reset"
|
|
)
|