From 43c7dc211f10851480352b12bd01f3443079bb01 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期二, 26 八月 2025 09:09:21 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/ProcessJob.h |  216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 216 insertions(+), 0 deletions(-)

diff --git a/SourceCode/Bond/Servo/ProcessJob.h b/SourceCode/Bond/Servo/ProcessJob.h
new file mode 100644
index 0000000..1300b46
--- /dev/null
+++ b/SourceCode/Bond/Servo/ProcessJob.h
@@ -0,0 +1,216 @@
+#pragma once
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <unordered_set>
+#include <algorithm>
+#include <cstdint>
+#include <chrono>
+#include <optional>
+
+namespace SERVO {
+    /// PJ 生命周期(贴近 E40 常见状态)
+    enum class PJState : uint8_t {
+        NoState = 0,
+        Queued,
+        SettingUp,
+        InProcess,
+        Paused,
+        Aborting,
+        Completed,
+        Aborted,
+        Failed
+    };
+
+    /// 配方指定方式(对应 S16F15 里 PRRECIPEMETHOD)
+    enum class RecipeMethod : uint8_t {
+        NoTuning = 1,   // 1 - recipe without variable tuning
+        WithTuning = 2  // 2 - recipe with variable tuning
+    };
+
+    /// 启动策略(对应 S16F15 里 PRPROCESSSTART)
+    enum class StartPolicy : uint8_t {
+        Queued = 0,   // 建立后排队
+        AutoStart = 1 // 条件满足则自动启动
+    };
+
+    /** 配方参数对(S16F15 中 RCPPARNM / RCPPARVAL) */
+    struct PJParam {
+        std::string name;   // RCPPARNM
+        std::string value;  // RCPPARVAL
+    };
+
+    /**
+    {L:2
+        CARRIERID
+        {L:j
+            SLOTID
+        }
+    }
+     */
+    struct CarrierSlotInfo {
+        std::string carrierId;          // CARRIERID
+        std::vector<uint8_t> slots;     // SLOTID[]
+        std::vector<void*> contexts;    // Glass
+    };
+
+    /// 简单资源视图接口:供 Validate() 查询(由设备端实现者在外部提供)
+    struct IResourceView {
+        virtual ~IResourceView() = default;
+        virtual bool isProcessJobsEmpty() const = 0;
+        virtual bool recipeExists(const std::string& ppid) const = 0;
+        virtual bool carrierPresent(const std::string& carrierId) const = 0;
+        virtual bool slotUsable(const std::string& carrierId, uint16_t slot) const = 0;
+        virtual bool ceidDefined(uint32_t ceid) const = 0;
+        // 你也可以扩展:port状态、占用情况、CJ/PJ空间等
+    };
+
+    /// PJ 主类
+    /**
+     * ProcessJob —— 与 S16F15(PRJobMultiCreate)字段一一对应的承载类
+     *
+     * S16F15 结构(核心节选):
+     * {L:6
+     *   PRJOBID                -> m_pjId
+     *   MF                     -> m_mf
+     *   {L:n { CARRIERID {L:j SLOTID} } } 
+     *   {L:3
+     *     PRRECIPEMETHOD       -> m_recipeType
+     *     RCPSPEC(PPID)      -> m_recipeSpec
+     *     {L:m { RCPPARNM RCPPARVAL }}     -> m_params
+     *   }
+     *   PRPROCESSSTART         -> m_startPolicy
+     *   {L:k PRPAUSEEVENTID}   -> m_pauseEvents
+     * }
+     */
+    class CProcessJob {
+    public:
+        // —— 构造 / 基本设置 ——
+        CProcessJob();
+        explicit CProcessJob(std::string pjId);
+
+        const std::string& id() const noexcept { return m_pjId; }
+        const std::string& parentCjId() const noexcept { return m_parentCjId; }
+        PJState state() const noexcept { return m_state; }
+        StartPolicy startPolicy() const noexcept { return m_startPolicy; }
+        RecipeMethod recipeMethod() const noexcept { return m_recipeMethod; }
+        const std::string& recipeSpec() const noexcept { return m_recipeSpec; } // PPID 或 Spec
+        std::string getStateText();
+
+        // 绑定父 CJ
+        void setParentCjId(std::string cjId);
+
+        // 配方
+        void setRecipe(RecipeMethod method, std::string spec);
+
+        // 启动策略
+        void setStartPolicy(StartPolicy sp) { m_startPolicy = sp; }
+
+        // 参数
+        void addParam(std::string name, std::string value);
+        void setParams(std::vector<PJParam> params);
+
+        // 暂停事件
+        void addPauseEvent(uint32_t ceid);
+        void setPauseEvents(std::vector<uint32_t> ceids);
+
+        // —— 校验 ——
+        struct ValidationIssue {
+            uint32_t code;      // 自定义错误码
+            std::string text;   // 文本描述
+        };
+        // 返回问题清单(空=通过)
+        bool validate(const IResourceView& rv);
+        const std::vector<ValidationIssue>& issues();
+
+        // —— 状态机(带守卫)——
+        bool queue();           // NoState -> Queued
+        bool start();           // Queued/SettingUp -> InProcess
+        bool enterSettingUp();  // Queued -> SettingUp
+        bool pause();           // InProcess -> Paused
+        bool resume();          // Paused -> InProcess
+        bool complete();        // InProcess -> Completed
+        bool abort();           // Any (未终态) -> Aborted
+        bool fail(std::string reason); // 任意态 -> Failed(记录失败原因)
+
+        // —— 访问器(用于上报/查询)——
+        const std::vector<PJParam>& params() const noexcept { return m_params; }
+        const std::vector<uint32_t>& pauseEvents() const noexcept { return m_pauseEvents; }
+        const std::string& failReason() const noexcept { return m_failReason; }
+
+        // 时间戳(可用于报表/追溯)
+        std::optional<std::chrono::system_clock::time_point> tQueued() const { return m_tQueued; }
+        std::optional<std::chrono::system_clock::time_point> tStart()  const { return m_tStart; }
+        std::optional<std::chrono::system_clock::time_point> tEnd()    const { return m_tEnd; }
+
+        // 长度限制工具(可在集成时统一策略)
+        static void clampString(std::string& s, size_t maxLen);
+        static bool asciiPrintable(const std::string& s);
+
+        // 清空并整体设置
+        void setCarriers(std::vector<CarrierSlotInfo> carriers);
+
+        // 追加一个载具
+        void addCarrier(std::string carrierId, std::vector<uint8_t> slots);
+
+        // 访问器
+        const std::vector<CarrierSlotInfo>& carriers() const noexcept { return m_carriers; }
+        CarrierSlotInfo* getCarrier(std::string& strId);
+
+        // 判定是否“按载具/卡位”方式
+        bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); }
+
+
+    public:
+        // ====== 版本头常量(建议保留,便于兼容)======
+        static constexpr uint32_t PJ_FILE_MAGIC = 0x504A4A31; // "PJJ1"
+        static constexpr uint16_t PJ_FILE_VERSION = 0x0001;
+
+        // ====== 流式序列化接口 ======
+        void serialize(std::ostream& os) const;
+        static bool deserialize(std::istream& is, CProcessJob& out, std::string* err = nullptr);
+
+    private:
+        // 内部状态转移帮助
+        void markQueued();
+        void markStart();
+        void markEnd();
+
+    private:
+        // 标识
+        std::string m_pjId;
+        std::string m_parentCjId;
+
+        // 配方
+        RecipeMethod m_recipeMethod{ RecipeMethod::NoTuning };
+        std::string  m_recipeSpec; // PPID / Spec
+
+        // 物料
+        static constexpr uint8_t MATERIAL_FORMAT = 14; // substrate
+        std::vector<CarrierSlotInfo> m_carriers;   // {L:n { CARRIERID {L:j SLOTID} }}
+
+        // 参数 / 暂停事件
+        std::vector<PJParam>    m_params;
+        std::vector<uint32_t>   m_pauseEvents;
+
+        // 状态 & 记录
+        StartPolicy m_startPolicy{ StartPolicy::Queued }; // 0=Queued, 1=AutoStart
+        PJState m_state{ PJState::NoState };
+        std::string m_failReason;
+
+        // 时间戳
+        std::optional<std::chrono::system_clock::time_point> m_tQueued;
+        std::optional<std::chrono::system_clock::time_point> m_tStart;
+        std::optional<std::chrono::system_clock::time_point> m_tEnd;
+
+        // 约束(可按你们协议调整)
+        static constexpr size_t MAX_ID_LEN = 64;   // PJID/ CJID/ CarrierID/ MID/ PPID
+        static constexpr size_t MAX_PARAM_K = 32;   // 参数名
+        static constexpr size_t MAX_PARAM_V = 64;   // 参数值
+
+        // 错误列表
+        std::vector<ValidationIssue> m_issues;
+    };
+}
+
+

--
Gitblit v1.9.3