chenluhua1980
2026-01-24 847a34f02bfe00475735fb5bfbefea2db28c8ad6
SourceCode/Bond/Servo/CMaster.cpp
@@ -62,6 +62,7 @@
      m_ullStartTime = 0;
      m_ullRunTime = 0;
      m_state = MASTERSTATE::READY;
      m_curveMode = CurveMode::Production;
      m_pActiveRobotTask = nullptr;
      m_nLastError = ER_CODE_NOERROR;
      m_isCompareMapsBeforeProceeding = FALSE;
@@ -118,6 +119,14 @@
         m_hEventDispatchThreadExit[1] = nullptr;
      }
      // 释放人工搬出缓冲区里的玻璃
      for (auto* pGlass : m_bufGlass) {
         if (pGlass != nullptr) {
            pGlass->release();
         }
      }
      m_bufGlass.clear();
      DeleteCriticalSection(&m_criticalSection);
   }
@@ -153,132 +162,162 @@
         LOGE("连接CC-Link失败.");
      }
      else {
            LOGI("连接CC-Link成功.");
            BoardVersion version{};
            int nRet = m_cclink.GetBoardVersion(version);
            if (nRet == 0) {
               LOGD("版本信息:%s.", version.toString().c_str());
            }
            else {
               LOGE("获取CC-Link版本信息失败.");
            }
            BoardStatus status;
            nRet = m_cclink.GetBoardStatus(status);
            if (nRet == 0) {
               LOGD("状态:%s.", status.toString().c_str());
            }
            else {
               LOGE("获取CC-Link状态失败.");
            }
         LOGI("连接CC-Link成功.");
         BoardVersion version{};
         int nRet = m_cclink.GetBoardVersion(version);
         if (nRet == 0) {
            LOGD("版本信息:%s.", version.toString().c_str());
         }
         else {
            LOGE("获取CC-Link版本信息失败.");
         }
         // 初始化添加各子设备
         CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
         CBonder* pBonder1, * pBonder2;
         CEFEM* pEfem;
         CArm* pArm;
         CArmTray* pArmTray1, * pArmTray2;
         CFliper* pFliper;
         CVacuumBake* pVacuumBake;
         CAligner* pAligner;
         CBakeCooling* pBakeCooling;
         CMeasurement* pMeasurement;
         pPort1 = addLoadPort(0);
         pPort2 = addLoadPort(1);
         pPort3 = addLoadPort(2);
         pPort4 = addLoadPort(3);
         pEfem = addEFEM();
         pArm = addArm();
         pArmTray1 = addArmTray(0);
         pArmTray2 = addArmTray(1);
         pFliper = addFliper();
         pVacuumBake = addVacuumBake();
         pAligner = addAligner();
         pBonder1 = addBonder(0);
         pBonder2 = addBonder(1);
         pBakeCooling = addBakeCooling();
         pMeasurement = addMeasurement();
         ASSERT(pEfem);
         ASSERT(pFliper);
         ASSERT(pVacuumBake);
         ASSERT(pAligner);
         ASSERT(pBonder1);
         ASSERT(pBonder2);
         ASSERT(pBakeCooling);
         ASSERT(pMeasurement);
         pEfem->setPort(0, pPort1);
         pEfem->setPort(1, pPort2);
         pEfem->setPort(2, pPort3);
         pEfem->setPort(3, pPort4);
         pEfem->setFliper(pFliper);
         pEfem->setAligner(pAligner);
         pEfem->setArmTray(0, pArmTray1);
         pEfem->setArmTray(1, pArmTray2);
         pPort1->setArm(pArm);
         pPort2->setArm(pArm);
         pPort3->setArm(pArm);
         pPort4->setArm(pArm);
         pArmTray1->setArm(pArm);
         pArmTray2->setArm(pArm);
         pFliper->setArm(pArm);
         pVacuumBake->setArm(pArm);
         pAligner->setArm(pArm);
         pBonder1->setArm(pArm);
         pBonder2->setArm(pArm);
         pBakeCooling->setArm(pArm);
         pMeasurement->setArm(pArm);
         connectEquipments();
         // 读缓存数据
         const ULONGLONG boot_cache_begin = GetTickCount64();
         const ULONGLONG boot_read_begin = GetTickCount64();
         readCache();
         LOGI("[BOOT][MASTER] readCache finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_read_begin));
         const ULONGLONG boot_state_begin = GetTickCount64();
         loadState();
         LOGI("[BOOT][MASTER] loadState finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_state_begin));
         if (m_listener.onControlJobChanged) {
            notifyControlJobChanged();
         BoardStatus status;
         nRet = m_cclink.GetBoardStatus(status);
         if (nRet == 0) {
            LOGD("状态:%s.", status.toString().c_str());
         }
         LOGI("[BOOT][MASTER] cache/state loaded, cost=%llu ms (since init %llu ms)",
            (unsigned long long)(GetTickCount64() - boot_cache_begin),
            (unsigned long long)(GetTickCount64() - boot_master_begin));
         // 定时器
         g_pMaster = this;
         SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
         // 调度线程
         m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
            0, &m_nDispatchThreadAddr);
         // 监控bit线程
         m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
            0, &m_nReadBitsThreadAddr);
         // 曲线服务
         CreateDAQBridgeServer();
         LOGI("<Master>初始化完成.");
         LOGI("[BOOT][MASTER] init finished, total cost=%llu ms",
            (unsigned long long)(GetTickCount64() - boot_master_begin));
         return 0;
         else {
            LOGE("获取CC-Link状态失败.");
         }
      }
      // 初始化添加各子设备
      CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
      CBonder* pBonder1, * pBonder2;
      CEFEM* pEfem;
      CArm* pArm;
      CArmTray* pArmTray1, * pArmTray2;
      CFliper* pFliper;
      CVacuumBake* pVacuumBake;
      CAligner* pAligner;
      CBakeCooling* pBakeCooling;
      CMeasurement* pMeasurement;
      pPort1 = addLoadPort(0);
      pPort2 = addLoadPort(1);
      pPort3 = addLoadPort(2);
      pPort4 = addLoadPort(3);
      pEfem = addEFEM();
      pArm = addArm();
      pArmTray1 = addArmTray(0);
      pArmTray2 = addArmTray(1);
      pFliper = addFliper();
      pVacuumBake = addVacuumBake();
      pAligner = addAligner();
      pBonder1 = addBonder(0);
      pBonder2 = addBonder(1);
      pBakeCooling = addBakeCooling();
      pMeasurement = addMeasurement();
      ASSERT(pEfem);
      ASSERT(pFliper);
      ASSERT(pVacuumBake);
      ASSERT(pAligner);
      ASSERT(pBonder1);
      ASSERT(pBonder2);
      ASSERT(pBakeCooling);
      ASSERT(pMeasurement);
      pEfem->setPort(0, pPort1);
      pEfem->setPort(1, pPort2);
      pEfem->setPort(2, pPort3);
      pEfem->setPort(3, pPort4);
      pEfem->setFliper(pFliper);
      pEfem->setAligner(pAligner);
      pEfem->setArmTray(0, pArmTray1);
      pEfem->setArmTray(1, pArmTray2);
      pPort1->setArm(pArm);
      pPort2->setArm(pArm);
      pPort3->setArm(pArm);
      pPort4->setArm(pArm);
      pArmTray1->setArm(pArm);
      pArmTray2->setArm(pArm);
      pFliper->setArm(pArm);
      pVacuumBake->setArm(pArm);
      pAligner->setArm(pArm);
      pBonder1->setArm(pArm);
      pBonder2->setArm(pArm);
      pBakeCooling->setArm(pArm);
      pMeasurement->setArm(pArm);
      connectEquipments();
      // 读缓存数据
      const ULONGLONG boot_cache_begin = GetTickCount64();
      const ULONGLONG boot_read_begin = GetTickCount64();
      readCache();
      LOGI("[BOOT][MASTER] readCache finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_read_begin));
      const ULONGLONG boot_state_begin = GetTickCount64();
      loadState();
      LOGI("[BOOT][MASTER] loadState finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_state_begin));
      if (m_listener.onControlJobChanged) {
         notifyControlJobChanged();
      }
      LOGI("[BOOT][MASTER] cache/state loaded, cost=%llu ms (since init %llu ms)",
         (unsigned long long)(GetTickCount64() - boot_cache_begin),
         (unsigned long long)(GetTickCount64() - boot_master_begin));
      // 定时器
      g_pMaster = this;
      SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
      // 调度线程
      m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
         0, &m_nDispatchThreadAddr);
      // 监控bit线程
      m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
         0, &m_nReadBitsThreadAddr);
      // 曲线服务
      CreateDAQBridgeServer();
      LOGI("<Master>初始化完成.");
      LOGI("[BOOT][MASTER] init finished, total cost=%llu ms",
         (unsigned long long)(GetTickCount64() - boot_master_begin));
      return 0;
   }
   void CMaster::setCurveMode(CurveMode mode)
   {
      if (m_curveMode == mode) {
         return;
      }
      m_curveMode = mode;
      if (m_pCollector != nullptr) {
         const uint32_t mids[] = {
            MID_Bonder1, MID_Bonder2,
            MID_VacuumBakeA, MID_VacuumBakeB,
            MID_BakeCoolingA, MID_BakeCoolingB
         };
         for (uint32_t mid : mids) {
            if (mode == CurveMode::EmptyChamber) {
               m_pCollector->batchStart(mid, "EMPTY_CHAMBER", 30 * 60 * 1000ULL); // 空腔模式:启动采样批次
            }
            else {
               m_pCollector->batchStop(mid);
               m_pCollector->buffersClear(mid); // 切回生产模式,清掉空腔数据
            }
         }
      }
      LOGI("<Master>CurveMode=%s", mode == CurveMode::EmptyChamber ? "EmptyChamber" : "Production");
   }
   CurveMode CMaster::getCurveMode() const
   {
      return m_curveMode;
   }
   int CMaster::term()
   {
@@ -1699,7 +1738,8 @@
               m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER ||
               m_state == MASTERSTATE::RUNNING_BATCH ||
               m_state == MASTERSTATE::STARTING);
         if (!allowSvLog) {
         const bool allowCurve = allowSvLog || (m_curveMode == CurveMode::EmptyChamber);
         if (!allowCurve) {
            return;
         }
         CSVData* pSVData = (CSVData*)pData;
@@ -1753,18 +1793,23 @@
               int paramIndex = mapping.first;
               int channel = mapping.second;
               if (paramIndex < params.size() && channel - 1 < vacuumbakeTypes.size()) {
               if (paramIndex < params.size()) {
                  auto& param = params.at(paramIndex);
                  double value = param.getDoubleValue();
                  const std::string& dataType = vacuumbakeTypes[channel - 1];
                  const std::string& paramName = param.getName();
                  const char slotTag = !paramName.empty() ? paramName[0] : '\0';
                  const int typeIndex = (slotTag == 'B') ? (channel - 8) : (channel - 1);
                  if (typeIndex < 0 || typeIndex >= (int)vacuumbakeTypes.size()) {
                     continue;
                  }
                  const int pushChannel = typeIndex + 1;
                  const std::string& dataType = vacuumbakeTypes[typeIndex];
                  if (m_pCollector != nullptr) {
                     if (slotTag == 'A')
                        m_pCollector->buffersPush(SlotToMid(eqid, 1), channel, ts, value);
                        m_pCollector->buffersPush(SlotToMid(eqid, 1), pushChannel, ts, value);
                     else if (slotTag == 'B')
                        m_pCollector->buffersPush(SlotToMid(eqid, 2), channel, ts, value);
                        m_pCollector->buffersPush(SlotToMid(eqid, 2), pushChannel, ts, value);
                  }
                  // 根据腔体前缀写入对应 Slot 的玻璃
@@ -1798,20 +1843,25 @@
               int paramIndex = mapping.first;
               int channel = mapping.second;
               if (paramIndex < params.size() && channel - 1 < coolingTypes.size()) {
               if (paramIndex < params.size()) {
                  auto& param = params.at(paramIndex);
                  double value = param.getDoubleValue();
                  const std::string& dataType = coolingTypes[channel - 1];
                  const std::string& paramName = param.getName();
                  const char slotTag = !paramName.empty() ? paramName[0] : '\0';
                  const bool paramIsBake = paramName.find("烘烤") != std::string::npos;
                  const bool paramIsCooling = paramName.find("冷却") != std::string::npos;
                  const int typeIndex = (slotTag == 'B') ? (channel - 7) : (channel - 1);
                  if (typeIndex < 0 || typeIndex >= (int)coolingTypes.size()) {
                     continue;
                  }
                  const int pushChannel = typeIndex + 1;
                  const std::string& dataType = coolingTypes[typeIndex];
                  if (m_pCollector != nullptr && paramIsBake) {
                     if (slotTag == 'A')
                        m_pCollector->buffersPush(SlotToMid(eqid, 1), channel, ts, value);
                        m_pCollector->buffersPush(SlotToMid(eqid, 1), pushChannel, ts, value);
                     else if (slotTag == 'B')
                        m_pCollector->buffersPush(SlotToMid(eqid, 3), channel, ts, value);
                        m_pCollector->buffersPush(SlotToMid(eqid, 3), pushChannel, ts, value);
                  }
                  if (!dataType.empty()) {
@@ -3519,6 +3569,15 @@
      if (pSlot == nullptr) return false;
      CGlass* pGlass = (CGlass*)pSlot->getContext();
      if (pGlass == nullptr) return false;
      // Buffer 上限为 1:新搬出时丢弃旧的
      if (!m_bufGlass.empty()) {
         for (auto* oldGlass : m_bufGlass) {
            if (oldGlass != nullptr) oldGlass->release();
         }
         m_bufGlass.clear();
      }
      m_bufGlass.push_back(pGlass);
      pGlass->addRef();
      pSlot->setContext(nullptr);
@@ -3607,14 +3666,14 @@
         auto& dataTypes = CServoUtilsTool::getEqDataTypes();
         auto& bonderTypes = dataTypes[MID_Bonder1];
         for (size_t i = 0; i < bonderTypes.size(); ++i) {
            m_pCollector->buffersSetChannelName(MID_Bonder1, i + 1, bonderTypes[i].c_str());
            m_pCollector->buffersSetChannelName(MID_Bonder2, i + 1, bonderTypes[i].c_str());
            m_pCollector->buffersSetChannelName(MID_Bonder1, (UINT)i + 1, bonderTypes[(UINT)i].c_str());
            m_pCollector->buffersSetChannelName(MID_Bonder2, (UINT)i + 1, bonderTypes[(UINT)i].c_str());
         }
         auto& vacuumbakeTypes = dataTypes[MID_VacuumBakeA];
         for (size_t i = 0; i < vacuumbakeTypes.size(); ++i) {
            m_pCollector->buffersSetChannelName(MID_VacuumBakeA, i + 1, vacuumbakeTypes[i].c_str());
            m_pCollector->buffersSetChannelName(MID_VacuumBakeB, i + 1, vacuumbakeTypes[i].c_str());
            m_pCollector->buffersSetChannelName(MID_VacuumBakeA, (UINT)i + 1, vacuumbakeTypes[(UINT)i].c_str());
            m_pCollector->buffersSetChannelName(MID_VacuumBakeB, (UINT)i + 1, vacuumbakeTypes[(UINT)i].c_str());
         }
         auto& coolingTypes = dataTypes[MID_BakeCoolingA];
@@ -3622,6 +3681,17 @@
            m_pCollector->buffersSetChannelName(MID_BakeCoolingA, i + 1, coolingTypes[i].c_str());
            m_pCollector->buffersSetChannelName(MID_BakeCoolingB, i + 1, coolingTypes[i].c_str());
         }
         if (m_curveMode == CurveMode::EmptyChamber) {
            const uint32_t mids[] = {
               MID_Bonder1, MID_Bonder2,
               MID_VacuumBakeA, MID_VacuumBakeB,
               MID_BakeCoolingA, MID_BakeCoolingB
            };
            for (uint32_t mid : mids) {
               m_pCollector->batchStart(mid, "EMPTY_CHAMBER", 10 * 60 * 1000ULL);
            }
         }
      }
   }