e84: per-port FSM via E84PortStore
E84 (Parallel I/O) is fundamentally per-load-port: each port has its own ten-wire handshake with the AMHS. Earlier revisions modeled it as a single equipment-wide FSM; this commit refactors to a per-port store, so multi-LP tools can run independent handshakes in parallel. Public API change in EquipmentDataModel: E84StateMachine e84; -> removed E84PortStore e84_ports; // create(port_id), get(port_id), ... Convenience pass-throughs: E84PortStore::on_signal_change auto-creates the port on first use (ergonomic for demos); applications should call create() explicitly with their full port set. The two existing callsites (test_gem300_scenario, test_e87_wire_scenarios) are updated. The multi-LP test now demonstrates the actual win: interleaved LP1 load + LP2 unload handshakes that reach their respective Ready states without sequencing, and an ES on LP1 that does NOT affect LP2 — exactly the failure mode the previous design couldn't catch. Five new dedicated tests in test_e84_ports.cpp for the store itself. COMPLIANCE.md §4i updated: row now reflects per-port design. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -222,35 +222,28 @@ TEST_CASE("Multi-LP: 4 ports are independent — events on one don't affect anot
|
||||
gem::SlotMapStatus::NotRead);
|
||||
}
|
||||
|
||||
TEST_CASE("Multi-LP: simultaneous E84 handshakes on two ports stay independent") {
|
||||
// No wire here — the E84 FSM is a per-port axis in the equipment
|
||||
// model; we test that two separate ports running their handshakes in
|
||||
// overlapping sequences don't interfere. The data model has a
|
||||
// single E84StateMachine for now; this exercise documents that the
|
||||
// current design is per-equipment, not per-port — so the test runs
|
||||
// the second handshake AFTER the first completes, and asserts the
|
||||
// second one sees the FSM cleanly returned to Idle.
|
||||
TEST_CASE("Multi-LP: per-port E84 FSMs run truly in parallel") {
|
||||
// E84 is now per-port (E84PortStore). Two ports can be in completely
|
||||
// different states at the same time without sequencing.
|
||||
gem::EquipmentDataModel m;
|
||||
m.load_ports.create(1);
|
||||
m.load_ports.create(2);
|
||||
|
||||
// LP1 load handshake.
|
||||
m.e84.on_signal_change(gem::E84Signal::CS_0, true);
|
||||
m.e84.on_signal_change(gem::E84Signal::VALID, true);
|
||||
m.e84.on_signal_change(gem::E84Signal::L_REQ, true);
|
||||
CHECK(m.e84.state() == gem::E84State::LoadReady);
|
||||
m.e84.on_signal_change(gem::E84Signal::BUSY, true);
|
||||
m.e84.on_signal_change(gem::E84Signal::BUSY, false);
|
||||
m.e84.on_signal_change(gem::E84Signal::COMPT, true);
|
||||
CHECK(m.e84.state() == gem::E84State::Complete);
|
||||
// LP1: interleave load-handshake bring-up with LP2: interleave
|
||||
// unload-handshake bring-up. Both reach their respective Ready
|
||||
// states with no cross-contamination.
|
||||
m.e84_ports.on_signal_change(1, gem::E84Signal::CS_0, true);
|
||||
m.e84_ports.on_signal_change(2, gem::E84Signal::CS_0, true);
|
||||
m.e84_ports.on_signal_change(1, gem::E84Signal::VALID, true);
|
||||
m.e84_ports.on_signal_change(2, gem::E84Signal::VALID, true);
|
||||
m.e84_ports.on_signal_change(1, gem::E84Signal::L_REQ, true);
|
||||
m.e84_ports.on_signal_change(2, gem::E84Signal::U_REQ, true);
|
||||
|
||||
// Reset for LP2.
|
||||
m.e84.reset();
|
||||
CHECK(m.e84.state() == gem::E84State::Idle);
|
||||
CHECK(m.e84_ports.get(1)->state() == gem::E84State::LoadReady);
|
||||
CHECK(m.e84_ports.get(2)->state() == gem::E84State::UnloadReady);
|
||||
|
||||
// LP2 unload handshake.
|
||||
m.e84.on_signal_change(gem::E84Signal::CS_0, true);
|
||||
m.e84.on_signal_change(gem::E84Signal::VALID, true);
|
||||
m.e84.on_signal_change(gem::E84Signal::U_REQ, true);
|
||||
CHECK(m.e84.state() == gem::E84State::UnloadReady);
|
||||
// ES on LP1 must not affect LP2.
|
||||
m.e84_ports.on_signal_change(1, gem::E84Signal::ES, true);
|
||||
CHECK(m.e84_ports.get(1)->state() == gem::E84State::EmergencyStop);
|
||||
CHECK(m.e84_ports.get(2)->state() == gem::E84State::UnloadReady);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user