/// <summary> /// 根据类型地址以及需要写入的数据来生成指令头 /// </summary> /// <param name="address">起始地址</param> /// <param name="value">实际的数据信息</param> /// <returns>带有成功标志的指令数据</returns> public static OperateResult <byte[]> BuildWriteWordCommand(string address, byte[] value) { var addressResult = FxCalculateWordStartAddress(address); if (!addressResult.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(addressResult)); } // 字节数据转换成ASCII格式 if (value != null) { value = MelsecHelper.BuildBytesFromData(value); } ushort startAddress = addressResult.Content; byte[] _PLCCommand = new byte[11 + value.Length]; _PLCCommand[0] = 0x02; // STX _PLCCommand[1] = 0x31; // Read _PLCCommand[2] = MelsecHelper.BuildBytesFromData(startAddress)[0]; // Offect Address _PLCCommand[3] = MelsecHelper.BuildBytesFromData(startAddress)[1]; _PLCCommand[4] = MelsecHelper.BuildBytesFromData(startAddress)[2]; _PLCCommand[5] = MelsecHelper.BuildBytesFromData(startAddress)[3]; _PLCCommand[6] = MelsecHelper.BuildBytesFromData((byte)(value.Length / 2))[0]; // Read Length _PLCCommand[7] = MelsecHelper.BuildBytesFromData((byte)(value.Length / 2))[1]; Array.Copy(value, 0, _PLCCommand, 8, value.Length); _PLCCommand[_PLCCommand.Length - 3] = 0x03; // ETX MelsecHelper.FxCalculateCRC(_PLCCommand).CopyTo(_PLCCommand, _PLCCommand.Length - 2); // CRC return(OperateResult.CreateSuccessResult(_PLCCommand)); }
/// <summary> /// 根据类型地址长度确认需要读取的指令头 /// </summary> /// <param name="address">起始地址</param> /// <param name="length">长度</param> /// <returns>带有成功标志的指令数据</returns> public static OperateResult <byte[]> BuildReadWordCommand(string address, ushort length) { var addressResult = FxCalculateWordStartAddress(address); if (!addressResult.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(addressResult)); } length = (ushort)(length * 2); ushort startAddress = addressResult.Content; byte[] _PLCCommand = new byte[11]; _PLCCommand[0] = 0x02; // STX _PLCCommand[1] = 0x30; // Read _PLCCommand[2] = MelsecHelper.BuildBytesFromData(startAddress)[0]; // 偏移地址 _PLCCommand[3] = MelsecHelper.BuildBytesFromData(startAddress)[1]; _PLCCommand[4] = MelsecHelper.BuildBytesFromData(startAddress)[2]; _PLCCommand[5] = MelsecHelper.BuildBytesFromData(startAddress)[3]; _PLCCommand[6] = MelsecHelper.BuildBytesFromData((byte)length)[0]; // 读取长度 _PLCCommand[7] = MelsecHelper.BuildBytesFromData((byte)length)[1]; _PLCCommand[8] = 0x03; // ETX MelsecHelper.FxCalculateCRC(_PLCCommand).CopyTo(_PLCCommand, 9); // CRC return(OperateResult.CreateSuccessResult(_PLCCommand)); // Return }
/// <summary> /// 根据类型地址长度确认需要读取的指令头 /// </summary> /// <param name="address">起始地址</param> /// <param name="length">bool数组长度</param> /// <returns>带有成功标志的指令数据</returns> public static OperateResult <byte[], int> BuildReadBoolCommand(string address, ushort length) { var addressResult = FxCalculateBoolStartAddress(address); if (!addressResult.IsSuccess) { return(OperateResult.CreateFailedResult <byte[], int>(addressResult)); } // 计算下实际需要读取的数据长度 ushort length2 = (ushort)((addressResult.Content2 + length - 1) / 8 - (addressResult.Content2 / 8) + 1); ushort startAddress = addressResult.Content1; byte[] _PLCCommand = new byte[11]; _PLCCommand[0] = 0x02; // STX _PLCCommand[1] = 0x30; // Read _PLCCommand[2] = MelsecHelper.BuildBytesFromData(startAddress)[0]; // 偏移地址 _PLCCommand[3] = MelsecHelper.BuildBytesFromData(startAddress)[1]; _PLCCommand[4] = MelsecHelper.BuildBytesFromData(startAddress)[2]; _PLCCommand[5] = MelsecHelper.BuildBytesFromData(startAddress)[3]; _PLCCommand[6] = MelsecHelper.BuildBytesFromData((byte)length2)[0]; // 读取长度 _PLCCommand[7] = MelsecHelper.BuildBytesFromData((byte)length2)[1]; _PLCCommand[8] = 0x03; // ETX MelsecHelper.FxCalculateCRC(_PLCCommand).CopyTo(_PLCCommand, 9); // CRC return(OperateResult.CreateSuccessResult(_PLCCommand, (int)addressResult.Content3)); }
/// <summary> /// 将MC协议的核心报文打包成一个可以直接对PLC进行发送的原始报文 /// </summary> /// <param name="mcCore">MC协议的核心报文</param> /// <param name="networkNumber">网络号</param> /// <param name="networkStationNumber">网络站号</param> /// <returns>原始报文信息</returns> public static byte[] PackMcCommand(byte[] mcCore, byte networkNumber = 0, byte networkStationNumber = 0) { byte[] plcCommand = new byte[22 + mcCore.Length]; plcCommand[0] = 0x35; // 副标题 plcCommand[1] = 0x30; plcCommand[2] = 0x30; plcCommand[3] = 0x30; plcCommand[4] = MelsecHelper.BuildBytesFromData(networkNumber)[0]; // 网络号 plcCommand[5] = MelsecHelper.BuildBytesFromData(networkNumber)[1]; plcCommand[6] = 0x46; // PLC编号 plcCommand[7] = 0x46; plcCommand[8] = 0x30; // 目标模块IO编号 plcCommand[9] = 0x33; plcCommand[10] = 0x46; plcCommand[11] = 0x46; plcCommand[12] = MelsecHelper.BuildBytesFromData(networkStationNumber)[0]; // 目标模块站号 plcCommand[13] = MelsecHelper.BuildBytesFromData(networkStationNumber)[1]; plcCommand[14] = MelsecHelper.BuildBytesFromData((ushort)(plcCommand.Length - 18))[0]; // 请求数据长度 plcCommand[15] = MelsecHelper.BuildBytesFromData((ushort)(plcCommand.Length - 18))[1]; plcCommand[16] = MelsecHelper.BuildBytesFromData((ushort)(plcCommand.Length - 18))[2]; plcCommand[17] = MelsecHelper.BuildBytesFromData((ushort)(plcCommand.Length - 18))[3]; plcCommand[18] = 0x30; // CPU监视定时器 plcCommand[19] = 0x30; plcCommand[20] = 0x31; plcCommand[21] = 0x30; mcCore.CopyTo(plcCommand, 22); return(plcCommand); }
/// <summary> /// 从地址,长度,是否位读取进行创建读取Ascii格式的MC的核心报文 /// </summary> /// <param name="address">三菱的地址信息,具体格式参照<seealso cref="MelsecMcNet"/> 的注释说明</param> /// <param name="length">读取的长度信息</param> /// <param name="isBit">是否进行了位读取操作</param> /// <param name="analysisAddress">对地址分析的委托方法</param> /// <returns>带有成功标识的报文对象</returns> public static OperateResult <byte[]> BuildAsciiReadMcCoreCommand(string address, ushort length, bool isBit, Func <string, OperateResult <MelsecMcDataType, int> > analysisAddress) { OperateResult <MelsecMcDataType, int> analysis = analysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } byte[] command = new byte[20]; command[0] = 0x30; // 批量读取数据命令 command[1] = 0x34; command[2] = 0x30; command[3] = 0x31; command[4] = 0x30; // 以点为单位还是字为单位成批读取 command[5] = 0x30; command[6] = 0x30; command[7] = isBit ? (byte)0x31 : (byte)0x30; command[8] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[0]; // 软元件类型 command[9] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[1]; command[10] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[0]; // 起始地址的地位 command[11] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[1]; command[12] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[2]; command[13] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[3]; command[14] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[4]; command[15] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[5]; command[16] = MelsecHelper.BuildBytesFromData(length)[0]; // 软元件点数 command[17] = MelsecHelper.BuildBytesFromData(length)[1]; command[18] = MelsecHelper.BuildBytesFromData(length)[2]; command[19] = MelsecHelper.BuildBytesFromData(length)[3]; return(OperateResult.CreateSuccessResult(command)); }
/// <summary> /// 以字为单位,创建ASCII数据写入的核心报文 /// </summary> /// <param name="address">三菱的地址信息,具体格式参照<seealso cref="MelsecMcNet"/> 的注释说明</param> /// <param name="value">实际的原始数据信息</param> /// <param name="analysisAddress">对地址分析的委托方法</param> /// <returns>带有成功标识的报文对象</returns> public static OperateResult <byte[]> BuildAsciiWriteWordCoreCommand(string address, byte[] value, Func <string, OperateResult <MelsecMcDataType, int> > analysisAddress) { OperateResult <MelsecMcDataType, int> analysis = analysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } if (value == null) { value = new byte[0]; } byte[] buffer = new byte[value.Length * 2]; for (int i = 0; i < value.Length / 2; i++) { MelsecHelper.BuildBytesFromData(BitConverter.ToUInt16(value, i * 2)).CopyTo(buffer, 4 * i); } value = buffer; byte[] command = new byte[20 + value.Length]; command[0] = 0x31; // 批量写入的命令 command[1] = 0x34; command[2] = 0x30; command[3] = 0x31; command[4] = 0x30; // 子命令 command[5] = 0x30; command[6] = 0x30; command[7] = 0x30; command[8] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[0]; // 软元件类型 command[9] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[1]; command[10] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[0]; // 起始地址的地位 command[11] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[1]; command[12] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[2]; command[13] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[3]; command[14] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[4]; command[15] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[5]; command[16] = MelsecHelper.BuildBytesFromData((ushort)(value.Length / 4))[0]; // 软元件点数 command[17] = MelsecHelper.BuildBytesFromData((ushort)(value.Length / 4))[1]; command[18] = MelsecHelper.BuildBytesFromData((ushort)(value.Length / 4))[2]; command[19] = MelsecHelper.BuildBytesFromData((ushort)(value.Length / 4))[3]; value.CopyTo(command, 20); return(OperateResult.CreateSuccessResult(command)); }
/// <summary> /// 以位为单位,创建ASCII数据写入的核心报文 /// </summary> /// <param name="address">三菱的地址信息,具体格式参照<seealso cref="MelsecMcNet"/> 的注释说明</param> /// <param name="value">原始的bool数组数据</param> /// <param name="analysisAddress">对地址分析的委托方法</param> /// <returns>带有成功标识的报文对象</returns> public static OperateResult <byte[]> BuildAsciiWriteBitCoreCommand(string address, bool[] value, Func <string, OperateResult <MelsecMcDataType, int> > analysisAddress) { OperateResult <MelsecMcDataType, int> analysis = analysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } if (value == null) { value = new bool[0]; } byte[] buffer = value.Select(m => m ? (byte)0x31 : (byte)0x30).ToArray( ); byte[] command = new byte[20 + buffer.Length]; command[0] = 0x31; // 批量写入的命令 command[1] = 0x34; command[2] = 0x30; command[3] = 0x31; command[4] = 0x30; // 子命令 command[5] = 0x30; command[6] = 0x30; command[7] = 0x31; command[8] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[0]; // 软元件类型 command[9] = Encoding.ASCII.GetBytes(analysis.Content1.AsciiCode)[1]; command[10] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[0]; // 起始地址的地位 command[11] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[1]; command[12] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[2]; command[13] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[3]; command[14] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[4]; command[15] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[5]; command[16] = MelsecHelper.BuildBytesFromData((ushort)(value.Length))[0]; // 软元件点数 command[17] = MelsecHelper.BuildBytesFromData((ushort)(value.Length))[1]; command[18] = MelsecHelper.BuildBytesFromData((ushort)(value.Length))[2]; command[19] = MelsecHelper.BuildBytesFromData((ushort)(value.Length))[3]; buffer.CopyTo(command, 20); return(OperateResult.CreateSuccessResult(command)); }
/// <summary> /// 生成位写入的数据报文信息,该报文可直接用于发送串口给PLC /// </summary> /// <param name="address">地址信息,每个地址存在一定的范围,需要谨慎传入数据。举例:M10,S10,X5,Y10,C10,T10</param> /// <param name="value"><c>True</c>或是<c>False</c></param> /// <returns>带报文信息的结果对象</returns> public static OperateResult <byte[]> BuildWriteBoolPacket(string address, bool value) { var analysis = FxAnalysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 二次运算起始地址偏移量,根据类型的不同,地址的计算方式不同 ushort startAddress = analysis.Content2; if (analysis.Content1 == MelsecMcDataType.M) { if (startAddress >= 8000) { startAddress = (ushort)(startAddress - 8000 + 0x0F00); } else { startAddress = (ushort)(startAddress + 0x0800); } } else if (analysis.Content1 == MelsecMcDataType.S) { startAddress = (ushort)(startAddress + 0x0000); } else if (analysis.Content1 == MelsecMcDataType.X) { startAddress = (ushort)(startAddress + 0x0400); } else if (analysis.Content1 == MelsecMcDataType.Y) { startAddress = (ushort)(startAddress + 0x0500); } else if (analysis.Content1 == MelsecMcDataType.CS) { startAddress += (ushort)(startAddress + 0x01C0); } else if (analysis.Content1 == MelsecMcDataType.CC) { startAddress += (ushort)(startAddress + 0x03C0); } else if (analysis.Content1 == MelsecMcDataType.CN) { startAddress += (ushort)(startAddress + 0x0E00); } else if (analysis.Content1 == MelsecMcDataType.TS) { startAddress += (ushort)(startAddress + 0x00C0); } else if (analysis.Content1 == MelsecMcDataType.TC) { startAddress += (ushort)(startAddress + 0x02C0); } else if (analysis.Content1 == MelsecMcDataType.TN) { startAddress += (ushort)(startAddress + 0x0600); } else { return(new OperateResult <byte[]>(StringResources.Language.MelsecCurrentTypeNotSupportedBitOperate)); } byte[] _PLCCommand = new byte[9]; _PLCCommand[0] = 0x02; // STX _PLCCommand[1] = value ? (byte)0x37 : (byte)0x38; // Read _PLCCommand[2] = MelsecHelper.BuildBytesFromData(startAddress)[2]; // 偏移地址 _PLCCommand[3] = MelsecHelper.BuildBytesFromData(startAddress)[3]; _PLCCommand[4] = MelsecHelper.BuildBytesFromData(startAddress)[0]; _PLCCommand[5] = MelsecHelper.BuildBytesFromData(startAddress)[1]; _PLCCommand[6] = 0x03; // ETX MelsecHelper.FxCalculateCRC(_PLCCommand).CopyTo(_PLCCommand, 7); // CRC return(OperateResult.CreateSuccessResult(_PLCCommand)); }