using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Aitex.Core.RT.Log; using MECF.Framework.RT.Core.IoProviders.Common; using MECF.Framework.RT.Core.IoProviders.Common.Net.NetworkBase; using MECF.Framework.RT.Core.IoProviders.Common.Net.StateOne; using MECF.Framework.RT.Core.IoProviders.Common.Transfer; namespace MECF.Framework.RT.Core.IoProviders.Melsec { /// /// 三菱MC协议的虚拟服务器,支持M,X,Y,D,W的数据池读写操作,使用二进制进行读写操作 /// public class MelsecMcServer : NetworkDataServerBase { #region Constructor /// /// 实例化一个mc协议的服务器 /// public MelsecMcServer() { // 共计使用了五个数据池 xBuffer = new SoftBuffer(DataPoolLength); yBuffer = new SoftBuffer(DataPoolLength); mBuffer = new SoftBuffer(DataPoolLength); dBuffer = new SoftBuffer(DataPoolLength * 2); wBuffer = new SoftBuffer(DataPoolLength * 2); WordLength = 1; ByteTransform = new RegularByteTransform(); } #endregion #region NetworkDataServerBase Override /// /// 读取自定义的寄存器的值。按照字为单位 /// /// 起始地址,示例:"D100","M100" /// 数据长度 /// /// byte数组值 public override OperateResult Read(string address, ushort length) { OperateResult analysis = MelsecHelper.McAnalysisAddress(address); if (!analysis.IsSuccess) return OperateResult.CreateFailedResult(analysis); if (analysis.Content1.DataCode == MelsecMcDataType.M.DataCode) { bool[] buffer = mBuffer.GetBytes(analysis.Content2, length * 16).Select(m => m != 0x00).ToArray(); return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(buffer)); } else if (analysis.Content1.DataCode == MelsecMcDataType.X.DataCode) { bool[] buffer = xBuffer.GetBytes(analysis.Content2, length * 16).Select(m => m != 0x00).ToArray(); return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(buffer)); } else if (analysis.Content1.DataCode == MelsecMcDataType.Y.DataCode) { bool[] buffer = yBuffer.GetBytes(analysis.Content2, length * 16).Select(m => m != 0x00).ToArray(); return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(buffer)); } else if (analysis.Content1.DataCode == MelsecMcDataType.D.DataCode) { return OperateResult.CreateSuccessResult(dBuffer.GetBytes(analysis.Content2 * 2, length * 2)); } else if (analysis.Content1.DataCode == MelsecMcDataType.W.DataCode) { return OperateResult.CreateSuccessResult(wBuffer.GetBytes(analysis.Content2 * 2, length * 2)); } else { return new OperateResult(StringResources.Language.NotSupportedDataType); } } /// /// 写入自定义的数据到数据内存中去 /// /// 地址 /// 数据值 /// 是否写入成功的结果对象 public override OperateResult Write(string address, byte[] value) { OperateResult analysis = MelsecHelper.McAnalysisAddress(address); if (!analysis.IsSuccess) return OperateResult.CreateFailedResult(analysis); if (analysis.Content1.DataCode == MelsecMcDataType.M.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(value).Select(m => m ? (byte)1 : (byte)0).ToArray(); mBuffer.SetBytes(buffer, analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.X.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(value).Select(m => m ? (byte)1 : (byte)0).ToArray(); xBuffer.SetBytes(buffer, analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.Y.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(value).Select(m => m ? (byte)1 : (byte)0).ToArray(); yBuffer.SetBytes(buffer, analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.D.DataCode) { dBuffer.SetBytes(value, analysis.Content2 * 2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.W.DataCode) { wBuffer.SetBytes(value, analysis.Content2 * 2); return OperateResult.CreateSuccessResult(); } else { return new OperateResult(StringResources.Language.NotSupportedDataType); } } #endregion #region Bool Read Write Operate /// /// 读取指定地址的bool数据对象 /// /// 西门子的地址信息 /// 带有成功标志的结果对象 public OperateResult ReadBool(string address) { OperateResult read = ReadBool(address, 1); if (!read.IsSuccess) return OperateResult.CreateFailedResult(read); return OperateResult.CreateSuccessResult(read.Content[0]); } /// /// 读取指定地址的bool数据对象 /// /// 三菱的地址信息 /// 数组的长度 /// 带有成功标志的结果对象 public OperateResult ReadBool(string address, ushort length) { OperateResult analysis = MelsecHelper.McAnalysisAddress(address); if (!analysis.IsSuccess) return OperateResult.CreateFailedResult(analysis); if (analysis.Content1.DataType == 0) return new OperateResult(StringResources.Language.MelsecCurrentTypeNotSupportedWordOperate); if (analysis.Content1.DataCode == MelsecMcDataType.M.DataCode) { return OperateResult.CreateSuccessResult(mBuffer.GetBytes(analysis.Content2, length).Select(m => m != 0x00).ToArray()); } else if (analysis.Content1.DataCode == MelsecMcDataType.X.DataCode) { return OperateResult.CreateSuccessResult(xBuffer.GetBytes(analysis.Content2, length).Select(m => m != 0x00).ToArray()); } else if (analysis.Content1.DataCode == MelsecMcDataType.Y.DataCode) { return OperateResult.CreateSuccessResult(yBuffer.GetBytes(analysis.Content2, length).Select(m => m != 0x00).ToArray()); } else if (analysis.Content1.DataCode == MelsecMcDataType.B.DataCode) { return OperateResult.CreateSuccessResult(yBuffer.GetBytes(analysis.Content2, length).Select(m => m != 0x00).ToArray()); } else { return new OperateResult(StringResources.Language.NotSupportedDataType); } } /// /// 往指定的地址里写入bool数据对象 /// /// 三菱的地址信息 /// 值 /// 是否成功的结果 public OperateResult Write(string address, bool value) { return Write(address, new bool[] { value }); } /// /// 往指定的地址里写入bool数组对象 /// /// 三菱的地址信息 /// 值 /// 是否成功的结果 public OperateResult Write(string address, bool[] value) { OperateResult analysis = MelsecHelper.McAnalysisAddress(address); if (!analysis.IsSuccess) return OperateResult.CreateFailedResult(analysis); if (analysis.Content1.DataType == 0) return new OperateResult(StringResources.Language.MelsecCurrentTypeNotSupportedWordOperate); if (analysis.Content1.DataCode == MelsecMcDataType.M.DataCode) { mBuffer.SetBytes(value.Select(m => m ? (byte)1 : (byte)0).ToArray(), analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.X.DataCode) { xBuffer.SetBytes(value.Select(m => m ? (byte)1 : (byte)0).ToArray(), analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.Y.DataCode) { yBuffer.SetBytes(value.Select(m => m ? (byte)1 : (byte)0).ToArray(), analysis.Content2); return OperateResult.CreateSuccessResult(); } else if (analysis.Content1.DataCode == MelsecMcDataType.B.DataCode) { yBuffer.SetBytes(value.Select(m => m ? (byte)1 : (byte)0).ToArray(), analysis.Content2); return OperateResult.CreateSuccessResult(); } else { return new OperateResult(StringResources.Language.NotSupportedDataType); } } #endregion #region NetServer Override /// /// 当客户端登录后,进行Ip信息的过滤,然后触发本方法,也就是说之后的客户端需要 /// /// 网络套接字 /// 终端节点 protected override void ThreadPoolLoginAfterClientCheck(Socket socket, System.Net.IPEndPoint endPoint) { // 开始接收数据信息 AppSession appSession = new AppSession(); appSession.IpEndPoint = endPoint; appSession.WorkSocket = socket; try { socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(SocketAsyncCallBack), appSession); AddClient(appSession); } catch { socket.Close(); LOG.Write(ToString()+string.Format(StringResources.Language.ClientOfflineInfo, endPoint)); } } private void SocketAsyncCallBack(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int receiveCount = session.WorkSocket.EndReceive(ar); MelsecQnA3EBinaryMessage mcMessage = new MelsecQnA3EBinaryMessage(); OperateResult read1 = ReceiveByMessage(session.WorkSocket, 5000, mcMessage); if (!read1.IsSuccess) { LOG.Write(ToString()+string.Format(StringResources.Language.ClientOfflineInfo+session.IpEndPoint)); RemoveClient(session); return; }; byte[] back = ReadFromMcCore(read1.Content); if (back != null) { session.WorkSocket.Send(back); } else { session.WorkSocket.Close(); RemoveClient(session); return; } RaiseDataReceived(read1.Content); session.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(SocketAsyncCallBack), session); } catch { // 关闭连接,记录日志 session.WorkSocket?.Close(); LOG.Write(ToString()+ string.Format(StringResources.Language.ClientOfflineInfo+session.IpEndPoint)); RemoveClient(session); return; } } } /// /// 当收到mc协议的报文的时候应该触发的方法,允许继承重写,来实现自定义的返回,或是数据监听。 /// /// mc报文 /// 返回的报文信息 protected virtual byte[] ReadFromMcCore(byte[] mcCore) { if (mcCore[11] == 0x01 && mcCore[12] == 0x04) { // 读数据 return PackCommand(ReadByCommand(SoftBasic.BytesArrayRemoveBegin(mcCore, 11))); } else if (mcCore[11] == 0x01 && mcCore[12] == 0x14) { // 写数据 return PackCommand(WriteByMessage(SoftBasic.BytesArrayRemoveBegin(mcCore, 11))); } else { return null; } } private byte[] PackCommand(byte[] data) { byte[] back = new byte[11 + data.Length]; SoftBasic.HexStringToBytes("D0 00 00 FF FF 03 00 00 00 00 00").CopyTo(back, 0); if (data.Length > 0) data.CopyTo(back, 11); BitConverter.GetBytes((short)(data.Length + 2)).CopyTo(back, 7); return back; } private byte[] ReadByCommand(byte[] command) { if (command[2] == 0x01) { // 位读取 ushort length = ByteTransform.TransUInt16(command, 8); int startIndex = (command[6] * 65536 + command[5] * 256 + command[4]); if (command[7] == MelsecMcDataType.M.DataCode) { byte[] buffer = mBuffer.GetBytes(startIndex, length); return MelsecHelper.TransBoolArrayToByteData(buffer); } else if (command[7] == MelsecMcDataType.X.DataCode) { byte[] buffer = xBuffer.GetBytes(startIndex, length); return MelsecHelper.TransBoolArrayToByteData(buffer); } else if (command[7] == MelsecMcDataType.Y.DataCode) { byte[] buffer = yBuffer.GetBytes(startIndex, length); return MelsecHelper.TransBoolArrayToByteData(buffer); } else if (command[7] == MelsecMcDataType.B.DataCode) { byte[] buffer = yBuffer.GetBytes(startIndex, length); return MelsecHelper.TransBoolArrayToByteData(buffer); } else { throw new Exception(StringResources.Language.NotSupportedDataType); } } else { // 字读取 ushort length = ByteTransform.TransUInt16(command, 8); int startIndex = (command[6] * 65536 + command[5] * 256 + command[4]); if (command[7] == MelsecMcDataType.M.DataCode) { bool[] buffer = mBuffer.GetBytes(startIndex, length * 16).Select(m => m != 0x00).ToArray(); return SoftBasic.BoolArrayToByte(buffer); } else if (command[7] == MelsecMcDataType.X.DataCode) { bool[] buffer = xBuffer.GetBytes(startIndex, length * 16).Select(m => m != 0x00).ToArray(); return SoftBasic.BoolArrayToByte(buffer); } else if (command[7] == MelsecMcDataType.Y.DataCode) { bool[] buffer = yBuffer.GetBytes(startIndex, length * 16).Select(m => m != 0x00).ToArray(); return SoftBasic.BoolArrayToByte(buffer); } else if (command[7] == MelsecMcDataType.D.DataCode) { bool[] buffer = yBuffer.GetBytes(startIndex, length * 16).Select(m => m != 0x00).ToArray(); return SoftBasic.BoolArrayToByte(buffer); } else if (command[7] == MelsecMcDataType.D.DataCode) { return dBuffer.GetBytes(startIndex * 2, length * 2); } else if (command[7] == MelsecMcDataType.W.DataCode) { return wBuffer.GetBytes(startIndex * 2, length * 2); } else { throw new Exception(StringResources.Language.NotSupportedDataType); } } } private byte[] WriteByMessage(byte[] command) { if (command[2] == 0x01) { // 位写入 ushort length = ByteTransform.TransUInt16(command, 8); int startIndex = (command[6] * 65536 + command[5] * 256 + command[4]); if (command[7] == MelsecMcDataType.M.DataCode) { byte[] buffer = MelsecMcNet.ExtractActualData(SoftBasic.BytesArrayRemoveBegin(command, 10), true).Content; mBuffer.SetBytes(buffer.Take(length).ToArray(), startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.X.DataCode) { byte[] buffer = MelsecMcNet.ExtractActualData(SoftBasic.BytesArrayRemoveBegin(command, 10), true).Content; xBuffer.SetBytes(buffer.Take(length).ToArray(), startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.Y.DataCode) { byte[] buffer = MelsecMcNet.ExtractActualData(SoftBasic.BytesArrayRemoveBegin(command, 10), true).Content; yBuffer.SetBytes(buffer.Take(length).ToArray(), startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.B.DataCode) { byte[] buffer = MelsecMcNet.ExtractActualData(SoftBasic.BytesArrayRemoveBegin(command, 10), true).Content; yBuffer.SetBytes(buffer.Take(length).ToArray(), startIndex); return new byte[0]; } else { throw new Exception(StringResources.Language.NotSupportedDataType); } } else { // 字写入 ushort length = ByteTransform.TransUInt16(command, 8); int startIndex = (command[6] * 65536 + command[5] * 256 + command[4]); if (command[7] == MelsecMcDataType.M.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(SoftBasic.BytesArrayRemoveBegin(command, 10)).Select(m => m ? (byte)1 : (byte)0).ToArray(); mBuffer.SetBytes(buffer, startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.X.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(SoftBasic.BytesArrayRemoveBegin(command, 10)).Select(m => m ? (byte)1 : (byte)0).ToArray(); xBuffer.SetBytes(buffer, startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.Y.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(SoftBasic.BytesArrayRemoveBegin(command, 10)).Select(m => m ? (byte)1 : (byte)0).ToArray(); yBuffer.SetBytes(buffer, startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.B.DataCode) { byte[] buffer = SoftBasic.ByteToBoolArray(SoftBasic.BytesArrayRemoveBegin(command, 10)).Select(m => m ? (byte)1 : (byte)0).ToArray(); yBuffer.SetBytes(buffer, startIndex); return new byte[0]; } else if (command[7] == MelsecMcDataType.D.DataCode) { dBuffer.SetBytes(SoftBasic.BytesArrayRemoveBegin(command, 10), startIndex * 2); return new byte[0]; } else if (command[7] == MelsecMcDataType.W.DataCode) { wBuffer.SetBytes(SoftBasic.BytesArrayRemoveBegin(command, 10), startIndex * 2); return new byte[0]; } else { throw new Exception(StringResources.Language.NotSupportedDataType); } } } #endregion #region Data Save Load Override /// /// 从字节数据加载数据信息 /// /// 字节数据 protected override void LoadFromBytes(byte[] content) { if (content.Length < DataPoolLength * 7) throw new Exception("File is not correct"); mBuffer.SetBytes(content, 0, 0, DataPoolLength); xBuffer.SetBytes(content, DataPoolLength, 0, DataPoolLength); yBuffer.SetBytes(content, DataPoolLength * 2, 0, DataPoolLength); dBuffer.SetBytes(content, DataPoolLength * 3, 0, DataPoolLength); wBuffer.SetBytes(content, DataPoolLength * 5, 0, DataPoolLength); } /// /// 将数据信息存储到字节数组去 /// /// 所有的内容 protected override byte[] SaveToBytes() { byte[] buffer = new byte[DataPoolLength * 7]; Array.Copy(mBuffer.GetBytes(), 0, buffer, 0, DataPoolLength); Array.Copy(xBuffer.GetBytes(), 0, buffer, DataPoolLength, DataPoolLength); Array.Copy(yBuffer.GetBytes(), 0, buffer, DataPoolLength * 2, DataPoolLength); Array.Copy(dBuffer.GetBytes(), 0, buffer, DataPoolLength * 3, DataPoolLength); Array.Copy(wBuffer.GetBytes(), 0, buffer, DataPoolLength * 5, DataPoolLength); return buffer; } #endregion #region Private Member private SoftBuffer xBuffer; // x寄存器的数据池 private SoftBuffer yBuffer; // y寄存器的数据池 private SoftBuffer mBuffer; // m寄存器的数据池 private SoftBuffer dBuffer; // d寄存器的数据池 private SoftBuffer wBuffer; // w寄存器的数据池 private const int DataPoolLength = 200000; // 数据的长度 #endregion #region Object Override /// /// 返回表示当前对象的字符串 /// /// 字符串信息 public override string ToString() { return $"MelsecMcServer[{Port}]"; } #endregion } }