You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<SwappingState, IState> _dictionary = new Dictionary<SwappingState, IState>();
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<string, StepModel> StepModel =
new ConcurrentDictionary<string, StepModel>()
{
["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<BinInfoRepository>();
AmtOrderRepository = AppInfo.Container.Resolve<SwapAmtOrderRepository>();
}
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<SwapAmtOrder> amtOrderInfos = AmtOrderRepository.QueryListByClause(it =>
it.ExpireTime < DateTime.Now
&& it.Status == (byte)InfoEnum.AmtOrderStatus.Success).ToList();
if (amtOrderInfos.Count > 0)
{
List<string> binNos = amtOrderInfos.SelectMany(i => i.AmtBinNoList.Split(',').ToList()).Distinct().ToList();
List<BinInfo> 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,
}