#pragma once #include #include #include #include #include #include #include #include "secsgem/gem/substrate_state.hpp" namespace secsgem::gem { struct Substrate { std::string substid; // SUBSTID — E90 wafer identifier std::string carrierid; // CARRIERID where this wafer originated uint8_t slot = 0; // 1-based slot in the source carrier std::string location; // free-form: equipment-defined module name std::unique_ptr fsm; }; class SubstrateStore { public: using LocationChangeHandler = std::function; using ProcessingChangeHandler = std::function; SubstrateStore() = default; SubstrateStore(const SubstrateStore&) = delete; SubstrateStore& operator=(const SubstrateStore&) = delete; SubstrateStore(SubstrateStore&&) = delete; SubstrateStore& operator=(SubstrateStore&&) = delete; void set_location_handler(LocationChangeHandler h) { on_loc_ = std::move(h); } void set_processing_handler(ProcessingChangeHandler h) { on_proc_ = std::move(h); } enum class CreateResult { Created, Denied_AlreadyExists }; CreateResult create(std::string substid, std::string carrierid = "", uint8_t slot = 0) { if (subs_.count(substid)) return CreateResult::Denied_AlreadyExists; auto fsm = std::make_unique(); const std::string id = substid; fsm->set_location_handler( [this, id](SubstrateState f, SubstrateState t, SubstrateEvent e) { if (on_loc_) on_loc_(id, f, t, e); }); fsm->set_processing_handler( [this, id](SubstrateProcessingState f, SubstrateProcessingState t, SubstrateProcessingEvent e) { if (on_proc_) on_proc_(id, f, t, e); }); subs_.emplace(substid, Substrate{substid, std::move(carrierid), slot, "", std::move(fsm)}); return CreateResult::Created; } bool has(const std::string& id) const { return subs_.count(id) > 0; } const Substrate* get(const std::string& id) const { auto it = subs_.find(id); return it == subs_.end() ? nullptr : &it->second; } Substrate* get(const std::string& id) { auto it = subs_.find(id); return it == subs_.end() ? nullptr : &it->second; } bool fire_location_event(const std::string& id, SubstrateEvent e, std::string new_location = "") { auto* s = get(id); if (!s) return false; if (!new_location.empty()) s->location = std::move(new_location); return s->fsm->on_location_event(e); } bool fire_processing_event(const std::string& id, SubstrateProcessingEvent e) { auto* s = get(id); return s && s->fsm->on_processing_event(e); } bool remove(const std::string& id) { return subs_.erase(id) > 0; } std::size_t size() const { return subs_.size(); } std::vector ids() const { std::vector out; out.reserve(subs_.size()); for (const auto& kv : subs_) out.push_back(kv.first); return out; } private: std::map subs_; LocationChangeHandler on_loc_; ProcessingChangeHandler on_proc_; }; } // namespace secsgem::gem