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
}
}