//******************* //A20.05.28.0 取得目前空BOX數量 並同時回復是否執行成功 private (List <CassetteData> emptyBox, bool isSuccess) GetTotalEmptyBoxNumber() { List <CassetteData> emptyBox_ = new List <CassetteData>(); bool isSuccess_ = false; try { emptyBox_ = cassette_dataBLL.loadCassetteData(). Where(data => data.CSTID == "" && scApp.TransferService.isUnitType(data.Carrier_LOC, UnitType.SHELF) ).ToList(); if (emptyBox_ != null) { isSuccess_ = true; } } catch (Exception ex) { logger.Error(ex, "Exception:"); emptyBoxLogger.Error(ex, DateTime.Now.ToString("HH:mm:ss.fff ") + "[GetTotalEmptyBoxNumber]"); } return(emptyBox_, isSuccess_); }
public void CheckTheEmptyBoxStockLevel() { emptyBoxLogger.Info("[CheckTheEmptyBoxStockLevel]"); zoneDatas = zoneBLL.loadZoneData(); boxDatas = cassette_dataBLL.loadCassetteData(); shelfDatas = shelfDefBLL.LoadShelf(); var emptyBox = GetTotalEmptyBoxNumber(); if (!initializedFlag) { zoneCacheDatas = new List <ZoneDef>(zoneDatas); foreach (var zoneCache in zoneCacheDatas) { zoneCache.EmptyBoxList = new List <string>(); zoneCache.SolidBoxList = new List <string>(); zoneCache.WaitForRecycleBoxList = new List <string>(); } initializedFlag = true; emptyBoxLogger.Info("===== EmptyBoxHandlerService initialized ====="); } //更新zone內的空箱實箱列表 UpdateZoneData(); //2020/06/22 Hsinyu Chang //A. 高水位檢查: 30秒一次 //A1: zone內有沒有已經標記成待退的空box,有則跳過這次檢查 //A2: 檢查是否達緊急水位,有則強制送往STK // A2-1: 如果沒有STK可以送,就送往其他OHB // A2-2: 連其他OHB也送不過去,呼叫MCS幫忙(to A3) //A3: 檢查是否達高水位,是則請求MCS幫退空box //B. 低水位檢查: 2分鐘一次 //B1: 先確認目前的line 上shelf的空box 是否夠用(目前標準為AGV station 數量) //B2: 檢查各個zone是否需要補空box //高水位檢查 foreach (ZoneDef zoneData in zoneCacheDatas) { //A1: zone內有沒有已經標記成待退的空box,有則跳過這次檢查 if (zoneData.WaitForRecycleBoxList.Count() != 0) { continue; } //A2: 檢查是否達緊急水位,有則強制送往STK,沒有STK就送往OHCV if (zoneData.BoxCount > zoneData.ZoneSize * emergencyWaterLevel) { //已達緊急水位,產生往Loop or STK的manual command退box emptyBoxLogger.Info($"{zoneData.ZoneID} reaches emergency water level: {zoneData.ZoneSize * emergencyWaterLevel}, force to send empty box to STK or OHCV..."); //找out mode下的STK port,沒有就找out mode下的OHCV port string dest = scApp.TransferService.GetSTKorOHCV_OutModePortName(); if (string.IsNullOrWhiteSpace(dest) == false) { string recycleBoxID = FindBestRecycleBoxID(zoneData, emptyBox.emptyBox); string recycleBoxLoc = cassette_dataBLL.GetCassetteLocByBoxID(recycleBoxID); scApp.TransferService.Manual_InsertCmd(recycleBoxLoc, dest, 5, "CheckTheEmptyBoxStockLevel", ACMD_MCS.CmdType.OHBC); } else { //沒有找到STK、OHCV為OutMode => 請求MCS幫退 emptyBoxLogger.Info($"No port is avaliable for recycling box directly, notice MCS and wait transfer command to recycling..."); RecycleBoxByMCS(zoneData, zoneData.BoxCount); } } //A3: 檢查是否達高水位,是則請求MCS幫退空box else if (zoneData.BoxCount > zoneData.HighWaterMark) { //還沒到緊急水位走這邊 //過多box,呼叫MCS退掉(優先退空的) emptyBoxLogger.Info($"{zoneData.ZoneID} do not reach emergency water level, just notice MCS and wait transfer command to recycling..."); RecycleBoxByMCS(zoneData, zoneData.BoxCount); } } //低水位檢查 if (lowLevelCheckCount < lowLevelCheckTime) { lowLevelCheckCount++; } else { lowLevelCheckCount = 0; //B1: 先確認目前的line 上shelf的空box 是否夠用(目前標準為AGV station 數量) if (emptyBox.isSuccess == true) { int requriedBoxAGV; List <CassetteData> emptyBoxList = new List <CassetteData>(emptyBox.emptyBox); var isEnoughEmptyBox = CheckIsEnoughEmptyBox(emptyBoxList.Count, out requriedBoxAGV); if (isEnoughEmptyBox.isEnough == false) { emptyBoxLogger.Info($"Not enough empty box for AGV ST use, request for empty box..."); DoSendRequireEmptyBoxToMCS(zoneCacheDatas.FirstOrDefault().ZoneID, requriedBoxAGV); } else { //B2: 檢查各個zone是否需要補空box foreach (ZoneDef zoneData in zoneCacheDatas) { if (zoneData.EmptyBoxList.Count() < zoneData.LowWaterMark) { emptyBoxLogger.Info($"{zoneData.ZoneID} has {zoneData.EmptyBoxList.Count()} empty box(es), reaches low water level: {zoneData.LowWaterMark}, request for empty box..."); //空box不足,呼叫MCS補充 DoSendRequireEmptyBoxToMCS(zoneData.ZoneID, (int)(zoneData.LowWaterMark - zoneData.EmptyBoxList.Count())); } } } } } }