diff --git a/Service/Ups/Client/UpsClient.cs b/Service/Ups/Client/UpsClient.cs new file mode 100644 index 0000000..bdb12f4 --- /dev/null +++ b/Service/Ups/Client/UpsClient.cs @@ -0,0 +1,49 @@ +using HybirdFrameworkCore.Autofac.Attribute; +using HybirdFrameworkDriver.Session; +using HybirdFrameworkDriver.TcpClient; +using log4net; +using Service.Ups.Codec; +using Service.Ups.Common; + +namespace Service.Ups.Client; + +[Scope] +public class UpsClient: TcpClient +{ + /// + /// 设备编号 + /// + public string Sn { get; set; } + + private ILog Log() + { + var name = "Fire"; + ILog logger = LogManager.GetLogger(name); + + Console.WriteLine(name + "-" + logger.GetHashCode()); + return logger; + } + + /// + /// + /// + /// + public bool Connect() + { + base.BaseConnect(); + Log().Info("ups connect succeed"); + return Connected; + } + + /// + ///UPS + /// + /// + /// + public void SessionAttr(string sn) + { + ChannelUtils.AddAttr(Channel, UpsConst.UpsSn, sn); + ChannelUtils.AddAttr(Channel, UpsConst.EqmTypeNo, sn); + ChannelUtils.AddAttr(Channel, UpsConst.EqmCode, sn); + } +} \ No newline at end of file diff --git a/Service/Ups/Client/UpsMgr.cs b/Service/Ups/Client/UpsMgr.cs new file mode 100644 index 0000000..0f84a0b --- /dev/null +++ b/Service/Ups/Client/UpsMgr.cs @@ -0,0 +1,76 @@ +using System.Collections.Concurrent; +using Autofac; +using DotNetty.Transport.Channels; +using HybirdFrameworkCore.Autofac; +using HybirdFrameworkDriver.Session; +using log4net; +using Service.Ups.Common; + +namespace Service.Ups.Client; + +public class UpsMgr +{ + + private static readonly ILog Log = LogManager.GetLogger(typeof(UpsMgr)); + + public static readonly ConcurrentDictionary Dictionary = new(); + + public static void ConnClient() + { + Log.Info($"begin to connect ups"); + UpsClient client = AppInfo.Container.Resolve(); + client.AutoReconnect = true; + client.Sn = UpsConst.Sn; + client.LogName = "ups" + UpsConst.EqmCode; + client.ConnectedEventHandler += (sender, b) => + { + client.SessionAttr(UpsConst.Sn); + }; + client.InitBootstrap(UpsConst.Ip, UpsConst.Port); + + Task.Run(() => + { + client.Connect(); + client.SessionAttr(UpsConst.Sn); + Log.Info($"succeed to connect loading..."); + }); + + AddBySn(UpsConst.Sn, client); + Log.Info($"begin to connect UpsClient"); + } + public static void AddBySn(string sn, UpsClient client) + { + Dictionary[sn] = client; + } + /// + /// 通过channel获取client + /// + /// + /// + /// 获取不到,client则为空 + /// + public static bool TryGetClient(IChannel channel, out string sn, out UpsClient? client) + { + string? snt = ChannelUtils.GetAttr(channel, UpsConst.EqmCode); + + if (!string.IsNullOrWhiteSpace(snt)) + { + var chargerClient = GetBySn(snt); + if (chargerClient != null) + { + sn = snt; + client = chargerClient; + return true; + } + } + + sn = string.Empty; + client = null; + return false; + } + public static UpsClient? GetBySn(string sn) + { + Dictionary.TryGetValue(sn, out var o); + return o; + } +} \ No newline at end of file diff --git a/Service/Ups/Codec/Decoder.cs b/Service/Ups/Codec/Decoder.cs new file mode 100644 index 0000000..b2eead8 --- /dev/null +++ b/Service/Ups/Codec/Decoder.cs @@ -0,0 +1,179 @@ +using System.Text; +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Transport.Channels; +using HybirdFrameworkCore.Utils; +using HybirdFrameworkDriver.Session; +using log4net; +using Newtonsoft.Json; +using Service.Ups.Common; +using Service.Ups.Msg; + +namespace Service.Ups.Codec; + +public class Decoder: ByteToMessageDecoder +{ + private readonly IByteBuffer[] _delimitersStart = { Unpooled.CopiedBuffer(UpsConst.StartChar) }; + private readonly IByteBuffer[] _delimitersEnd = { Unpooled.CopiedBuffer(UpsConst.EndChar) }; + + private ILog Log(string? chargerSn) + { + if (ObjUtils.IsNotNullOrWhiteSpace(chargerSn)) + { + return LogManager.GetLogger("Charger" + chargerSn); + } + + return LogManager.GetLogger(typeof(Decoder)); + } + + protected override void Decode(IChannelHandlerContext context, IByteBuffer buffer, List output) + { + string? chargerSn = ChannelUtils.GetAttr(context.Channel, UpsConst.UpsSn); + IByteBuffer? delimiterStart = FindDelimiterStart(buffer); + IByteBuffer? delimiterEnd = FindDelimiterEnd(buffer); + if (delimiterStart != null&&delimiterEnd!=null) + { + //分隔符索引 + int delimiterIndex = IndexOf(buffer, delimiterStart); + int delimiterFinish = IndexOf(buffer, delimiterEnd); + + + //计算帧长 + int frameLengthIndex = delimiterFinish - delimiterIndex + 1; + + if (delimiterIndex > 0) + { + buffer.SkipBytes(delimiterIndex); + return; + } + + //没有帧长 + /*if (buffer.ReadableBytes < frameLengthIndex + 2) + { + // 数据不足,等待更多数据 + return; + }*/ + + // 读取长度字段 + /*byte frameLength = buffer.GetByte(buffer.ReaderIndex + frameLengthIndex); + //总帧长 + int totalFrameLength = delimiterIndex + delimiter.Capacity + 2 + 2 + frameLength;*/ + // 最小总帧长过滤 + /*if (totalFrameLength < 5) + { + return; + }*/ + + /*if (buffer.ReadableBytes < totalFrameLength) + { + // 数据不足,等待更多数据 + return; + }*/ + + byte[]? data = null; + try + { + ASDU asdu = Parse(buffer, frameLengthIndex, delimiterStart, out data); + Log(chargerSn) + .Info( + $"receive {BitUtls.BytesToHexStr(data)}:{JsonConvert.SerializeObject(asdu)} from {chargerSn}"); + output.Add(asdu); + } + catch (Exception e) + { + Log(chargerSn).Error($"decode fail msg={BitUtls.BytesToHexStr(data)}"); + } + } + } + + private IByteBuffer? FindDelimiterStart(IByteBuffer buffer) + { + foreach (IByteBuffer delimiter in _delimitersStart) + { + int delimiterIndex = IndexOf(buffer, delimiter); + if (delimiterIndex >= 0) + { + return delimiter; + } + } + + return null; + } + + + private IByteBuffer? FindDelimiterEnd(IByteBuffer buffer) + { + foreach (IByteBuffer delimiter in _delimitersEnd) + { + int delimiterIndex = IndexOf(buffer, delimiter); + if (delimiterIndex >= 0) + { + return delimiter; + } + } + + return null; + } + + #region 查找帧头 + + private static int IndexOf(IByteBuffer haystack, IByteBuffer needle) + { + for (int i = haystack.ReaderIndex; i < haystack.WriterIndex; i++) + { + int num = i; + int j; + for (j = 0; j < needle.Capacity && haystack.GetByte(num) == needle.GetByte(j); j++) + { + num++; + if (num == haystack.WriterIndex && j != needle.Capacity - 1) + { + return -1; + } + } + + if (j == needle.Capacity) + { + return i - haystack.ReaderIndex; + } + } + + return -1; + } + + #endregion + + #region 查找帧尾 + + + + #endregion + + + public ASDU Parse(IByteBuffer byteBuffer, int totalFrameLength, IByteBuffer delimiter, out byte[] data) + { + //这里转成ascll码 + data = new byte[totalFrameLength]; + byteBuffer.ReadBytes(data); + + //data就是数据 + string stRAsicll= Encoding.ASCII.GetString(data ).ToUpper(); + + string[] strLst = stRAsicll.Split(" "); + + int removeIndex = delimiter.Capacity; + //TODO::后续处理 + + ushort cmd = data[2 + removeIndex]; + byte[] bytes = new byte[data[2]]; + Array.Copy(data, 2 + removeIndex, bytes, 0, bytes.Length); + byte length = data[2]; + ASDU asdu = cmd switch + { + _ => new ASDU(), + }; + ASDU.ParseHeader(data, asdu); + + return asdu; + } +} \ No newline at end of file diff --git a/Service/Ups/Codec/Encoder.cs b/Service/Ups/Codec/Encoder.cs new file mode 100644 index 0000000..d66743b --- /dev/null +++ b/Service/Ups/Codec/Encoder.cs @@ -0,0 +1,41 @@ +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Transport.Channels; +using HybirdFrameworkCore.Utils; +using HybirdFrameworkDriver.Session; +using log4net; +using Newtonsoft.Json; +using Service.Fire.Common; +using Service.Fire.Msg; + +namespace Service.Ups.Codec; + +public class Encoder: MessageToByteEncoder +{ + private ILog? Log(string? chargerSn) + { + if (ObjUtils.IsNotNullOrWhiteSpace(chargerSn)) + { + return LogManager.GetLogger("fire" + chargerSn); + } + return LogManager.GetLogger(typeof(Fire.Codec.Encoder)); + } + + /// + /// + /// + /// + /// + /// + protected override void Encode(IChannelHandlerContext context, APCI obj, IByteBuffer output) + { + + string? sn = ChannelUtils.GetAttr(context.Channel, FireConst.FireSn); + byte[] bytes = obj.ToBytes(); + Log(sn)?.Info( + $"send {BitUtls.BytesToHexStr(bytes)}:{JsonConvert.SerializeObject(obj)} to {ChannelUtils.GetAttr(context.Channel, FireConst.FireSn)}"); + + + context.WriteAndFlushAsync(bytes); + } +} \ No newline at end of file diff --git a/Service/Ups/Common/UpsConst.cs b/Service/Ups/Common/UpsConst.cs new file mode 100644 index 0000000..5e80344 --- /dev/null +++ b/Service/Ups/Common/UpsConst.cs @@ -0,0 +1,19 @@ +using DotNetty.Common.Utilities; + +namespace Service.Ups.Common; + +public class UpsConst +{ + public static readonly AttributeKey UpsSn = AttributeKey.ValueOf("ups_sn");//fire + public static readonly AttributeKey EqmTypeNo = AttributeKey.ValueOf("eqm_type_no");//5 + public static readonly AttributeKey EqmCode = AttributeKey.ValueOf("eqm_code");//fire + //public static readonly AttributeKey DestAddr = AttributeKey.ValueOf("dest_addr");// + public static readonly byte[] StartChar = { 0x28 /* ,0xEE*/ }; + public static readonly byte[] EndChar = { 0x3E /* ,0xEE*/ }; + + public static string Ip = "127.0.0.1"; + public static int Port = 505; + public static string Sn = "fire"; + public static string No = "1"; + public static string Code = "5"; +} \ No newline at end of file diff --git a/Service/Ups/IBaseHandler.cs b/Service/Ups/IBaseHandler.cs new file mode 100644 index 0000000..9e39993 --- /dev/null +++ b/Service/Ups/IBaseHandler.cs @@ -0,0 +1,7 @@ +namespace Service.Ups; +using DotNetty.Transport.Channels; + +public interface IBaseHandler : IChannelHandler +{ + +} \ No newline at end of file diff --git a/Service/Ups/Msg/APCI.cs b/Service/Ups/Msg/APCI.cs new file mode 100644 index 0000000..3aa9fd2 --- /dev/null +++ b/Service/Ups/Msg/APCI.cs @@ -0,0 +1,15 @@ +using HybirdFrameworkDriver.Common; + +namespace Service.Ups.Msg; + +public abstract class APCI: IToBytes +{ + public byte[] ToBytes() + { + var bodyBytes = GetBytes(); + var list = new List(); + + return list.ToArray(); + } + public abstract byte[] GetBytes(); +} \ No newline at end of file diff --git a/Service/Ups/Msg/ASDU.cs b/Service/Ups/Msg/ASDU.cs new file mode 100644 index 0000000..2f7f4aa --- /dev/null +++ b/Service/Ups/Msg/ASDU.cs @@ -0,0 +1,32 @@ +using DotNetty.Buffers; +using HybirdFrameworkCore.Utils; +using Service.Fire.Common; + +namespace Service.Ups.Msg; + +public class ASDU:APCI +{ + public override byte[] GetBytes() + { + var list = new List(); + + list.AddRange(ModelConvert.Encode(this)); + return list.ToArray(); + } + + public static void ParseHeader(byte[] data, ASDU asdu) + { + IByteBuffer byteBuffer = Unpooled.WrappedBuffer(data); + try + { + } + catch (Exception e) + { + throw e; + } + finally + { + byteBuffer.Release(); + } + } +} \ No newline at end of file diff --git a/WebStarter/Program.cs b/WebStarter/Program.cs index 6d61d27..4e74421 100644 --- a/WebStarter/Program.cs +++ b/WebStarter/Program.cs @@ -19,6 +19,7 @@ using Service.Fire.Common; using Service.FireControl.Client; using Service.Plc.Client; using Service.RealTime; +using Service.Ups.Client; using SqlSugar; using SqlSugar.IOC; using WebStarter.MyFilter; @@ -194,6 +195,12 @@ if (AppSettingsHelper.GetBool("fireZw", "enable")) FireMgr.ConnClient(); } +//中卫Ups +if (AppSettingsHelper.GetBool("ups", "enable")) +{ + UpsMgr.ConnClient(); +} + TaskInit.Init(); QuartzSchedulerFactory.Init();