using System.Collections.Concurrent; using Autofac; using DotNetty.Common.Utilities; using Entity.Constant; using Entity.DbModel.Station; using HybirdFrameworkCore.Autofac; using log4net; using Newtonsoft.Json; using Repository.Station; using Service.Cloud.Msg.Cloud.Req; using Service.Execute.Api; using Service.Execute.Model; using Service.Execute.Model.Tbox; using Service.Execute.StaticTools; using Service.Execute.Step; using Service.Execute.SwapException; using Service.Plc.Client; namespace Service.Execute; public class SwappingStateMachine : IDisposable { private static readonly ILog Log = LogManager.GetLogger(typeof(SwappingStateMachine)); private static readonly SwappingStateMachine SwappingMachine = new SwappingStateMachine(); private BinInfoRepository BinInfoRepository { get; set; } private SwapAmtOrderRepository AmtOrderRepository { get; set; } public bool CancelFlag { get; set; } = false; public bool StopFlag { get; set; } = false; public bool PlcSwapFlag { get; set; } = false; //手动确认换电成功 public bool ManualSwapSuccFlag { get; set; } = false; //手动确认解锁/上锁成功 public bool ManualConfirmCarUnlockFlag { get; set; } //手动确认解锁/上锁成功 public bool ManualConfirmCarLockFlag { get; set; } //plc任务异常,流程结束 public bool PLCAbnormalFlag { get; set; } public OperateModel OperateModel = null; public readonly LedTool? LedTool = null; private readonly Thread _executeThread; private readonly Dictionary _dictionary = new Dictionary(); private StateResult _result = new StateResult() { SwappingState = SwappingState.Begin }; //给云平台的实时状态 public InfoEnum.BusinessSwappingForCloudState BusinessSwappingForCloudState = InfoEnum.BusinessSwappingForCloudState.UnKnown; public DateTime BusinessSwappingStateUpdateTime = DateTime.Now; public ExceptionReason ExceptionReason = ExceptionReason.None; //换电实时状态 0:开始 1:成功 2:失败 public int? SwapStatus = null; public string SwapFailReason = ""; public int StepSort = 0; public RfidReadModel? RfidReadModel = null; public TboxCarInfoModel? BoxCarInfoModel = null; public SwapOrder? SwapOrder = null; public SwapStart? swapStart = null; public SwapOrderBatteryInfo? SwapOrderBatteryInfo = null; public ConcurrentDictionary StepModel = new ConcurrentDictionary() { ["0"] = new StepModel { StepNo = 0, Status = 0, StepName = "空闲" }, ["1"] = new StepModel { StepNo = 1, Status = 0, StepName = "车辆到站(入口雷达检测到车辆驶入)" }, ["2"] = new StepModel { StepNo = 2, Status = 0, StepName = "rfid扫描完成" }, //["3"] = new StepModel { StepNo = 3, Status = 0, StepName = "云平台车辆认证" }, ["3"] = new StepModel { StepNo = 4, Status = 0, StepName = "车辆到位" }, // ["5"] = new StepModel { StepNo = 5, Status = 0, StepName = "云平台下发换电指令" }, ["4"] = new StepModel { StepNo = 5, Status = 0, StepName = "车辆就绪和货箱举升到位" }, ["5"] = new StepModel { StepNo = 5, Status = 0, StepName = "下高压完成" }, ["6"] = new StepModel { StepNo = 5, Status = 0, StepName = "车辆解锁" }, //["6"] = new StepModel { StepNo = 6, Status = 0, StepName = "下发plc选包" }, ["7"] = new StepModel { StepNo = 6, Status = 0, StepName = "开始换电" }, ["8"] = new StepModel { StepNo = 7, Status = 0, StepName = "拆旧电池完成" }, ["9"] = new StepModel { StepNo = 8, Status = 0, StepName = "入库旧电池完成" }, ["10"] = new StepModel { StepNo = 9, Status = 0, StepName = "搬运新电池完成" }, ["11"] = new StepModel { StepNo = 10, Status = 0, StepName = "安装新电池完成" }, ["12"] = new StepModel { StepNo = 11, Status = 0, StepName = "安装完成" }, ["13"] = new StepModel { StepNo = 12, Status = 0, StepName = "车辆上锁" }, ["14"] = new StepModel { StepNo = 13, Status = 0, StepName = "换电完成(车辆驶离)" }, ["15"] = new StepModel { StepNo = 14, Status = 0, StepName = "换电失败(车辆驶离)" }, }; #region 小步状态 //雷达检测/车辆进入 public bool RadarInFlag = false; //开始读rf public bool BeginRfidReadFlag = false; //读rfid public bool RfidReadFlag = false; //云平台车辆 public bool CloudVelCheckFlag = false; //Tbox连接 public bool BoxConnectFlag = false; //车辆lock public bool BoxLocalCheckFlag = false; //车辆数据上传 public bool CloudTBoxFlag = false; //选包 public bool SelectPackFlag = false; //车辆到位 public bool VehiclesInPlaceFlag = false; //下发选包 public bool DistributeSelectPackFlag = false; //云平台下发 public bool CloudCarCanStartFlag = false; //车辆解锁 public bool VelUnlockFlag = false; //给Tbox下发开始换电 public bool StartSwapToTBoxFlag = false; public bool TboxHandUpFlag = false; public bool TboxEnergyDownFlag = false; public bool TboxDownFlag = false; public bool TboxEnergyUpFlag = false; //实体按钮 public bool PhysicalButtonState = false; //开始换电 public bool StartSwappingFlag = false; //上使能 public bool PlcHoldFlag = false; //拍照状态 public bool ChannelStatusOkFlag = false; //二次检测车 public bool VehiclesInPlace2Flag = false; //拆旧电池 public bool UnOldBatteryFlag = false; //入库旧电池 public bool StorageOldBatteryFlag = false; //搬运新电池 public bool OutNewBatteryFlag = false; //安装新电池 public bool InstallNewBatteryFlag = false; //安装完成 public bool FinishNewBatteryFlag = false; //航车回归安全位置 public bool ToSafePositionFlag = false; //车辆上锁 public bool VelLockFlag = false; //车辆离开 public bool RadarOutFlag = false; #endregion private SwappingStateMachine() { _executeThread = new Thread(Work); _executeThread.Name = "Swapping main"; _dictionary[SwappingState.Begin] = new BeginState(); _dictionary[SwappingState.StationReady] = new StationReadyState(); _dictionary[SwappingState.CarPrepare] = new CarPrepareState(); _dictionary[SwappingState.SwapCanStart] = new SwapCanStartState(); _dictionary[SwappingState.CarCtrl] = new CarCtrlState(); _dictionary[SwappingState.DoSwapping] = new DoSwappingState(); _dictionary[SwappingState.SwapDone] = new SwapDoneState(); _dictionary[SwappingState.Exception] = new ExceptionState(); _dictionary[SwappingState.Canceled] = new CancelState(); _dictionary[SwappingState.ManualSucc] = new ManualSuccState(); LedTool = new LedTool(); BinInfoRepository = AppInfo.Container.Resolve(); AmtOrderRepository = AppInfo.Container.Resolve(); } public static SwappingStateMachine GetInstance() { return SwappingMachine; } public static StateResult ReturnWithInvokeErr(InvokeStatus status, ExceptionReason exceptionReason) { if (status == InvokeStatus.Cancel) { return new StateResult() { SwappingState = SwappingState.Canceled }; } else if (status == InvokeStatus.TimeOut) { return null; } else if (status == InvokeStatus.ManualSucc) { return new StateResult() { SwappingState = SwappingState.ManualSucc }; } else if(status == InvokeStatus.Exception) { return new StateResult() { SwappingState = SwappingState.SwapDone }; } else { return StateResult.Exception(exceptionReason, null); } } private void Work() { Log.Info("State machine begin work"); while (!StopFlag) { Log.Info($"handle = {_result.SwappingState} begin"); try { StateResult? result = _dictionary[_result.SwappingState].Handle(this); if (result != null) { _result = result; } } catch (Exception e) { Log.Error($"handle {_result.SwappingState} error", e); } Log.Info($"handle = {_result.SwappingState} end"); Thread.Sleep(500); } Log.Info("State machine canceled"); } public void Stop() { StopFlag = true; CancelFlag = true; Thread.Sleep(2000); } public bool IsCanceled() { return CancelFlag; } public bool IsManualSwapSucc() { return ManualSwapSuccFlag; } public bool Start() { Reset(); _executeThread.Start(); Log.Info($"start machine ok"); return true; } public void Reset() { Log.Info("reset data"); if (PlcMgr.PlcClient?.ReadTaskNo() == 1) { PlcMgr.PlcClient?.ExChangeTaskNo(0); } ResetOrderAmtStatus(); if (RfidReadModel != null) { //wifi数据重置 TBoxApi.Reset(RfidReadModel.VelVin); TBoxApi.SetHeart("1", 1); } //重置所有小步状态 ResetStep(); ResetData(); //重置云平台下发的指令 // CloudApi.ClearCarCanStartInfo(); } public bool Cancel() { CancelFlag = true; Thread.Sleep(5000); Log.Info($"Cancel machine ok"); return true; } public bool Manual() { ManualSwapSuccFlag = true; Thread.Sleep(5000); Log.Info($"ManualSwapSuccFlag machine ok"); return true; } public bool ManualConfirmLockCar() { ManualConfirmCarLockFlag = true; Thread.Sleep(2000); Log.Info($"ManualConfirmLockCar ok"); return true; } public bool ManualConfirmUnLockCar() { ManualConfirmCarUnlockFlag = true; Thread.Sleep(2000); Log.Info($"ManualConfirmLockCar ok"); return true; } private void ResetData() { BusinessSwappingForCloudState = InfoEnum.BusinessSwappingForCloudState.Idle; BusinessSwappingStateUpdateTime = DateTime.Now; ExceptionReason = ExceptionReason.None; OperateModel = null; //换电实时状态 0:开始 1:成功 2:失败 SwapStatus = null; SwapFailReason = ""; RfidReadModel = null; BoxCarInfoModel = null; SwapOrder = null; SwapOrderBatteryInfo = null; StepSort = 0; foreach (var key in StepModel.Keys.ToList()) { StepModel[key].Status = 0; StepModel[key].StartTime = null; } PlcSwapFlag = false; ManualSwapSuccFlag = false; OperateModel = null; ManualConfirmCarUnlockFlag = false; ManualConfirmCarLockFlag = false; CancelFlag = false; StopFlag = false; PLCAbnormalFlag=false; } private void ResetStep() { RadarInFlag = false; BeginRfidReadFlag = false; RfidReadFlag = false; CloudVelCheckFlag = false; BoxConnectFlag = false; BoxLocalCheckFlag = false; CloudTBoxFlag = false; SelectPackFlag = false; VehiclesInPlaceFlag = false; DistributeSelectPackFlag = false; CloudCarCanStartFlag = false; VelUnlockFlag = false; StartSwappingFlag = false; PlcHoldFlag = false; ChannelStatusOkFlag = false; VehiclesInPlace2Flag = false; UnOldBatteryFlag = false; StorageOldBatteryFlag = false; OutNewBatteryFlag = false; InstallNewBatteryFlag = false; FinishNewBatteryFlag = false; ToSafePositionFlag = false; VelLockFlag = false; RadarOutFlag = false; StartSwapToTBoxFlag = false; TboxHandUpFlag = false; TboxEnergyDownFlag = false; TboxDownFlag = false; TboxEnergyUpFlag = false; } //关于仓库锁定相关重置 private void ResetOrderAmtStatus() { //仓库解锁 解锁两个 if (SwapOrderBatteryInfo != null) { if (SwapOrderBatteryInfo?.UpBinInfo != null) ; { BinInfoRepository.Update(i => i.AmtLock == (int)InfoEnum.AmtBatLockStatus.UnLock, i => i.Id == SwapOrderBatteryInfo.UpBinInfo[0].Id); BinInfoRepository.Update(i => i.AmtLock == (int)InfoEnum.AmtBatLockStatus.UnLock, i => i.Id == SwapOrderBatteryInfo.UpBinInfo[1].Id); } } //预约单 List amtOrderInfos = AmtOrderRepository.QueryListByClause(it => it.ExpireTime < DateTime.Now && it.Status == (byte)InfoEnum.AmtOrderStatus.Success).ToList(); if (amtOrderInfos.Count > 0) { List binNos = amtOrderInfos.SelectMany(i => i.AmtBinNoList.Split(',').ToList()).Distinct().ToList(); List listByClause = BinInfoRepository.QueryListByClause(i => binNos.Contains(i.No)); foreach (var binInfo in listByClause) { binInfo.AmtLock = (int)InfoEnum.AmtBatLockStatus.UnLock; } BinInfoRepository.Update(listByClause); } } public void Dispose() { StopFlag = true; CancelFlag = true; Thread.Sleep(2000); } } public enum SwappingState { Begin, StationReady, CarPrepare, SwapCanStart, CarCtrl, DoSwapping, SwapDone, Exception, Canceled, ManualSucc, }