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:
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "secsgem/gem/e84_state.hpp"
|
||||
|
||||
namespace secsgem::gem {
|
||||
|
||||
// E84 (Parallel I/O) is per-load-port: each port has its own ten-wire
|
||||
// handshake with the AMHS. Earlier revisions of this codebase modeled
|
||||
// E84 as a single equipment-wide FSM; multi-LP tools need one FSM per
|
||||
// port. E84PortStore keys per-port FSMs by port_id (1-based, matching
|
||||
// LoadPortStore).
|
||||
class E84PortStore {
|
||||
public:
|
||||
using StateChangeHandler =
|
||||
std::function<void(uint8_t port_id, E84State from, E84State to,
|
||||
E84Signal trigger)>;
|
||||
|
||||
E84PortStore() = default;
|
||||
E84PortStore(const E84PortStore&) = delete;
|
||||
E84PortStore& operator=(const E84PortStore&) = delete;
|
||||
E84PortStore(E84PortStore&&) = delete;
|
||||
E84PortStore& operator=(E84PortStore&&) = delete;
|
||||
|
||||
void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); }
|
||||
|
||||
bool create(uint8_t port_id) {
|
||||
if (ports_.count(port_id)) return false;
|
||||
auto fsm = std::make_unique<E84StateMachine>();
|
||||
const uint8_t pid = port_id;
|
||||
fsm->set_state_change_handler(
|
||||
[this, pid](E84State f, E84State t, E84Signal sig) {
|
||||
if (on_change_) on_change_(pid, f, t, sig);
|
||||
});
|
||||
ports_.emplace(port_id, std::move(fsm));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool has(uint8_t port_id) const { return ports_.count(port_id) > 0; }
|
||||
|
||||
E84StateMachine* get(uint8_t port_id) {
|
||||
auto it = ports_.find(port_id);
|
||||
return it == ports_.end() ? nullptr : it->second.get();
|
||||
}
|
||||
const E84StateMachine* get(uint8_t port_id) const {
|
||||
auto it = ports_.find(port_id);
|
||||
return it == ports_.end() ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
// Convenience pass-throughs that auto-create the port on first use.
|
||||
// Real applications should call create() explicitly with their
|
||||
// expected port set, but the implicit create keeps quick demos
|
||||
// ergonomic.
|
||||
bool on_signal_change(uint8_t port_id, E84Signal s, bool value) {
|
||||
if (!ports_.count(port_id)) create(port_id);
|
||||
auto* fsm = get(port_id);
|
||||
if (!fsm) return false;
|
||||
fsm->on_signal_change(s, value);
|
||||
return true;
|
||||
}
|
||||
bool reset(uint8_t port_id) {
|
||||
auto* fsm = get(port_id);
|
||||
if (!fsm) return false;
|
||||
fsm->reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t size() const { return ports_.size(); }
|
||||
std::vector<uint8_t> ids() const {
|
||||
std::vector<uint8_t> out;
|
||||
out.reserve(ports_.size());
|
||||
for (const auto& kv : ports_) out.push_back(kv.first);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<uint8_t, std::unique_ptr<E84StateMachine>> ports_;
|
||||
StateChangeHandler on_change_;
|
||||
};
|
||||
|
||||
} // namespace secsgem::gem
|
||||
Reference in New Issue
Block a user