From 8d4702885aebbeff0a2f472660e89d34777a0783 Mon Sep 17 00:00:00 2001 From: lxw Date: Tue, 21 May 2024 11:22:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8D=A2=E7=94=B5=E4=B8=BB=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=20=20StationReady?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Entity/Api/Req/AddSwapOrderReq.cs | 20 +- Entity/Api/Req/ModifySwapOrderReq.cs | 4 +- Entity/Api/Req/QueryChargeOrderReq.cs | 17 +- Entity/Api/Req/QuerySwapOrderPageReq.cs | 8 +- Entity/Api/Resp/ChargeOrderResp.cs | 2 +- Entity/Constant/StationConstant.cs | 63 +++ .../Station/SwapOrderBatteryRepository.cs | 14 + Repository/Station/SwapOrderRepository.cs | 14 + Repository/Station/SwapOrderStepRepository.cs | 14 + Service/Execute/Api/CloudApi.cs | 6 + Service/Execute/Api/PlcApi.cs | 36 ++ Service/Execute/Api/RfidApi.cs | 78 +++ Service/Execute/Api/TboxApi.cs | 6 + Service/Execute/Enum/InfoEnum.cs | 95 ++++ Service/Execute/Enum/SwapOrderNoGenerator.cs | 20 + Service/Execute/IState.cs | 9 + Service/Execute/Invoker.cs | 167 ++++++ Service/Execute/Model/RfidReadModel.cs | 31 + Service/Execute/StateResult.cs | 23 + Service/Execute/StaticTools/LedReference.cs | 529 ++++++++++++++++++ Service/Execute/StaticTools/LedTool.cs | 159 ++++++ Service/Execute/StaticTools/SoundReference.cs | 145 +++++ Service/Execute/StaticTools/SoundTool.cs | 159 ++++++ Service/Execute/StationSoftMgr.cs | 31 + Service/Execute/Step/BeginState.cs | 14 + Service/Execute/Step/CancelState.cs | 14 + Service/Execute/Step/CarCtrlState.cs | 14 + Service/Execute/Step/CarPrepareState.cs | 14 + Service/Execute/Step/DoSwappingState.cs | 14 + Service/Execute/Step/ExceptionState.cs | 14 + Service/Execute/Step/SelectPackState.cs | 14 + Service/Execute/Step/StationReadyState.cs | 219 ++++++++ Service/Execute/Step/SwapDoneState.cs | 14 + .../Execute/SwapException/ExceptionData.cs | 9 + .../Execute/SwapException/ExceptionReason.cs | 23 + Service/Execute/SwappingStateMachine.cs | 208 +++++++ Service/Execute/Tech/InfoAttribute.cs | 60 ++ Service/Execute/Tech/RemarkAttribute.cs | 37 ++ Service/Init/StaticStationInfo.cs | 19 + Service/Service.csproj | 4 + .../Controllers/ChargeOrderController.cs | 2 +- WebStarter/Controllers/SwapOrderController.cs | 6 +- WebStarter/Controllers/Test/GenController.cs | 7 +- .../Test/WeatherForecastController.cs | 2 +- WebStarter/Program.cs | 1 - 45 files changed, 2321 insertions(+), 38 deletions(-) create mode 100644 Entity/Constant/StationConstant.cs create mode 100644 Repository/Station/SwapOrderBatteryRepository.cs create mode 100644 Repository/Station/SwapOrderRepository.cs create mode 100644 Repository/Station/SwapOrderStepRepository.cs create mode 100644 Service/Execute/Api/CloudApi.cs create mode 100644 Service/Execute/Api/PlcApi.cs create mode 100644 Service/Execute/Api/RfidApi.cs create mode 100644 Service/Execute/Api/TboxApi.cs create mode 100644 Service/Execute/Enum/InfoEnum.cs create mode 100644 Service/Execute/Enum/SwapOrderNoGenerator.cs create mode 100644 Service/Execute/IState.cs create mode 100644 Service/Execute/Invoker.cs create mode 100644 Service/Execute/Model/RfidReadModel.cs create mode 100644 Service/Execute/StateResult.cs create mode 100644 Service/Execute/StaticTools/LedReference.cs create mode 100644 Service/Execute/StaticTools/LedTool.cs create mode 100644 Service/Execute/StaticTools/SoundReference.cs create mode 100644 Service/Execute/StaticTools/SoundTool.cs create mode 100644 Service/Execute/StationSoftMgr.cs create mode 100644 Service/Execute/Step/BeginState.cs create mode 100644 Service/Execute/Step/CancelState.cs create mode 100644 Service/Execute/Step/CarCtrlState.cs create mode 100644 Service/Execute/Step/CarPrepareState.cs create mode 100644 Service/Execute/Step/DoSwappingState.cs create mode 100644 Service/Execute/Step/ExceptionState.cs create mode 100644 Service/Execute/Step/SelectPackState.cs create mode 100644 Service/Execute/Step/StationReadyState.cs create mode 100644 Service/Execute/Step/SwapDoneState.cs create mode 100644 Service/Execute/SwapException/ExceptionData.cs create mode 100644 Service/Execute/SwapException/ExceptionReason.cs create mode 100644 Service/Execute/SwappingStateMachine.cs create mode 100644 Service/Execute/Tech/InfoAttribute.cs create mode 100644 Service/Execute/Tech/RemarkAttribute.cs create mode 100644 Service/Init/StaticStationInfo.cs diff --git a/Entity/Api/Req/AddSwapOrderReq.cs b/Entity/Api/Req/AddSwapOrderReq.cs index e5600cd..02d7951 100644 --- a/Entity/Api/Req/AddSwapOrderReq.cs +++ b/Entity/Api/Req/AddSwapOrderReq.cs @@ -1,8 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using Entity.DbModel.Station; -using SqlSugar; - -namespace Entity.Api.Resp +namespace Entity.Api.Req { /// ///新增换电订单 @@ -17,28 +13,28 @@ namespace Entity.Api.Resp /// Default: /// Nullable:True /// - public string Sn {get;set;} + public string? Sn {get;set;} /// /// Desc:车牌号 /// Default: /// Nullable:True /// - public string VehicleNo {get;set;} + public string? VehicleNo {get;set;} /// /// Desc:车辆mac /// Default: /// Nullable:True /// - public string VehicleMac {get;set;} + public string? VehicleMac {get;set;} /// /// Desc:车辆vin码 /// Default: /// Nullable:True /// - public string VehicleVin {get;set;} + public string? VehicleVin {get;set;} /// /// Desc:车辆进场时间 @@ -80,7 +76,7 @@ namespace Entity.Api.Resp /// Default: /// Nullable:True /// - public string FailReason {get;set;} + public string? FailReason {get;set;} /// /// Desc:上传云平台状态;0-未上传;1-已上传 @@ -94,7 +90,7 @@ namespace Entity.Api.Resp /// Default: /// Nullable:True /// - public string CreatedBy {get;set;} + public string? CreatedBy {get;set;} /// /// Desc:创建时间 @@ -108,7 +104,7 @@ namespace Entity.Api.Resp /// Default: /// Nullable:True /// - public string UpdatedBy {get;set;} + public string? UpdatedBy {get;set;} /// /// Desc:更新时间 diff --git a/Entity/Api/Req/ModifySwapOrderReq.cs b/Entity/Api/Req/ModifySwapOrderReq.cs index a6609cd..7519375 100644 --- a/Entity/Api/Req/ModifySwapOrderReq.cs +++ b/Entity/Api/Req/ModifySwapOrderReq.cs @@ -1,8 +1,6 @@ using System.ComponentModel.DataAnnotations; -using Entity.DbModel.Station; -using SqlSugar; -namespace Entity.Api.Resp +namespace Entity.Api.Req { /// ///新增换电订单 diff --git a/Entity/Api/Req/QueryChargeOrderReq.cs b/Entity/Api/Req/QueryChargeOrderReq.cs index 2811f15..87128f0 100644 --- a/Entity/Api/Req/QueryChargeOrderReq.cs +++ b/Entity/Api/Req/QueryChargeOrderReq.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using HybirdFrameworkCore.Entity; using SqlSugar; namespace Entity.Api.Req @@ -6,7 +7,7 @@ namespace Entity.Api.Req /// ///查询充电订单 /// - public class QueryChargeOrderReq + public class QueryChargeOrderReq :QueryPageModel { @@ -16,14 +17,14 @@ namespace Entity.Api.Req /// Default: /// Nullable:True /// - public string Sn {get;set;} + public string? Sn {get;set;} /// /// Desc:电池编号 /// Default: /// Nullable:True /// - public string BatteryNo {get;set;} + public string? BatteryNo {get;set;} @@ -32,14 +33,14 @@ namespace Entity.Api.Req /// Default: /// Nullable:True /// - public string ChargerNo {get;set;} + public string? ChargerNo {get;set;} /// /// Desc:充电枪编号 /// Default: /// Nullable:True /// - public string ChargerGunNo {get;set;} + public string? ChargerGunNo {get;set;} /// /// Desc:充电开始时间 @@ -74,7 +75,7 @@ namespace Entity.Api.Req /// Default: /// Nullable:True /// - public string ChargeTimeCount {get;set;} + public string? ChargeTimeCount {get;set;} /// /// Desc:充电电量 @@ -118,14 +119,14 @@ namespace Entity.Api.Req /// Default: /// Nullable:True /// - public string ElecPriceModelVersion {get;set;} + public string? ElecPriceModelVersion {get;set;} /// /// Desc:换电订单编号 /// Default: /// Nullable:True /// - public string SwapOrderSn {get;set;} + public string? SwapOrderSn {get;set;} /// /// Desc:上传云平台状态;0-未上传;1-已上传 diff --git a/Entity/Api/Req/QuerySwapOrderPageReq.cs b/Entity/Api/Req/QuerySwapOrderPageReq.cs index a51554d..3344aed 100644 --- a/Entity/Api/Req/QuerySwapOrderPageReq.cs +++ b/Entity/Api/Req/QuerySwapOrderPageReq.cs @@ -9,28 +9,28 @@ public class QuerySwapOrderPageReq : QueryPageModel /// Default: /// Nullable:True /// - public string Sn { get; set; } + public string? Sn { get; set; } /// /// Desc:车牌号 /// Default: /// Nullable:True /// - public string VehicleNo { get; set; } + public string? VehicleNo { get; set; } /// /// Desc:车辆mac /// Default: /// Nullable:True /// - public string VehicleMac { get; set; } + public string? VehicleMac { get; set; } /// /// Desc:车辆vin码 /// Default: /// Nullable:True /// - public string VehicleVin { get; set; } + public string? VehicleVin { get; set; } /// diff --git a/Entity/Api/Resp/ChargeOrderResp.cs b/Entity/Api/Resp/ChargeOrderResp.cs index 981a0dc..473d33c 100644 --- a/Entity/Api/Resp/ChargeOrderResp.cs +++ b/Entity/Api/Resp/ChargeOrderResp.cs @@ -41,7 +41,7 @@ namespace Entity.Api.Resp /// Default: /// Nullable:True /// - public string ChargerNo {get;set;} + public string? ChargerNo {get;set;} /// /// Desc:充电枪编号 diff --git a/Entity/Constant/StationConstant.cs b/Entity/Constant/StationConstant.cs new file mode 100644 index 0000000..9443856 --- /dev/null +++ b/Entity/Constant/StationConstant.cs @@ -0,0 +1,63 @@ +using System.ComponentModel; +using System.Reflection; + +namespace Entity.Constant; + +public class StationConstant +{ + /// + /// 换电站状态: 1:营运中 2:歇业中 3:设备维护状态 4:暂停营业 + /// + public enum StationStatus + { + + [Description("营运中")] + Run=1, + [Description("歇业中")] + Stop, + [Description("设备维护")] + Repair, + [Description("暂停营业")] + Suspend, + + + } + /// + /// 换电方式:1:自动换电 2:手动换电 + /// + public enum StationWay + { + + [Description("自动换电")] + Auto=1, + [Description("手动换电")] + Manual, + + } + /// + /// 换电模式:1:本地换电 2:远程换电 + /// + public enum StationModel + { + + [Description("本地换电")] + Local=1, + [Description("远程换电、云平台参与")] + Remote, + + } + + public static class EnumExtensions + { + public static string GetDescription( Enum value) + { + FieldInfo field = value.GetType().GetField(value.ToString()); + + DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; + + return attribute == null ? value.ToString() : attribute.Description; + } + } + + +} \ No newline at end of file diff --git a/Repository/Station/SwapOrderBatteryRepository.cs b/Repository/Station/SwapOrderBatteryRepository.cs new file mode 100644 index 0000000..880786c --- /dev/null +++ b/Repository/Station/SwapOrderBatteryRepository.cs @@ -0,0 +1,14 @@ +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using SqlSugar; + +namespace Repository.Station; + +[Scope("SingleInstance")] +public class SwapOrderBatteryRepository:BaseRepository +{ + + public SwapOrderBatteryRepository(ISqlSugarClient sqlSugar) : base(sqlSugar) + { + } +} \ No newline at end of file diff --git a/Repository/Station/SwapOrderRepository.cs b/Repository/Station/SwapOrderRepository.cs new file mode 100644 index 0000000..1d80947 --- /dev/null +++ b/Repository/Station/SwapOrderRepository.cs @@ -0,0 +1,14 @@ +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using SqlSugar; + +namespace Repository.Station; + +[Scope("SingleInstance")] +public class SwapOrderRepository:BaseRepository +{ + + public SwapOrderRepository(ISqlSugarClient sqlSugar) : base(sqlSugar) + { + } +} \ No newline at end of file diff --git a/Repository/Station/SwapOrderStepRepository.cs b/Repository/Station/SwapOrderStepRepository.cs new file mode 100644 index 0000000..9c03534 --- /dev/null +++ b/Repository/Station/SwapOrderStepRepository.cs @@ -0,0 +1,14 @@ +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using SqlSugar; + +namespace Repository.Station; + +[Scope("SingleInstance")] +public class SwapOrderStepRepository:BaseRepository +{ + + public SwapOrderStepRepository(ISqlSugarClient sqlSugar) : base(sqlSugar) + { + } +} \ No newline at end of file diff --git a/Service/Execute/Api/CloudApi.cs b/Service/Execute/Api/CloudApi.cs new file mode 100644 index 0000000..8745576 --- /dev/null +++ b/Service/Execute/Api/CloudApi.cs @@ -0,0 +1,6 @@ +namespace Service.Execute.Api; + +public class CloudApi +{ + +} \ No newline at end of file diff --git a/Service/Execute/Api/PlcApi.cs b/Service/Execute/Api/PlcApi.cs new file mode 100644 index 0000000..3f5b381 --- /dev/null +++ b/Service/Execute/Api/PlcApi.cs @@ -0,0 +1,36 @@ +using Service.Init.Entity; + +namespace Service.Execute.Api; + +public class PlcApi +{ + /// + /// 是否远程模式 + /// + /// + public static bool IsRemote() + { + + return true; + } + + /// + /// 入口雷达检测 + /// + /// + public static bool EntranceRadar() + { + //TODO:: + return true; + } + + /// + /// 出口雷达检测 + /// + /// + public static bool ExitRadar() + { + //TODO:: + return true; + } +} \ No newline at end of file diff --git a/Service/Execute/Api/RfidApi.cs b/Service/Execute/Api/RfidApi.cs new file mode 100644 index 0000000..26f0802 --- /dev/null +++ b/Service/Execute/Api/RfidApi.cs @@ -0,0 +1,78 @@ +using log4net; +using Newtonsoft.Json; +using Swapping.Business.Rfid; + +namespace Service.Execute.Api; + +public class RfidApi +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(RfidApi)); + //TODO::Rfid 服务地址 + private static readonly string BASE_URL = "http://localhost:7243"; + + private static readonly HttpClient _httpClient = new HttpClient() + { + Timeout = TimeSpan.FromSeconds(60) + }; + + public static async Task BeginRead() + { + Log.Info("BeginRead"); + string url = BASE_URL + "/Api/BeginRead"; + try + { + string s = await _httpClient.GetStringAsync(url); + Log.Info($"BeginRead resp = {s}"); + return bool.Parse(s); + } + catch (Exception e) + { + Console.WriteLine(e); + return false; + } + } + + public static async Task StopRead() + { + Log.Info("StopRead"); + string url = BASE_URL + "/Api/StopRead"; + try + { + string s = await _httpClient.GetStringAsync(url); + Log.Info($"StopRead resp = {s}"); + return bool.Parse(s); + } + catch (Exception e) + { + Console.WriteLine(e); + return false; + } + } + + public static async Task ReadRifd() + { + Log.Info("ReadRifd"); + string url = BASE_URL + "/Api/ReadRfidData"; + try + { + string s = await _httpClient.GetStringAsync(url); + Log.Info($"ReadRifd resp={s}"); + if (s != String.Empty) + { + RfidReadModel? model = JsonConvert.DeserializeObject(s); + if (model != null) + { + return model; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + return null; + } + + return null; + } + +} \ No newline at end of file diff --git a/Service/Execute/Api/TboxApi.cs b/Service/Execute/Api/TboxApi.cs new file mode 100644 index 0000000..b0817c4 --- /dev/null +++ b/Service/Execute/Api/TboxApi.cs @@ -0,0 +1,6 @@ +namespace Service.Execute.Api; + +public class TBoxApi +{ + +} \ No newline at end of file diff --git a/Service/Execute/Enum/InfoEnum.cs b/Service/Execute/Enum/InfoEnum.cs new file mode 100644 index 0000000..c93d07c --- /dev/null +++ b/Service/Execute/Enum/InfoEnum.cs @@ -0,0 +1,95 @@ +using Service.Execute.Tech; +using Swapping.Business.Tech; + +namespace Service.Execute.Enum; + +public class InfoEnum +{ + public enum SwapInfo : ushort + { + [Info("Rfid读写失败", "Rfid读写失败")] ErrorReadRfid = 1, + [Info("车辆进站", "车辆进站")] InfoCarIn = 2, + + [Info("Tbox连接失败", "Tbox连接失败,请联系站务人员")] ErrorTBoxConn = 4, + [Info("云端校验失败", "云端校验失败,请联系站务人员")] ErrorCloudCheck = 5, + [Info("车辆已到位", "车辆已到位")] InfoCarInPosition = 6, + [Info("车辆到位超时", "车辆到位超时")] ErrorCarInPositionTimeout = 7, + [Info("云平台下发换电失败", "云平台下发换电超时")] CloudSendSwapError = 8, + + + [Info("自由度调整,挂N挡,拉手刹", "自由度调整,挂N挡,拉手刹")] + InfoCarPrepare = 9, + [Info("自由度调整超时", "自由度调整超时")] ErrorCarPrepareTimeout = 10, + [Info("请选择更换电池数量", "请选择更换电池数量")] InfoSelectPack = 11, + [Info("选包失败,请驶离", "选包失败,请驶离")] ErrorSelectPack = 12, + + [Info("下高压失败,请联系站务人员", "下高压失败,请联系站务人员")] + ErrorHvPwrOff = 13, + + [Info("下低压失败,请联系站务人员", "下低压失败,请联系站务人员")] + ErrorLvPwrOff = 14, + [Info("电池拆卸中,请稍后", "电池拆卸中,请稍后")] InfoUnPack = 15, + [Info("电池安装中,请稍后", "电池安装中,请稍后")] InfoPack = 16, + [Info("电池包已安装完成", "电池包已安装完成")] InfoPackFinish = 17, + [Info("车辆自检中,请稍后", "车辆自检中,请稍后")] InfoSelfCheck = 18, + [Info("自检失败,请联系站务人员", "自检失败,请联系站务人员")] ErrorSelfCheck = 19, + [Info("换电已完成,请驶离", "换电已完成,请驶离")] InfoCarLeave = 20, + } + + public enum SelectBinStatusInfo : byte + { + [Remark("通道的电池仓无换电电池")] NoBattery, + [Remark("可以换电")] Success, + [Remark("结束充电电池数量不足")] LessOfFinishCharging, + [Remark("空仓不够放")] LessOfEmptyBin, + [Remark("符合soc限制数量不足")] LessOfSoc, + [Remark("结束充电大于3分钟的数量不足")] LessOf3Minute, + [Remark("各种差数量不足")] LessOfMean, + [Remark("未被预约数量不足")] LessOfUnAmt, + [Remark("预约电池异常")] AmtError, + [Remark("电池捆绑选包失败")] GroupError, + [Remark("无可用捆绑")] NoGroupError + } + + //1:预约成功;2:预约取消;3:预约失败;4:换电完成;5:换电失败 + public enum AmtOrderStatus : byte + { + [Remark("预约成功")] Success = 1, + [Remark("预约取消")] Cancel = 2, + [Remark("预约失败")] Fail = 3, + [Remark("换电完成")] SwapFinish = 4, + [Remark("换电失败")] SwapFail = 5, + [Remark("换电中")] Swapping = 6, + [Remark("预约失败")] Expire = 7, + } + + public enum BusinessSwappingState : byte + { + [Remark("未知")] UnKnown, + [Remark("空闲")] Idle, + [Remark("RFID扫描完成")] ScanRfid, + [Remark("云平台验证完成")] CloudCheck, + [Remark("车辆到位")] CarInPosition, + [Remark("车辆准备完成(N档、手刹)")] CarPrepare, + [Remark("云平台启动换电完成")] CloudBeginSwap, + [Remark("车辆调整完成(下高压、下低压)")] CarAdjust, + [Remark("开始换电")] BeginSwap, + [Remark("拆卸亏电包")] UnPack, + [Remark("安装满电包")] Pack, + [Remark("包安装完成")] PackFinish, + [Remark("车辆自检")] CarSelfCheck, + [Remark("换电完成(车辆驶离)")] SwapDone + } + + public enum AmtBatLockStatus : byte + { + UnLock = 0, + Lock = 1 + } + + public enum SwapOrderResult : byte + { + Success = 0, + Fail = 1 + } +} \ No newline at end of file diff --git a/Service/Execute/Enum/SwapOrderNoGenerator.cs b/Service/Execute/Enum/SwapOrderNoGenerator.cs new file mode 100644 index 0000000..75f4f83 --- /dev/null +++ b/Service/Execute/Enum/SwapOrderNoGenerator.cs @@ -0,0 +1,20 @@ +namespace Swapping.Business.Common; + +public class SwapOrderNoGenerator +{ + private static UInt16 Seq = 0; + private static Object Locker = new object(); + + public static string GenerateOrderNo(string stationNo) + { + lock (Locker) + { + if (Seq > 9999) + { + Seq = 0; + } + + return $"{stationNo}{DateTime.Now.ToString("yyyyMMddHHmmss")}{Seq++.ToString().PadLeft(6, '0')}"; + } + } +} \ No newline at end of file diff --git a/Service/Execute/IState.cs b/Service/Execute/IState.cs new file mode 100644 index 0000000..79cade5 --- /dev/null +++ b/Service/Execute/IState.cs @@ -0,0 +1,9 @@ + + +namespace Service.Execute; + +public interface IState +{ + public StateResult? Handle(SwappingStateMachine machine); + +} \ No newline at end of file diff --git a/Service/Execute/Invoker.cs b/Service/Execute/Invoker.cs new file mode 100644 index 0000000..c371974 --- /dev/null +++ b/Service/Execute/Invoker.cs @@ -0,0 +1,167 @@ +using log4net; + +namespace Service.Execute; + +public class Invoker +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(Invoker)); + + public static InvokeStatus Invoke(string name, int duration, int times, Func cancel, Func done, + Action doAction, + Action timeoutAction, bool isTimeOutExit) + { + int hvPwrOffTimes = 0; + while (!done()) + { + Log.Info($"begin {name}"); + Thread.Sleep(duration); + if (cancel()) + { + Log.Info($" {name} canceled"); + return InvokeStatus.Cancel; + } + + try + { + doAction(); + } + catch (Exception e) + { + Log.Error($"{name}", e); + } + + if (hvPwrOffTimes++ > times) + { + timeoutAction(); + Log.Info($" {name} timeout"); + if (isTimeOutExit) + { + return InvokeStatus.TimeOut; + } + } + } + + Log.Info($" {name} done"); + return InvokeStatus.Done; + } + + public static InvokeStatus Invoke(string name, int duration, int times, Func cancel, Func done, + Action doAction, + Action timeoutAction, bool isTimeOutExit, Action exceptionAction) + { + int hvPwrOffTimes = 0; + while (!done()) + { + Log.Info($"begin {name}"); + Thread.Sleep(duration); + if (cancel()) + { + Log.Info($" {name} canceled"); + return InvokeStatus.Cancel; + } + + try + { + doAction(); + } + catch (Exception e) + { + Log.Error($"{name}", e); + exceptionAction(); + } + + if (hvPwrOffTimes++ > times) + { + timeoutAction(); + Log.Info($" {name} timeout"); + if (isTimeOutExit) + { + return InvokeStatus.TimeOut; + } + } + } + + Log.Info($" {name} done"); + return InvokeStatus.Done; + } + + + public static InvokeStatus Invoke(string name, int duration, int times, Func cancel, Func done, + Action doAction, + Action timeoutAction, bool isTimeOutExit, Action exceptionAction, int timeOutActionTime,InvokeStatus timeOutException) + { + int count = 0; + while (!done()) + { + Log.Info($"begin {name}"); + Thread.Sleep(duration); + if (cancel()) + { + Log.Info($" {name} canceled"); + return InvokeStatus.Cancel; + } + + try + { + doAction(); + } + catch (Exception e) + { + Log.Error($"{name}", e); + exceptionAction(); + } + + if (count++ > times) + { + if (count % timeOutActionTime == 0) + { + timeoutAction(); + Log.Info($" {name} timeout"); + if (isTimeOutExit) + { + return timeOutException; + } + } + } + } + + Log.Info($" {name} done"); + return InvokeStatus.Done; + } + + public static InvokeStatus Invoke(string name, int duration, int times, Func cancel, Func done, + Action doAction) + { + int hvPwrOffTimes = 0; + while (!done()) + { + Log.Info($"begin {name}"); + Thread.Sleep(duration); + if (cancel()) + { + Log.Info($" {name} canceled"); + return InvokeStatus.Cancel; + } + + try + { + doAction(); + } + catch (Exception e) + { + Log.Error($"{name}", e); + } + } + + Log.Info($" {name} done"); + return InvokeStatus.Done; + } +} + +public enum InvokeStatus +{ + Cancel, + TimeOut, + Done, + Exception +} \ No newline at end of file diff --git a/Service/Execute/Model/RfidReadModel.cs b/Service/Execute/Model/RfidReadModel.cs new file mode 100644 index 0000000..e4115f1 --- /dev/null +++ b/Service/Execute/Model/RfidReadModel.cs @@ -0,0 +1,31 @@ +namespace Swapping.Business.Rfid; + +public class RfidReadModel +{ + public string Result { get; set; } + + /// + /// 车辆VIN码 + /// + public string VelVin { get; set; } + + /// + /// 车辆电池包数 + /// + public string BattNum { set; get; } + + /// + /// 车辆配方-加解锁高度,整型,单位:mm + /// + public string VelRecp { set; get; } + + /// + /// 车辆MAC地址 + /// + public string VelMac { set; get; } + + /// + /// 车辆车牌号 + /// + public string VelNo { set; get; } +} \ No newline at end of file diff --git a/Service/Execute/StateResult.cs b/Service/Execute/StateResult.cs new file mode 100644 index 0000000..c62dd53 --- /dev/null +++ b/Service/Execute/StateResult.cs @@ -0,0 +1,23 @@ +using Service.Execute.SwapException; + +namespace Service.Execute; + +public class StateResult +{ + public static readonly StateResult Cancel = new() { SwappingState = SwappingState.Canceled }; + public SwappingState SwappingState { get; set; } + public Object Model { get; set; } + + public static StateResult Exception(ExceptionReason exceptionReason, string msg) + { + return new StateResult() + { + SwappingState = SwappingState.Exception, + Model = new ExceptionData() + { + ExceptionReason = exceptionReason, + Msg = msg + } + }; + } +} \ No newline at end of file diff --git a/Service/Execute/StaticTools/LedReference.cs b/Service/Execute/StaticTools/LedReference.cs new file mode 100644 index 0000000..da23dfe --- /dev/null +++ b/Service/Execute/StaticTools/LedReference.cs @@ -0,0 +1,529 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// +// 对此文件的更改可能导致不正确的行为,并在以下条件下丢失: +// 代码重新生成。 +// +//------------------------------------------------------------------------------ + +namespace ServiceReferenceLed +{ + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReferenceLed.WebServiceLedSoap")] + public interface WebServiceLedSoap + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/LedConnect", ReplyAction="*")] + System.Threading.Tasks.Task LedConnectAsync(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/LedDisConnect", ReplyAction="*")] + System.Threading.Tasks.Task LedDisConnectAsync(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/GetLedConnectedSts", ReplyAction="*")] + System.Threading.Tasks.Task GetLedConnectedStsAsync(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/WriteWelcome", ReplyAction="*")] + System.Threading.Tasks.Task WriteWelcomeAsync(ServiceReferenceLed.WriteWelcomeRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/WriteContent", ReplyAction="*")] + System.Threading.Tasks.Task WriteContentAsync(ServiceReferenceLed.WriteContentRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/WriteProgramContent", ReplyAction="*")] + System.Threading.Tasks.Task WriteProgramContentAsync(ServiceReferenceLed.WriteProgramContentRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/WriteProgramWelcome", ReplyAction="*")] + System.Threading.Tasks.Task WriteProgramWelcomeAsync(ServiceReferenceLed.WriteProgramWelcomeRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/WriteClearScreen", ReplyAction="*")] + System.Threading.Tasks.Task WriteClearScreenAsync(); + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteWelcomeRequest + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteWelcome", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteWelcomeRequestBody Body; + + public WriteWelcomeRequest() + { + } + + public WriteWelcomeRequest(ServiceReferenceLed.WriteWelcomeRequestBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute(Namespace="http://tempuri.org/")] + public partial class WriteWelcomeRequestBody + { + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=0)] + public string str_cn; + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=1)] + public string str_cn1; + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=2)] + public string str_cn2; + + public WriteWelcomeRequestBody() + { + } + + public WriteWelcomeRequestBody(string str_cn, string str_cn1, string str_cn2) + { + this.str_cn = str_cn; + this.str_cn1 = str_cn1; + this.str_cn2 = str_cn2; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteWelcomeResponse + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteWelcomeResponse", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteWelcomeResponseBody Body; + + public WriteWelcomeResponse() + { + } + + public WriteWelcomeResponse(ServiceReferenceLed.WriteWelcomeResponseBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute()] + public partial class WriteWelcomeResponseBody + { + + public WriteWelcomeResponseBody() + { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteContentRequest + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteContent", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteContentRequestBody Body; + + public WriteContentRequest() + { + } + + public WriteContentRequest(ServiceReferenceLed.WriteContentRequestBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute(Namespace="http://tempuri.org/")] + public partial class WriteContentRequestBody + { + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=0)] + public string content; + + public WriteContentRequestBody() + { + } + + public WriteContentRequestBody(string content) + { + this.content = content; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteContentResponse + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteContentResponse", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteContentResponseBody Body; + + public WriteContentResponse() + { + } + + public WriteContentResponse(ServiceReferenceLed.WriteContentResponseBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute()] + public partial class WriteContentResponseBody + { + + public WriteContentResponseBody() + { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteProgramContentRequest + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteProgramContent", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteProgramContentRequestBody Body; + + public WriteProgramContentRequest() + { + } + + public WriteProgramContentRequest(ServiceReferenceLed.WriteProgramContentRequestBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute(Namespace="http://tempuri.org/")] + public partial class WriteProgramContentRequestBody + { + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=0)] + public string content; + + public WriteProgramContentRequestBody() + { + } + + public WriteProgramContentRequestBody(string content) + { + this.content = content; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteProgramContentResponse + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteProgramContentResponse", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteProgramContentResponseBody Body; + + public WriteProgramContentResponse() + { + } + + public WriteProgramContentResponse(ServiceReferenceLed.WriteProgramContentResponseBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute()] + public partial class WriteProgramContentResponseBody + { + + public WriteProgramContentResponseBody() + { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteProgramWelcomeRequest + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteProgramWelcome", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteProgramWelcomeRequestBody Body; + + public WriteProgramWelcomeRequest() + { + } + + public WriteProgramWelcomeRequest(ServiceReferenceLed.WriteProgramWelcomeRequestBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute(Namespace="http://tempuri.org/")] + public partial class WriteProgramWelcomeRequestBody + { + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=0)] + public string str_cn; + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=1)] + public string str_cn1; + + [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=2)] + public string str_cn2; + + public WriteProgramWelcomeRequestBody() + { + } + + public WriteProgramWelcomeRequestBody(string str_cn, string str_cn1, string str_cn2) + { + this.str_cn = str_cn; + this.str_cn1 = str_cn1; + this.str_cn2 = str_cn2; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class WriteProgramWelcomeResponse + { + + [System.ServiceModel.MessageBodyMemberAttribute(Name="WriteProgramWelcomeResponse", Namespace="http://tempuri.org/", Order=0)] + public ServiceReferenceLed.WriteProgramWelcomeResponseBody Body; + + public WriteProgramWelcomeResponse() + { + } + + public WriteProgramWelcomeResponse(ServiceReferenceLed.WriteProgramWelcomeResponseBody Body) + { + this.Body = Body; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.Runtime.Serialization.DataContractAttribute()] + public partial class WriteProgramWelcomeResponseBody + { + + public WriteProgramWelcomeResponseBody() + { + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + public interface WebServiceLedSoapChannel : ServiceReferenceLed.WebServiceLedSoap, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + public partial class WebServiceLedSoapClient : System.ServiceModel.ClientBase, ServiceReferenceLed.WebServiceLedSoap + { + + /// + /// 实现此分部方法,配置服务终结点。 + /// + /// 要配置的终结点 + /// 客户端凭据 + static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials); + + public WebServiceLedSoapClient(EndpointConfiguration endpointConfiguration) : + base(WebServiceLedSoapClient.GetBindingForEndpoint(endpointConfiguration), WebServiceLedSoapClient.GetEndpointAddress(endpointConfiguration)) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceLedSoapClient(EndpointConfiguration endpointConfiguration, string remoteAddress) : + base(WebServiceLedSoapClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress)) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceLedSoapClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) : + base(WebServiceLedSoapClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceLedSoapClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public System.Threading.Tasks.Task LedConnectAsync() + { + return base.Channel.LedConnectAsync(); + } + + public System.Threading.Tasks.Task LedDisConnectAsync() + { + return base.Channel.LedDisConnectAsync(); + } + + public System.Threading.Tasks.Task GetLedConnectedStsAsync() + { + return base.Channel.GetLedConnectedStsAsync(); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task ServiceReferenceLed.WebServiceLedSoap.WriteWelcomeAsync(ServiceReferenceLed.WriteWelcomeRequest request) + { + return base.Channel.WriteWelcomeAsync(request); + } + + public System.Threading.Tasks.Task WriteWelcomeAsync(string str_cn, string str_cn1, string str_cn2) + { + ServiceReferenceLed.WriteWelcomeRequest inValue = new ServiceReferenceLed.WriteWelcomeRequest(); + inValue.Body = new ServiceReferenceLed.WriteWelcomeRequestBody(); + inValue.Body.str_cn = str_cn; + inValue.Body.str_cn1 = str_cn1; + inValue.Body.str_cn2 = str_cn2; + return ((ServiceReferenceLed.WebServiceLedSoap)(this)).WriteWelcomeAsync(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task ServiceReferenceLed.WebServiceLedSoap.WriteContentAsync(ServiceReferenceLed.WriteContentRequest request) + { + return base.Channel.WriteContentAsync(request); + } + + public System.Threading.Tasks.Task WriteContentAsync(string content) + { + ServiceReferenceLed.WriteContentRequest inValue = new ServiceReferenceLed.WriteContentRequest(); + inValue.Body = new ServiceReferenceLed.WriteContentRequestBody(); + inValue.Body.content = content; + return ((ServiceReferenceLed.WebServiceLedSoap)(this)).WriteContentAsync(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task ServiceReferenceLed.WebServiceLedSoap.WriteProgramContentAsync(ServiceReferenceLed.WriteProgramContentRequest request) + { + return base.Channel.WriteProgramContentAsync(request); + } + + public System.Threading.Tasks.Task WriteProgramContentAsync(string content) + { + ServiceReferenceLed.WriteProgramContentRequest inValue = new ServiceReferenceLed.WriteProgramContentRequest(); + inValue.Body = new ServiceReferenceLed.WriteProgramContentRequestBody(); + inValue.Body.content = content; + return ((ServiceReferenceLed.WebServiceLedSoap)(this)).WriteProgramContentAsync(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task ServiceReferenceLed.WebServiceLedSoap.WriteProgramWelcomeAsync(ServiceReferenceLed.WriteProgramWelcomeRequest request) + { + return base.Channel.WriteProgramWelcomeAsync(request); + } + + public System.Threading.Tasks.Task WriteProgramWelcomeAsync(string str_cn, string str_cn1, string str_cn2) + { + ServiceReferenceLed.WriteProgramWelcomeRequest inValue = new ServiceReferenceLed.WriteProgramWelcomeRequest(); + inValue.Body = new ServiceReferenceLed.WriteProgramWelcomeRequestBody(); + inValue.Body.str_cn = str_cn; + inValue.Body.str_cn1 = str_cn1; + inValue.Body.str_cn2 = str_cn2; + return ((ServiceReferenceLed.WebServiceLedSoap)(this)).WriteProgramWelcomeAsync(inValue); + } + + public System.Threading.Tasks.Task WriteClearScreenAsync() + { + return base.Channel.WriteClearScreenAsync(); + } + + public virtual System.Threading.Tasks.Task OpenAsync() + { + return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action(((System.ServiceModel.ICommunicationObject)(this)).EndOpen)); + } + + public virtual System.Threading.Tasks.Task CloseAsync() + { + return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginClose(null, null), new System.Action(((System.ServiceModel.ICommunicationObject)(this)).EndClose)); + } + + private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration) + { + if ((endpointConfiguration == EndpointConfiguration.WebServiceLedSoap)) + { + System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding(); + result.MaxBufferSize = int.MaxValue; + result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max; + result.MaxReceivedMessageSize = int.MaxValue; + result.AllowCookies = true; + return result; + } + if ((endpointConfiguration == EndpointConfiguration.WebServiceLedSoap12)) + { + System.ServiceModel.Channels.CustomBinding result = new System.ServiceModel.Channels.CustomBinding(); + System.ServiceModel.Channels.TextMessageEncodingBindingElement textBindingElement = new System.ServiceModel.Channels.TextMessageEncodingBindingElement(); + textBindingElement.MessageVersion = System.ServiceModel.Channels.MessageVersion.CreateVersion(System.ServiceModel.EnvelopeVersion.Soap12, System.ServiceModel.Channels.AddressingVersion.None); + result.Elements.Add(textBindingElement); + System.ServiceModel.Channels.HttpTransportBindingElement httpBindingElement = new System.ServiceModel.Channels.HttpTransportBindingElement(); + httpBindingElement.AllowCookies = true; + httpBindingElement.MaxBufferSize = int.MaxValue; + httpBindingElement.MaxReceivedMessageSize = int.MaxValue; + result.Elements.Add(httpBindingElement); + return result; + } + throw new System.InvalidOperationException(string.Format("找不到名称为“{0}”的终结点。", endpointConfiguration)); + } + + private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration) + { + if ((endpointConfiguration == EndpointConfiguration.WebServiceLedSoap)) + { + return new System.ServiceModel.EndpointAddress("http://127.0.0.1:8081/WebServiceLed.asmx"); + } + if ((endpointConfiguration == EndpointConfiguration.WebServiceLedSoap12)) + { + return new System.ServiceModel.EndpointAddress("http://127.0.0.1:8081/WebServiceLed.asmx"); + } + throw new System.InvalidOperationException(string.Format("找不到名称为“{0}”的终结点。", endpointConfiguration)); + } + + public enum EndpointConfiguration + { + + WebServiceLedSoap, + + WebServiceLedSoap12, + } + } +} diff --git a/Service/Execute/StaticTools/LedTool.cs b/Service/Execute/StaticTools/LedTool.cs new file mode 100644 index 0000000..6114aa7 --- /dev/null +++ b/Service/Execute/StaticTools/LedTool.cs @@ -0,0 +1,159 @@ +namespace Service.Execute.StaticTools +{ + /// + /// LED管理工具 + /// + public class LedTool + { + static ServiceReferenceLed.WebServiceLedSoapClient client = new ServiceReferenceLed.WebServiceLedSoapClient(ServiceReferenceLed.WebServiceLedSoapClient.EndpointConfiguration.WebServiceLedSoap); + /// + /// 通讯连接 + /// + public void LedConnect() + { + try + { if (client != null) + { + client.LedConnectAsync(); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 通讯断开 + /// + public void LedDisConnect() + { + try + { + if (client != null) + { + client.LedDisConnectAsync(); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// LED连接状态值 + /// + public bool GetLedConnectedSts() + { + bool result = false; + try + { + if (client != null) + { + result = client.GetLedConnectedStsAsync().Result; + } + } + catch (Exception ex) + { + ex.ToString(); + } + return result; + } + + /// + /// 欢迎文本指令 + /// + public void WriteWelcome(string str_cn, string str_cn1, string str_cn2) + { + try + { + if (client != null) + { + client.WriteWelcomeAsync(str_cn, str_cn1, str_cn2); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + + /// + /// 欢迎文本指令 + /// + public void WriteContent(string content) + { + try + { + if (client != null) + { + client.WriteContentAsync(content); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 普通文本节目 + /// + /// 接收文本内容 + public void WriteProgramContent(string content) + { + try + { + if (client != null) + { + client.WriteProgramContentAsync(content); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 欢迎文本节目 + /// + public void WriteProgramWelcome(string str_cn, string str_cn1, string str_cn2) + { + try + { + if (client != null) + { + client.WriteProgramWelcomeAsync(str_cn, str_cn1, str_cn2); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 清屏 + /// + public void WriteClearScreen() + { + try + { + if (client != null) + { + client.WriteClearScreenAsync(); + } + } + catch (Exception ex) + { + ex.ToString(); + } + } + + + + } +} \ No newline at end of file diff --git a/Service/Execute/StaticTools/SoundReference.cs b/Service/Execute/StaticTools/SoundReference.cs new file mode 100644 index 0000000..28d4bb7 --- /dev/null +++ b/Service/Execute/StaticTools/SoundReference.cs @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// +// 对此文件的更改可能导致不正确的行为,并在以下条件下丢失: +// 代码重新生成。 +// +//------------------------------------------------------------------------------ + +namespace ServiceReferenceSound +{ + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReferenceSound.WebServiceSoundSoap")] + public interface WebServiceSoundSoap + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/PlaySoundBySwapStep", ReplyAction="*")] + System.Threading.Tasks.Task PlaySoundBySwapStepAsync(ushort step); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/PlayOneSoundFile", ReplyAction="*")] + System.Threading.Tasks.Task PlayOneSoundFileAsync(int soundcode); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/PlayLoopSoundFile", ReplyAction="*")] + System.Threading.Tasks.Task PlayLoopSoundFileAsync(int soundcode, int interval); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + public interface WebServiceSoundSoapChannel : ServiceReferenceSound.WebServiceSoundSoap, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")] + public partial class WebServiceSoundSoapClient : System.ServiceModel.ClientBase, ServiceReferenceSound.WebServiceSoundSoap + { + + /// + /// 实现此分部方法,配置服务终结点。 + /// + /// 要配置的终结点 + /// 客户端凭据 + static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials); + + public WebServiceSoundSoapClient(EndpointConfiguration endpointConfiguration) : + base(WebServiceSoundSoapClient.GetBindingForEndpoint(endpointConfiguration), WebServiceSoundSoapClient.GetEndpointAddress(endpointConfiguration)) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceSoundSoapClient(EndpointConfiguration endpointConfiguration, string remoteAddress) : + base(WebServiceSoundSoapClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress)) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceSoundSoapClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) : + base(WebServiceSoundSoapClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress) + { + this.Endpoint.Name = endpointConfiguration.ToString(); + ConfigureEndpoint(this.Endpoint, this.ClientCredentials); + } + + public WebServiceSoundSoapClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public System.Threading.Tasks.Task PlaySoundBySwapStepAsync(ushort step) + { + return base.Channel.PlaySoundBySwapStepAsync(step); + } + + public System.Threading.Tasks.Task PlayOneSoundFileAsync(int soundcode) + { + return base.Channel.PlayOneSoundFileAsync(soundcode); + } + + public System.Threading.Tasks.Task PlayLoopSoundFileAsync(int soundcode, int interval) + { + return base.Channel.PlayLoopSoundFileAsync(soundcode, interval); + } + + public virtual System.Threading.Tasks.Task OpenAsync() + { + return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action(((System.ServiceModel.ICommunicationObject)(this)).EndOpen)); + } + + public virtual System.Threading.Tasks.Task CloseAsync() + { + return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginClose(null, null), new System.Action(((System.ServiceModel.ICommunicationObject)(this)).EndClose)); + } + + private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration) + { + if ((endpointConfiguration == EndpointConfiguration.WebServiceSoundSoap)) + { + System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding(); + result.MaxBufferSize = int.MaxValue; + result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max; + result.MaxReceivedMessageSize = int.MaxValue; + result.AllowCookies = true; + return result; + } + if ((endpointConfiguration == EndpointConfiguration.WebServiceSoundSoap12)) + { + System.ServiceModel.Channels.CustomBinding result = new System.ServiceModel.Channels.CustomBinding(); + System.ServiceModel.Channels.TextMessageEncodingBindingElement textBindingElement = new System.ServiceModel.Channels.TextMessageEncodingBindingElement(); + textBindingElement.MessageVersion = System.ServiceModel.Channels.MessageVersion.CreateVersion(System.ServiceModel.EnvelopeVersion.Soap12, System.ServiceModel.Channels.AddressingVersion.None); + result.Elements.Add(textBindingElement); + System.ServiceModel.Channels.HttpTransportBindingElement httpBindingElement = new System.ServiceModel.Channels.HttpTransportBindingElement(); + httpBindingElement.AllowCookies = true; + httpBindingElement.MaxBufferSize = int.MaxValue; + httpBindingElement.MaxReceivedMessageSize = int.MaxValue; + result.Elements.Add(httpBindingElement); + return result; + } + throw new System.InvalidOperationException(string.Format("找不到名称为“{0}”的终结点。", endpointConfiguration)); + } + + private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration) + { + if ((endpointConfiguration == EndpointConfiguration.WebServiceSoundSoap)) + { + return new System.ServiceModel.EndpointAddress("http://127.0.0.1:8080/WebServiceSound.asmx"); + } + if ((endpointConfiguration == EndpointConfiguration.WebServiceSoundSoap12)) + { + return new System.ServiceModel.EndpointAddress("http://127.0.0.1:8080/WebServiceSound.asmx"); + } + throw new System.InvalidOperationException(string.Format("找不到名称为“{0}”的终结点。", endpointConfiguration)); + } + + public enum EndpointConfiguration + { + + WebServiceSoundSoap, + + WebServiceSoundSoap12, + } + } +} diff --git a/Service/Execute/StaticTools/SoundTool.cs b/Service/Execute/StaticTools/SoundTool.cs new file mode 100644 index 0000000..c8dbc7e --- /dev/null +++ b/Service/Execute/StaticTools/SoundTool.cs @@ -0,0 +1,159 @@ +namespace Service.Execute.StaticTools +{ + public class SoundTool + { + private static ServiceReferenceSound.WebServiceSoundSoapClient client = new ServiceReferenceSound.WebServiceSoundSoapClient(ServiceReferenceSound.WebServiceSoundSoapClient.EndpointConfiguration.WebServiceSoundSoap); + + /// + /// 播放通道换电步骤声音 + /// + /// 步骤。10:车辆已到位;40:换电开始;50:换电进行中;60:车辆换电完成;90:停止播报 + /// 声音播放结果 + private static bool ChannelPlayStepSound(ushort step) + { + bool bRst = false; + try + { + Task result = client.PlaySoundBySwapStepAsync(step); + } + catch(Exception ex) + { + ex.ToString(); + } + return bRst; + } + + /// + /// 根据声音编码单次播放相关语音 + /// + /// 声音文件编码。比如:50001-请将车辆行驶到指定位置 + /// 声音播放结果 + public static void PlayOneSound(int soundCode) + { + try + { + client.PlaySoundBySwapStepAsync((ushort)soundCode); + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 根据声音编码循环播放相关语音 + /// + /// 声音文件编码。比如:50001-请将车辆行驶到指定位置 + /// 播放声音间隔时间-秒 + /// 声音播放结果 + public static void PlayLoopSound(int soundcode,int interval) + { + try + { + client.PlayLoopSoundFileAsync(soundcode,interval); + } + catch (Exception ex) + { + ex.ToString(); + } + } + + /// + /// 播放欢迎语 + /// + public static void PlayWelcomeSound() + { + ChannelPlayStepSound(10); + } + + /// + /// 播放车辆到位,请拉手刹、熄火 + /// + public static void PlayTruskIsReached() + { + ChannelPlayStepSound(40); + } + + /// + /// 播放读RFID电子标签失败 + /// + public static void PlayReadeRfidFail() + { + ChannelPlayStepSound(22); + } + + /// + /// 播放车辆认证成功 + /// + public static void PlayTruckSignOK() + { + ChannelPlayStepSound(23); + } + + /// + /// 播放车辆认证失败 + /// + public static void PlayTruckSignFail() + { + ChannelPlayStepSound(24); + } + + /// + /// 播放蓝牙连接失败,异常结束请驶离 + /// + public static void PlayBlueToothFail() + { + ChannelPlayStepSound(32); + } + + /// + /// 播放换电进行中,请勿执行任何操作 + /// + public static void PlaySwapStart() + { + ChannelPlayStepSound(50); + } + + /// + /// 播放电池入库搬运中 + /// + public static void PlayBatteryEntry() + { + ChannelPlayStepSound(51); + } + + /// + /// 播放电池出库搬运中 + /// + public static void PlayBatteryDelivery() + { + ChannelPlayStepSound(52); + } + + /// + /// 播放电池安装完成 + /// + public static void PlayBatteryFinished() + { + ChannelPlayStepSound(53); + } + + + /// + /// 播放换电完成,车辆请驶离 + /// + public static void PlaySwapFinished() + { + ChannelPlayStepSound(60); + } + + /// + /// 停止语音播放 + /// + public static void PlaySoundStop() + { + ChannelPlayStepSound(90); + } + + } +} diff --git a/Service/Execute/StationSoftMgr.cs b/Service/Execute/StationSoftMgr.cs new file mode 100644 index 0000000..b2319bd --- /dev/null +++ b/Service/Execute/StationSoftMgr.cs @@ -0,0 +1,31 @@ + +namespace Service.Execute +{ + /// + /// 软件管理类 + /// + public class StationSoftMgr + { + public static SwappingStateMachine SwappingStateMachine = SwappingStateMachine.GetInstance(); + + + + #region 换电流程启动 + + /// + /// 换电流程启动 + /// + public static void SwappingStateMachineStart() + { + SwappingStateMachine.Start(); + } + + + + + #endregion 换电流程启动 + + + + } +} \ No newline at end of file diff --git a/Service/Execute/Step/BeginState.cs b/Service/Execute/Step/BeginState.cs new file mode 100644 index 0000000..1ae4c84 --- /dev/null +++ b/Service/Execute/Step/BeginState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class BeginState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/CancelState.cs b/Service/Execute/Step/CancelState.cs new file mode 100644 index 0000000..f91e9da --- /dev/null +++ b/Service/Execute/Step/CancelState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class CancelState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/CarCtrlState.cs b/Service/Execute/Step/CarCtrlState.cs new file mode 100644 index 0000000..4850a4f --- /dev/null +++ b/Service/Execute/Step/CarCtrlState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class CarCtrlState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/CarPrepareState.cs b/Service/Execute/Step/CarPrepareState.cs new file mode 100644 index 0000000..4db0463 --- /dev/null +++ b/Service/Execute/Step/CarPrepareState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class CarPrepareState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/DoSwappingState.cs b/Service/Execute/Step/DoSwappingState.cs new file mode 100644 index 0000000..a9759b1 --- /dev/null +++ b/Service/Execute/Step/DoSwappingState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class DoSwappingState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/ExceptionState.cs b/Service/Execute/Step/ExceptionState.cs new file mode 100644 index 0000000..650f7fd --- /dev/null +++ b/Service/Execute/Step/ExceptionState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class ExceptionState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/SelectPackState.cs b/Service/Execute/Step/SelectPackState.cs new file mode 100644 index 0000000..6469a08 --- /dev/null +++ b/Service/Execute/Step/SelectPackState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class SelectPackState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/StationReadyState.cs b/Service/Execute/Step/StationReadyState.cs new file mode 100644 index 0000000..6832ae6 --- /dev/null +++ b/Service/Execute/Step/StationReadyState.cs @@ -0,0 +1,219 @@ +using System.Text; +using Entity.Constant; +using Entity.DbModel.Station; +using log4net; +using Microsoft.VisualBasic; +using Newtonsoft.Json; +using Repository.Station; +using Service.Execute.Api; +using Service.Execute.Enum; +using Service.Execute.StaticTools; +using Service.Execute.SwapException; +using Service.Init; +using Swapping.Business.Common; +using Swapping.Business.Rfid; +using Swapping.Business.Tech; + +namespace Service.Execute.Step; + +public class StationReadyState : IState +{ + private readonly ILog _log = LogManager.GetLogger(typeof(StationReadyState)); + + + public SwapOrderRepository SwapOrderRepository { get; set; } + + public StateResult Handle(SwappingStateMachine machine) + { + _log.Info($"'goto stationReady"); + + machine.Reset(); + SwappingStateMachine.BusinessSwappingState = InfoEnum.BusinessSwappingState.Idle; + SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now; + + //判断换电站是否具备换电条件 + if (!IsAutoSwapping()) + { + return null; + } + + //plc是否是远程模式 + var plcIsRemote = PlcIsRemote(machine); + if (InvokeStatus.Done != plcIsRemote) + { + return SwappingStateMachine.ReturnWithInvokeErr(plcIsRemote, ExceptionReason.None); + } + + + //监测雷达 + var entranceRadar = EntranceRadar(machine); + + if (InvokeStatus.Done != entranceRadar) + { + return SwappingStateMachine.ReturnWithInvokeErr(entranceRadar, ExceptionReason.None); + } + + + //开始读rifd + var beginRfid = BeginRead(machine); + if (InvokeStatus.Done != beginRfid) + { + return SwappingStateMachine.ReturnWithInvokeErr(beginRfid, ExceptionReason.None); + } + + + // 读取rfid + var readRfid = ReadRfid(machine); + if (InvokeStatus.Done != readRfid) + { + return SwappingStateMachine.ReturnWithInvokeErr(readRfid, ExceptionReason.ReadRfidError); + } + + return new StateResult() + { + SwappingState = SwappingState.CarPrepare, + }; + } + + + public InvokeStatus PlcIsRemote(SwappingStateMachine machine) + { + return Invoker.Invoke("check plc remote", 1000, 5, machine.IsCanceled, PlcApi.IsRemote, + () => + { + //LED显示-欢迎光临_换电站点_正在营业(三行展示) + string welcomeContent = "欢迎光临" + StaticStationInfo.StationName + "正在营业"; + + machine.LedTool?.WriteContent(welcomeContent); + }, + () => { }, false); + } + + public InvokeStatus EntranceRadar(SwappingStateMachine machine) + { + return Invoker.Invoke("wait entrance radar", 1000, 1, machine.IsCanceled, + () => SwappingStateMachine.RadarInFlag, () => + { + if (!PlcApi.EntranceRadar()) + { + _log.Info("entrance radar false"); + } + else + { + SwappingStateMachine.ExceptionReason = ExceptionReason.None; + _log.Info("entrance radar true"); + SwappingStateMachine.RadarInFlag = true; + } + }); + } + + public InvokeStatus BeginRead(SwappingStateMachine machine) + { + return Invoker.Invoke("read rfid", 1000, 20, machine.IsCanceled, + () => SwappingStateMachine.BeginRfidReadFlag, () => + { + Task beginRead = RfidApi.BeginRead(); + beginRead.Wait(); + if (!beginRead.Result) + { + _log.Info("begin read rfid error"); + } + else + { + SwappingStateMachine.ExceptionReason = ExceptionReason.None; + _log.Info("begin read done"); + SwappingStateMachine.BeginRfidReadFlag = true; + } + }, () => + { + machine.LedTool.WriteProgramContent(InfoEnum.SwapInfo.ErrorReadRfid.GetLed()); + SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorReadRfid); + }, false, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.ReadRfidError; }); + } + + /// + /// 判断换电站是否具备换电的条件 + /// 1、换电站状态: + /// 2、换电站方式: + /// + /// + private bool IsAutoSwapping() + { + var statusDes = StationConstant.EnumExtensions.GetDescription(StaticStationInfo.StationStatus); + _log.Info($"换电站处于{statusDes}状态"); + var wayDes = StationConstant.EnumExtensions.GetDescription(StaticStationInfo.StationWay); + _log.Info($"换电站处于{wayDes}模式"); + + if (StationConstant.StationStatus.Run == StaticStationInfo.StationStatus + && StationConstant.StationWay.Auto == StaticStationInfo.StationWay) + { + return true; + } + + return false; + } + + private InvokeStatus ReadRfid(SwappingStateMachine machine) + { + //开始读rifd + return Invoker.Invoke("read rfid", 1000, 20, machine.IsCanceled, + () => SwappingStateMachine.RfidReadFlag, () => + { + //TODO::开始读rfid RfidService.BeginRead(); + Task rfidReadModel = RfidApi.ReadRifd(); + rfidReadModel.Wait(); + if (rfidReadModel.IsCompletedSuccessfully && rfidReadModel.Result != null) + { + var resultFVelMac = rfidReadModel.Result.VelMac; + StringBuilder sb = new StringBuilder(16); + sb.Append(resultFVelMac[0]).Append(resultFVelMac[1]).Append(" ") + .Append(resultFVelMac[2]).Append(resultFVelMac[3]).Append(" ") + .Append(resultFVelMac[4]).Append(resultFVelMac[5]).Append(" ") + .Append(resultFVelMac[6]).Append(resultFVelMac[7]).Append(" ") + .Append(resultFVelMac[8]).Append(resultFVelMac[9]).Append(" ") + .Append(resultFVelMac[10]).Append(resultFVelMac[11]); + rfidReadModel.Result.VelMac = sb.ToString(); + machine.RfidReadModel = rfidReadModel.Result; + _log.Info($"read rfid={JsonConvert.SerializeObject(machine.RfidReadModel)}"); + + SwappingStateMachine.ExceptionReason = ExceptionReason.None; + SwappingStateMachine.BusinessSwappingState = InfoEnum.BusinessSwappingState.ScanRfid; + SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now; + _log.Info($"BusinessSwappingState={SwappingStateMachine.BusinessSwappingState}"); + + machine.SwapOrder = SaveOrder(BuildOrder(machine.RfidReadModel)); + + RfidApi.StopRead(); + _log.Info("stop read rfid"); + + SwappingStateMachine.RfidReadFlag = true; + } + }, () => + { + machine.LedTool.WriteProgramContent(InfoEnum.SwapInfo.ErrorReadRfid.GetLed()); + SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorReadRfid); + }, true, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.ReadRfidError; }, 10, + InvokeStatus.Exception); + } + + + private SwapOrder BuildOrder(RfidReadModel rfidReadModel) + { + SwapOrder swapOrder = new SwapOrder() + { + Sn = SwapOrderNoGenerator.GenerateOrderNo(StaticStationInfo.StationNo), + VehicleVin = rfidReadModel.VelVin, + VehicleMac = rfidReadModel.VelMac, + VehicleNo = rfidReadModel.VelNo, + VehicleEnterTime = DateTime.Now, + }; + + return swapOrder; + } + + private SwapOrder SaveOrder(SwapOrder swapOrder) + { + SwapOrderRepository.Insert(swapOrder); + return swapOrder; + } +} \ No newline at end of file diff --git a/Service/Execute/Step/SwapDoneState.cs b/Service/Execute/Step/SwapDoneState.cs new file mode 100644 index 0000000..2a47703 --- /dev/null +++ b/Service/Execute/Step/SwapDoneState.cs @@ -0,0 +1,14 @@ +namespace Service.Execute.Step; + +public class SwapDoneState: IState +{ + public StateResult Handle(SwappingStateMachine machine) + { + + return new StateResult() + { + + SwappingState = SwappingState.StationReady + }; + } +} \ No newline at end of file diff --git a/Service/Execute/SwapException/ExceptionData.cs b/Service/Execute/SwapException/ExceptionData.cs new file mode 100644 index 0000000..f51bb33 --- /dev/null +++ b/Service/Execute/SwapException/ExceptionData.cs @@ -0,0 +1,9 @@ +using Service.Execute.SwapException; + +namespace Service.Execute; + +public class ExceptionData +{ + public ExceptionReason ExceptionReason { get; set; } + public string? Msg { get; set; } +} \ No newline at end of file diff --git a/Service/Execute/SwapException/ExceptionReason.cs b/Service/Execute/SwapException/ExceptionReason.cs new file mode 100644 index 0000000..26d8aa2 --- /dev/null +++ b/Service/Execute/SwapException/ExceptionReason.cs @@ -0,0 +1,23 @@ +namespace Service.Execute.SwapException; + + + /// + /// 异常原因 + /// + public enum ExceptionReason + { + None, + ReadRfidError, + OpenBarrierError, + ConnVbleError, + CarStateCheckError, + CloudCheckError, + CloudVbleDataError, + CarInPositionError, + CloudSendSwapError, + SelectPackError, + HvPwrOffError, + LvPwrOffError, + SelfCheckError, + TimeOutError + } diff --git a/Service/Execute/SwappingStateMachine.cs b/Service/Execute/SwappingStateMachine.cs new file mode 100644 index 0000000..66d365e --- /dev/null +++ b/Service/Execute/SwappingStateMachine.cs @@ -0,0 +1,208 @@ +using Entity.DbModel.Station; +using log4net; +using Newtonsoft.Json; +using Service.Execute.Enum; +using Service.Execute.StaticTools; +using Service.Execute.Step; +using Service.Execute.SwapException; +using Service.Execute.Tech; +using Swapping.Business.Rfid; + +namespace Service.Execute; + +public class SwappingStateMachine : IDisposable +{ + private static readonly ILog _log = LogManager.GetLogger(typeof(SwappingStateMachine)); + private static SwappingStateMachine _swappingStateMachine = new SwappingStateMachine(); + public static bool CancelFlag { get; set; } = false; + public static bool StopFlag { get; set; } = false; + + public LedTool LedTool = null; + private Thread _executeThread; + private Dictionary Dictionary = new Dictionary(); + + private StateResult _result = new StateResult() { SwappingState = SwappingState.Begin }; + public static InfoEnum.BusinessSwappingState BusinessSwappingState = InfoEnum.BusinessSwappingState.UnKnown; + public static DateTime BusinessSwappingStateUpdateTime = DateTime.Now; + public static ExceptionReason ExceptionReason = ExceptionReason.None; + + + + public RfidReadModel? RfidReadModel=null; + + public SwapOrder? SwapOrder=null; + + + #region 小步状态 + + //雷达检测/车辆进入 + public static bool RadarInFlag = false; + //开始读rfid + public static bool BeginRfidReadFlag = false; + //读rfid + public static bool RfidReadFlag = false; + + //云平台车辆认证 + public static bool CloudVelCheckFlag = false; + + //Tbox连接 + public static bool TBoxConnectionFlag = false; + + //选包 + public static bool SelectPackFlag = false; + + //车辆到位 + public static bool VehiclesInPlaceFlag = false; + + //通道定位 + public static bool ChannelPositioningFlag = false; + + //下发选包 + public static bool DistributeSelectPackFlag = false; + + //云平台下发启动换电 + public static bool CloudPackFlag = false; + + //车辆解锁 + public static bool VelUnlockFlag = false; + + //开始换电 + public static bool StartSwappingFlag = false; + + //拆旧电池 + public static bool UnOldBatteryFlag = false; + + //入库旧电池 + public static bool StorageOldBatteryFlag = false; + + //搬运新电池 + public static bool OutNewBatteryFlag = false; + + //安装新电池 + public static bool InstallNewBatteryFlag = false; + + //安装完成 + public static bool FinishNewBatteryFlag = false; + + //车辆上锁 + public static bool VelLockFlag = false; + + + //车辆离开 + public static 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.SelectPack] = new SelectPackState(); + 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(); + + LedTool = new LedTool(); + } + + public static SwappingStateMachine GetInstance() + { + return _swappingStateMachine; + } + + + 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 + { + return StateResult.Exception(ExceptionReason.ReadRfidError, 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 Start() + { + Reset(); + _executeThread.Start(); + _log.Info($"start machine ok"); + return true; + } + + public void Reset() + { + } + + + public void Dispose() + { + StopFlag = true; + CancelFlag = true; + Thread.Sleep(2000); + } +} + +public enum SwappingState +{ + Begin, + StationReady, + CarPrepare, + SelectPack, + CarCtrl, + DoSwapping, + SwapDone, + Exception, + Canceled +} + diff --git a/Service/Execute/Tech/InfoAttribute.cs b/Service/Execute/Tech/InfoAttribute.cs new file mode 100644 index 0000000..7857ae5 --- /dev/null +++ b/Service/Execute/Tech/InfoAttribute.cs @@ -0,0 +1,60 @@ +using System.Reflection; + +namespace Swapping.Business.Tech; + +public class InfoAttribute : Attribute +{ + private string _Led; + private string _Sound; + + public InfoAttribute(string led, string sound) + { + this._Led = led; + this._Sound = sound; + } + + public string GetLed() + { + return this._Led; + } + + public string GetSound() + { + return _Sound; + } +} + +public static class InfoExtend +{ + public static string GetLed(this Enum value) + { + Type type = value.GetType(); + FieldInfo? fieldInfo = type.GetField(value.ToString()); + if (fieldInfo != null && fieldInfo.IsDefined(typeof(InfoAttribute), true)) + { + Attribute? attribute = fieldInfo.GetCustomAttribute(typeof(InfoAttribute)); + if (attribute != null) + { + return ((InfoAttribute)attribute).GetLed(); + } + } + + return value.ToString(); + } + + public static string GetSound(this Enum value) + { + Type type = value.GetType(); + FieldInfo? fieldInfo = type.GetField(value.ToString()); + if (fieldInfo != null && fieldInfo.IsDefined(typeof(InfoAttribute), true)) + { + Attribute? attribute = fieldInfo.GetCustomAttribute(typeof(InfoAttribute)); + if (attribute != null) + { + return ((InfoAttribute)attribute).GetSound(); + } + } + + return value.ToString(); + } +} \ No newline at end of file diff --git a/Service/Execute/Tech/RemarkAttribute.cs b/Service/Execute/Tech/RemarkAttribute.cs new file mode 100644 index 0000000..1ec3e7c --- /dev/null +++ b/Service/Execute/Tech/RemarkAttribute.cs @@ -0,0 +1,37 @@ +using System.Reflection; + +namespace Service.Execute.Tech; + +public class RemarkAttribute : Attribute +{ + private string _Remark; + + public RemarkAttribute(string remark) + { + this._Remark = remark; + } + + public string GetRemark() + { + return this._Remark; + } +} + +public static class RemarkExtend +{ + public static string GetRemark(this global::System.Enum value) + { + Type type = value.GetType(); + FieldInfo? fieldInfo = type.GetField(value.ToString()); + if (fieldInfo != null && fieldInfo.IsDefined(typeof(RemarkAttribute), true)) + { + Attribute? attribute = fieldInfo.GetCustomAttribute(typeof(RemarkAttribute)); + if (attribute != null) + { + return ((RemarkAttribute)attribute).GetRemark(); + } + } + + return value.ToString(); + } +} \ No newline at end of file diff --git a/Service/Init/StaticStationInfo.cs b/Service/Init/StaticStationInfo.cs new file mode 100644 index 0000000..8f52904 --- /dev/null +++ b/Service/Init/StaticStationInfo.cs @@ -0,0 +1,19 @@ +using Entity.Constant; + +namespace Service.Init; + +/// +/// 换电站基本信息静态数据 +/// +public class StaticStationInfo +{ + public static StationConstant.StationStatus StationStatus; + + public static StationConstant.StationWay StationWay; + + public static StationConstant.StationModel StationModel; + + public static string StationName; + + public static string StationNo; +} \ No newline at end of file diff --git a/Service/Service.csproj b/Service/Service.csproj index 433e1ae..136039a 100644 --- a/Service/Service.csproj +++ b/Service/Service.csproj @@ -15,6 +15,10 @@ + + + + diff --git a/WebStarter/Controllers/ChargeOrderController.cs b/WebStarter/Controllers/ChargeOrderController.cs index 9045e2b..3b17641 100644 --- a/WebStarter/Controllers/ChargeOrderController.cs +++ b/WebStarter/Controllers/ChargeOrderController.cs @@ -50,7 +50,7 @@ public class ChargeOrderController : ControllerBase /// /// /// - [HttpGet("Modify")] + [HttpPost("Modify")] public async Task> Modify([FromBody] ModifyChargeOrderReq req) { diff --git a/WebStarter/Controllers/SwapOrderController.cs b/WebStarter/Controllers/SwapOrderController.cs index add3199..5c4a51a 100644 --- a/WebStarter/Controllers/SwapOrderController.cs +++ b/WebStarter/Controllers/SwapOrderController.cs @@ -29,7 +29,7 @@ public class SwapOrderController : ControllerBase /// /// /// - [HttpGet("Modify")] + [HttpPost("Modify")] public async Task> Modify([FromBody] ModifySwapOrderReq req) { @@ -41,8 +41,8 @@ public class SwapOrderController : ControllerBase /// /// ids 订单列表 /// - [HttpGet("DeleteByIds")] - public async Task> DeleteByIds(List ids) + [HttpPost("DeleteByIds")] + public async Task> DeleteByIds([FromBody] List ids) { return Result.Success(null); diff --git a/WebStarter/Controllers/Test/GenController.cs b/WebStarter/Controllers/Test/GenController.cs index 4b4ad5e..cee0a5d 100644 --- a/WebStarter/Controllers/Test/GenController.cs +++ b/WebStarter/Controllers/Test/GenController.cs @@ -1,9 +1,8 @@ -using Entity.DbModel.Station; using Microsoft.AspNetCore.Mvc; using Repository.Station; using SqlSugar; -namespace WebStarter.Controllers; +namespace WebStarter.Controllers.Test; [ApiController] [Route("[controller]")] @@ -38,7 +37,7 @@ public class GenController : ControllerBase Console.WriteLine("生成完毕"); } - [HttpGet("test115")] + /*[HttpGet("test115")] public void Test115() { _batteryGroupRepository.Insert(new List() @@ -63,7 +62,7 @@ public class GenController : ControllerBase Console.WriteLine("测试完毕"); - } + }*/ static string ToPascalCase(string input) diff --git a/WebStarter/Controllers/Test/WeatherForecastController.cs b/WebStarter/Controllers/Test/WeatherForecastController.cs index 35fb358..db4465a 100644 --- a/WebStarter/Controllers/Test/WeatherForecastController.cs +++ b/WebStarter/Controllers/Test/WeatherForecastController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Service.System; -namespace WebStarter.Controllers; +namespace WebStarter.Controllers.Test; [ApiController] [Route("[controller]")] diff --git a/WebStarter/Program.cs b/WebStarter/Program.cs index 1ccc693..08010f6 100644 --- a/WebStarter/Program.cs +++ b/WebStarter/Program.cs @@ -4,7 +4,6 @@ using HybirdFrameworkCore.Autofac; using HybirdFrameworkCore.Configuration; using HybirdFrameworkCore.Entity; using HybirdFrameworkCore.Redis; -using Microsoft.OpenApi.Models; using SqlSugar; using SqlSugar.IOC;