From 6dc80508b1c0f431007f8a8c947c152ec00c3d15 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期一, 08 九月 2025 09:24:05 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/GlassJson.cpp |  334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 334 insertions(+), 0 deletions(-)

diff --git a/SourceCode/Bond/Servo/GlassJson.cpp b/SourceCode/Bond/Servo/GlassJson.cpp
new file mode 100644
index 0000000..c16be0b
--- /dev/null
+++ b/SourceCode/Bond/Servo/GlassJson.cpp
@@ -0,0 +1,334 @@
+#include "stdafx.h"
+#include "GlassJson.h"
+
+#include <chrono>
+#include <optional>
+#include <sstream>
+#include <limits>
+#include <cstdlib>
+
+#include "CGlass.h"
+#include "CParam.h"
+#include "CJobDataS.h"
+#include "CPath.h"
+
+using namespace SERVO;
+
+// ==================== 小工具(兼容老 JsonCpp) ====================
+
+// 将 optional<time_point> 转毫秒(int64),再以字符串写入 JSON
+static std::string tp_to_ms_str(std::optional<std::chrono::system_clock::time_point> tp) {
+    if (!tp) return std::string(); // 空串表示无
+    using namespace std::chrono;
+    long long ms = duration_cast<milliseconds>(tp->time_since_epoch()).count();
+    return std::to_string(ms);
+}
+
+// 从 JSON 的字符串/数字容忍式读取 64 位,优先 string
+static bool get_ll_from_json(const Json::Value& v, const char* key, long long& out) {
+    if (!v.isMember(key)) return false;
+    const Json::Value& x = v[key];
+    if (x.isString()) {
+        const std::string s = x.asString();
+        if (s.empty()) return false;
+        char* endp = nullptr;
+        errno = 0;
+#if defined(_MSC_VER)
+        long long val = _strtoi64(s.c_str(), &endp, 10);
+#else
+        long long val = std::strtoll(s.c_str(), &endp, 10);
+#endif
+        if (endp && *endp == '\0' && errno == 0) { out = val; return true; }
+        // 容错:如果其实是数字字符串(带空格),再试一次
+        try { out = std::stoll(s); return true; }
+        catch (...) {}
+        return false;
+    }
+    if (x.isInt()) { out = static_cast<long long>(x.asInt());  return true; }
+    if (x.isUInt()) { out = static_cast<long long>(x.asUInt()); return true; }
+    if (x.isDouble()) { out = static_cast<long long>(x.asDouble()); return true; }
+    return false;
+}
+
+// 写 64 位为字符串(跨版本/跨语言更稳)
+static void put_ull_as_str(Json::Value& obj, const char* key, unsigned long long v) {
+    obj[key] = Json::Value(std::to_string(v));
+}
+static void put_ll_as_str(Json::Value& obj, const char* key, long long v) {
+    obj[key] = Json::Value(std::to_string(v));
+}
+
+// 简化读取(带默认)
+static int         JInt(const Json::Value& v, const char* k, int d = 0)
+{
+    return v.isMember(k) ? v[k].asInt() : d;
+}
+static unsigned    JUInt(const Json::Value& v, const char* k, unsigned d = 0)
+{
+    return v.isMember(k) ? v[k].asUInt() : d;
+}
+static bool        JBool(const Json::Value& v, const char* k, bool d = false)
+{
+    return v.isMember(k) ? v[k].asBool() : d;
+}
+static std::string JStr(const Json::Value& v, const char* k, const std::string& d = "")
+{
+    return v.isMember(k) ? v[k].asString() : d;
+}
+static double      JDouble(const Json::Value& v, const char* k, double d = 0.0)
+{
+    return v.isMember(k) ? v[k].asDouble() : d;
+}
+
+// ==================== CGlass -> JSON ====================
+
+Json::Value GlassJson::ToJson(const CGlass& gConst) {
+    CGlass& g = const_cast<CGlass&>(gConst); // 许多 getter 不是 const
+    Json::Value root(Json::objectValue);
+
+    // 基本
+    root["id"] = g.getID();
+    root["materials"] = static_cast<int>(g.getType());              // 0/1/2/3
+    root["buddy_id"] = g.getBuddyId();
+    root["has_buddy"] = (g.getBuddy() != nullptr);
+
+    int port = 0, slot = 0;
+    g.getOrginPort(port, slot);
+    root["origin_port"] = port;
+    root["origin_slot"] = slot;
+
+    root["scheduled"] = g.isScheduledForProcessing() ? true : false;
+    root["state"] = static_cast<int>(g.state());                // GlsState -> int
+    root["fail_reason"] = g.m_failReason;
+
+    // 时间戳:以字符串写
+    root["t_queued_ms"] = tp_to_ms_str(g.tQueued());
+    root["t_start_ms"] = tp_to_ms_str(g.tStart());
+    root["t_end_ms"] = tp_to_ms_str(g.tEnd());
+
+    // params: vector<CParam>
+    {
+        Json::Value arr(Json::arrayValue);
+        for (auto& p : g.getParams()) {
+            Json::Value jp(Json::objectValue);
+            jp["id"] = p.getId();
+            jp["name"] = p.getName();
+            jp["unit"] = p.getUnit();
+            int vt = p.getValueType(); // PVT_INT=0, PVT_DOUBLE=1
+            jp["vtype"] = vt;
+            if (vt == PVT_INT)  jp["iv"] = p.getIntValue();
+            else                jp["fv"] = p.getDoubleValue();
+            arr.append(std::move(jp));
+        }
+        root["params"] = std::move(arr);
+    }
+
+    // JobDataS
+    {
+        CJobDataS& s = *g.getJobDataS();
+        Json::Value js(Json::objectValue);
+        js["cassette_seq_no"] = s.getCassetteSequenceNo();
+        js["job_seq_no"] = s.getJobSequenceNo();
+        js["lot_id"] = s.getLotId();
+        js["product_id"] = s.getProductId();
+        js["operation_id"] = s.getOperationId();
+        js["glass1_id"] = s.getGlass1Id();
+        js["glass2_id"] = s.getGlass2Id();
+
+        js["job_type"] = s.getJobType();
+        js["materials_type"] = s.getMaterialsType();
+        js["product_type"] = s.getProductType();
+        js["dummy_type"] = s.getDummyType();
+        js["skip_flag"] = s.getSkipFlag();
+        js["process_flag"] = s.getProcessFlag();
+        js["process_reason"] = s.getProcessResonCode();
+        js["last_glass_flag"] = s.getLastGlassFlag();
+        js["first_glass_flag"] = s.getFirstGlassFlag();
+
+        Json::Value q(Json::arrayValue);
+        for (int i = 0; i < 3; i++) q.append(s.getQTime(i));
+        js["qtime"] = std::move(q);
+        js["qtime_over_flag"] = s.getQTimeOverFlag();
+
+        js["master_recipe"] = s.getMasterRecipe();
+        Json::Value rids(Json::arrayValue);
+        for (int i = 0; i < DEVICE_COUNT; i++) rids.append(s.getDeviceRecipeId(i));
+        js["device_recipe_ids"] = std::move(rids);
+
+        js["panel_measure"] = s.getPanelMeasure();
+        js["mode"] = s.getMode();
+        js["slot_unit_select_flag"] = s.getSlotUnitSelectFlag();
+
+        js["source_port_no"] = s.getSourcePortNo();
+        js["source_slot_no"] = s.getSourceSlotNo();
+        js["target_port_no"] = s.getTargetPortNo();
+        js["target_slot_no"] = s.getTargetSlotNo();
+
+        js["product_judge"] = s.getProductJudge();
+
+        root["job_data_s"] = std::move(js);
+    }
+
+    // path(链表 → 数组;时间字段以字符串存)
+    {
+        Json::Value arr(Json::arrayValue);
+        if (auto head = g.getPath()) {
+            CPath* p = head->getHeadPath();
+            while (p) {
+                Json::Value n(Json::objectValue);
+                n["eq_id"] = p->getEqID();
+                n["unit"] = p->getUnit();
+                put_ull_as_str(n, "time_in", static_cast<unsigned long long>(p->getInTime()));
+                put_ull_as_str(n, "time_out", static_cast<unsigned long long>(p->getOutTime()));
+                n["processed"] = p->isProcessEnd() ? true : false;
+                n["insp_result"] = static_cast<int>(p->getInspResult()); // 0:not,1:pass,2:fail
+                arr.append(std::move(n));
+                p = p->getNext();
+            }
+        }
+        root["path"] = std::move(arr);
+    }
+
+    root["payload_version"] = 1;
+    return root;
+}
+
+// ==================== JSON -> CGlass ====================
+
+void GlassJson::FromJson(const Json::Value& root, CGlass& g) {
+    // 基本
+    g.setID(JStr(root, "id").c_str());
+    g.setType(static_cast<MaterialsType>(JInt(root, "materials", 0)));
+    g.getBuddyId() = JStr(root, "buddy_id");
+    g.setScheduledForProcessing(JBool(root, "scheduled") ? TRUE : FALSE);
+    g.m_failReason = JStr(root, "fail_reason");
+    g.setOriginPort(JInt(root, "origin_port", 0), JInt(root, "origin_slot", 0));
+
+    // 状态与时间(时间从字符串/数字容错解析)
+    g.m_state = static_cast<GlsState>(JInt(root, "state", 0));
+    long long ms = 0;
+    if (get_ll_from_json(root, "t_queued_ms", ms)) g.m_tQueued = std::chrono::system_clock::time_point(std::chrono::milliseconds(ms)); else g.m_tQueued = std::nullopt;
+    if (get_ll_from_json(root, "t_start_ms", ms)) g.m_tStart = std::chrono::system_clock::time_point(std::chrono::milliseconds(ms)); else g.m_tStart = std::nullopt;
+    if (get_ll_from_json(root, "t_end_ms", ms)) g.m_tEnd = std::chrono::system_clock::time_point(std::chrono::milliseconds(ms)); else g.m_tEnd = std::nullopt;
+
+    // params
+    g.getParams().clear();
+    if (root.isMember("params") && root["params"].isArray()) {
+        for (const auto& jp : root["params"]) {
+            const int vt = JInt(jp, "vtype", 0); // 0=int,1=double
+            const std::string name = JStr(jp, "name");
+            const std::string id = JStr(jp, "id");
+            const std::string unit = JStr(jp, "unit");
+            if (vt == PVT_INT) {
+                CParam p(name.c_str(), id.c_str(), unit.c_str(), JInt(jp, "iv", 0));
+                g.getParams().push_back(std::move(p));
+            }
+            else {
+                CParam p(name.c_str(), id.c_str(), unit.c_str(), JDouble(jp, "fv", 0.0));
+                g.getParams().push_back(std::move(p));
+            }
+        }
+    }
+
+    // JobDataS
+    if (root.isMember("job_data_s") && root["job_data_s"].isObject()) {
+        const auto& js = root["job_data_s"];
+        CJobDataS* s = g.getJobDataS();
+
+        s->setCassetteSequenceNo(JInt(js, "cassette_seq_no", 0));
+        s->setJobSequenceNo(JInt(js, "job_seq_no", 0));
+
+        s->setLotId(JStr(js, "lot_id").c_str());
+        s->setProductId(JStr(js, "product_id").c_str());
+        s->setOperationId(JStr(js, "operation_id").c_str());
+        s->setGlass1Id(JStr(js, "glass1_id").c_str());
+        s->setGlass2Id(JStr(js, "glass2_id").c_str());
+
+        s->setJobType(JInt(js, "job_type", 0));
+        s->setMaterialsType(JInt(js, "materials_type", 0));
+        s->setProductType(JInt(js, "product_type", 0));
+        s->setDummyType(JInt(js, "dummy_type", 0));
+        s->setSkipFlag(JInt(js, "skip_flag", 0));
+        s->setProcessFlag(JInt(js, "process_flag", 0));
+        s->setProcessResonCode(JInt(js, "process_reason", 0));
+        s->setLastGlassFlag(JInt(js, "last_glass_flag", 0));
+        s->setFirstGlassFlag(JInt(js, "first_glass_flag", 0));
+
+        if (js.isMember("qtime") && js["qtime"].isArray()) {
+            for (int i = 0; i < 3; i++) {
+                int v = (i < (int)js["qtime"].size()) ? js["qtime"][i].asInt() : 0;
+                s->setQTime(i, v);
+            }
+        }
+        else {
+            for (int i = 0; i < 3; i++) s->setQTime(i, 0);
+        }
+        s->setQTimeOverFlag(JInt(js, "qtime_over_flag", 0));
+
+        s->setMasterRecipe(JInt(js, "master_recipe", 0));
+        if (js.isMember("device_recipe_ids") && js["device_recipe_ids"].isArray()) {
+            for (int i = 0; i < DEVICE_COUNT; i++) {
+                int v = (i < (int)js["device_recipe_ids"].size()) ? js["device_recipe_ids"][i].asInt() : 0;
+                s->setDeviceRecipeId(i, static_cast<short>(v));
+            }
+        }
+        else {
+            for (int i = 0; i < DEVICE_COUNT; i++) s->setDeviceRecipeId(i, 0);
+        }
+
+        s->setPanelMeasure(JStr(js, "panel_measure").c_str());
+        s->setMode(JInt(js, "mode", 0));
+        s->setSlotUnitSelectFlag(JInt(js, "slot_unit_select_flag", 0));
+
+        s->setSourcePortNo(JInt(js, "source_port_no", 0));
+        s->setSourceSlotNo(JInt(js, "source_slot_no", 0));
+        s->setTargetPortNo(JInt(js, "target_port_no", 0));
+        s->setTargetSlotNo(JInt(js, "target_slot_no", 0));
+
+        s->setProductJudge(static_cast<short>(JInt(js, "product_judge", 0)));
+    }
+
+    // path:顺序重建链(时间字段以字符串读回)
+    if (root.isMember("path") && root["path"].isArray()) {
+        for (const auto& n : root["path"]) {
+            unsigned eq = JUInt(n, "eq_id", 0);
+            unsigned unit = JUInt(n, "unit", 0);
+            g.addPath(eq, unit);
+
+            CPath* tail = nullptr;
+            if (auto head = g.getPath()) tail = head->getTailPath();
+            if (!tail) continue;
+
+            long long tin = 0, tout = 0;
+            if (get_ll_from_json(n, "time_in", tin))  tail->setInTime(static_cast<ULONGLONG>(tin));
+            if (get_ll_from_json(n, "time_out", tout)) tail->setOutTime(static_cast<ULONGLONG>(tout));
+            tail->setInspResult(static_cast<InspResult>(JInt(n, "insp_result", 0)));
+            if (JBool(n, "processed", false)) tail->processEnd();
+        }
+    }
+}
+
+// ==================== 便捷封装 ====================
+
+std::string GlassJson::ToString(const CGlass& g) {
+    Json::FastWriter w;              // 旧版:紧凑,无格式
+    // w.omitEndingLineFeed();          // 去掉末尾换行(如果你的 JsonCpp 版本支持)
+    return w.write(ToJson(g));
+}
+
+std::string GlassJson::ToPrettyString(const CGlass& g) {
+    Json::StyledWriter w;            // 旧版:美化输出
+    return w.write(ToJson(g));
+}
+
+bool GlassJson::FromString(const std::string& text, CGlass& g, std::string* err) {
+    Json::Reader reader;             // 旧版解析器
+    Json::Value j;
+    bool ok = reader.parse(text, j, /*collectComments*/ false);
+    if (!ok) {
+        if (err) *err = reader.getFormatedErrorMessages();
+        return false;
+    }
+    FromJson(j, g);
+    return true;
+}

--
Gitblit v1.9.3