using DotNetty.Buffers; using DotNetty.Codecs; using DotNetty.Transport.Channels; using HybirdFrameworkCore.Utils; using HybirdFrameworkDriver.Session; using log4net; using Newtonsoft.Json; using Service.Charger.Client; using Service.Charger.Msg; using Service.Charger.Msg.Charger.Req; using Service.Charger.Msg.Charger.Resp; namespace Service.Charger.Codec; /// /// 解码器 /// public class Decoder : ByteToMessageDecoder { private readonly IByteBuffer[] _delimiters = { Unpooled.CopiedBuffer(PlcConst.StartChar) }; /// /// /// /// /// private ILog Log(string? chargerSn) { if (ObjUtils.IsNotNullOrWhiteSpace(chargerSn)) { //return LogManager.GetLogger("Plc" + chargerSn); return LogManager.GetLogger("Plc"); } return LogManager.GetLogger(typeof(Decoder)); } #region MyRegion #endregion protected override void Decode(IChannelHandlerContext context, IByteBuffer buffer, List output) { string? chargerSn = ChannelUtils.GetAttr(context.Channel, PlcConst.ChargerSn); IByteBuffer? delimiter = FindDelimiter(buffer); if (delimiter != null) { //分隔符索引 int delimiterIndex = IndexOf(buffer, delimiter); //帧长索引 int frameLengthIndex = delimiterIndex + delimiter.Capacity; if (delimiterIndex > 0) { buffer.SkipBytes(delimiterIndex); return; } if (buffer.ReadableBytes < frameLengthIndex + 2) { // 数据不足,等待更多数据 return; } // 读取长度字段 int frameLength = buffer.GetUnsignedShortLE(buffer.ReaderIndex + frameLengthIndex); //总帧长 int totalFrameLength = delimiterIndex + delimiter.Capacity + 2 + frameLength; // int totalFrameLength = delimiterIndex + frameLength; // 最小总帧长过滤 if (totalFrameLength < 21) { return; } if (buffer.ReadableBytes < totalFrameLength) { // 数据不足,等待更多数据 return; } byte[]? data = null; try { ASDU asdu = Parse(buffer, totalFrameLength, delimiter, 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? FindDelimiter(IByteBuffer buffer) { foreach (IByteBuffer delimiter in _delimiters) { int delimiterIndex = IndexOf(buffer, delimiter); if (delimiterIndex >= 0) { return delimiter; } } return null; } 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; } public ASDU Parse(IByteBuffer byteBuffer, int totalFrameLength, IByteBuffer delimiter, out byte[] data) { data = new byte[totalFrameLength]; byteBuffer.ReadBytes(data); int removeIndex = delimiter.Capacity; ushort cmd = data[14 + removeIndex]; byte[] bytes = new byte[data.Length - (23 + removeIndex)]; Array.Copy(data, 23 + removeIndex, bytes, 0, bytes.Length); ASDU baseMsg = cmd switch { /*0x*/ 93 => ModelConvert.Decode(bytes), /*0x*/ 82 => ModelConvert.Decode(bytes), /*0x*/ 76 => ModelConvert.Decode(bytes), /*0x*/ 106 => ModelConvert.Decode(bytes), /*0x*/ 200 => ModelConvert.Decode(bytes), /*0x*/ 83 => ModelConvert.Decode(bytes), /*0x*/ 78 => ModelConvert.Decode(bytes), /*0x*/ 77 => ModelConvert.Decode(bytes), /*0x*/ 95 => ModelConvert.Decode(bytes), /*0x*/ 92 => ModelConvert.Decode(bytes), /*0x*/ 87 => ModelConvert.Decode(bytes), /*0x*/ 84 => ModelConvert.Decode(bytes), /*0x*/ 107 => ModelConvert.Decode(bytes), /*0x*/ 89 => ModelConvert.Decode(bytes), /*0x*/ 96 => ModelConvert.Decode(bytes), /*0x*/ 116 => ModelConvert.Decode(bytes), /*0x*/ 80 => ModelConvert.Decode(bytes), /*0x*/ 101 => ModelConvert.Decode(bytes), /*0x*/ 111 => ModelConvert.Decode(bytes), /*0x*/ 99 => ModelConvert.Decode(bytes), /*0x*/ 100 => ModelConvert.Decode(bytes), /*0x*/ 113 => ModelConvert.Decode(bytes), /*0x*/ 88 => ModelConvert.Decode(bytes), /*0x*/ 117 => ModelConvert.Decode(bytes), /*0x*/ 94 => ModelConvert.Decode(bytes), _ => new ASDU() }; ASDU.ParseHeader(data, baseMsg); return baseMsg; } }