/// <summary> /// 以位为单位,创建数据写入的核心报文 /// </summary> /// <param name="address">三菱的地址信息,具体格式参照<seealso cref="MelsecMcNet"/> 的注释说明</param> /// <param name="value">原始的bool数组数据</param> /// <param name="analysisAddress">对地址分析的委托方法</param> /// <returns>带有成功标识的报文对象</returns> public static OperateResult <byte[]> BuildWriteBitCoreCommand(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 = MelsecHelper.TransBoolArrayToByteData(value); byte[] command = new byte[10 + buffer.Length]; command[0] = 0x01; // 批量写入数据命令 command[1] = 0x14; command[2] = 0x01; // 以位为单位成批写入 command[3] = 0x00; command[4] = BitConverter.GetBytes(analysis.Content2)[0]; // 起始地址的地位 command[5] = BitConverter.GetBytes(analysis.Content2)[1]; command[6] = BitConverter.GetBytes(analysis.Content2)[2]; command[7] = analysis.Content1.DataCode; // 指明写入的数据 command[8] = (byte)(value.Length % 256); // 软元件长度的地位 command[9] = (byte)(value.Length / 256); buffer.CopyTo(command, 10); return(OperateResult.CreateSuccessResult(command)); }
/// <summary> /// 根据类型地址以及需要写入的数据来生成指令头 /// </summary> /// <param name="address">起始地址</param> /// <param name="value">数据值</param> /// <param name="plcNumber">PLC编号</param> /// <returns>带有成功标志的指令数据</returns> public static OperateResult <byte[]> BuildWriteCommand(string address, byte[] value, byte plcNumber) { var analysis = MelsecHelper.McA1EAnalysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } int length = -1; if (analysis.Content1.DataType == 1) { // 按照位写入的操作,数据需要重新计算 length = value.Length; value = MelsecHelper.TransBoolArrayToByteData(value); } // 默认信息----注意:高低字节交错 byte subtitle = analysis.Content1.DataType == 0x01 ? (byte)0x02 : (byte)0x03; byte[] _PLCCommand = new byte[12 + value.Length]; _PLCCommand[0] = subtitle; // 副标题 _PLCCommand[1] = plcNumber; // PLC号 _PLCCommand[2] = 0x0A; // CPU监视定时器(L)这里设置为0x00,0x0A,等待CPU返回的时间为10*250ms=2.5秒 _PLCCommand[3] = 0x00; // CPU监视定时器(H) _PLCCommand[4] = (byte)(analysis.Content2 % 256); // 起始软元件(开始读取的地址) _PLCCommand[5] = (byte)(analysis.Content2 / 256); _PLCCommand[6] = 0x00; _PLCCommand[7] = 0x00; _PLCCommand[8] = analysis.Content1.DataCode[1]; // 软元件代码(L) _PLCCommand[9] = analysis.Content1.DataCode[0]; // 软元件代码(H) _PLCCommand[10] = (byte)(length % 256); // 软元件点数 _PLCCommand[11] = 0x00; // 判断是否进行位操作 if (analysis.Content1.DataType == 0x01) { if (length > 0) { _PLCCommand[10] = (byte)(length % 256); // 软元件点数 } else { _PLCCommand[10] = (byte)(value.Length * 2 % 256); // 软元件点数 } } else { _PLCCommand[10] = (byte)(value.Length / 2 % 256); // 软元件点数 } Array.Copy(value, 0, _PLCCommand, 12, value.Length); // 将具体的要写入的数据附加到写入命令后面 return(OperateResult.CreateSuccessResult(_PLCCommand)); }
/// <summary> /// 向PLC写入数据,数据格式为原始的字节类型 /// </summary> /// <param name="address">初始地址</param> /// <param name="value">原始的字节数据</param> /// <returns>返回写入结果</returns> public override OperateResult Write(string address, byte[] value) { // 地址解析 var analysis = AnalysisAddress(address); if (!analysis.IsSuccess) { return(analysis); } OperateResult <MelsecA1EDataType, byte[]> command; // 预处理指令 if (analysis.Content1.DataType == 0x01) { // 位写入 command = BuildWriteCommand(address, MelsecHelper.TransBoolArrayToByteData(value), value.Length); } else { // 字写入 command = BuildWriteCommand(address, value); } if (!command.IsSuccess) { return(command); } OperateResult <byte[]> read = ReadFromCoreServer(command.Content2); if (!read.IsSuccess) { return(read); } if (read.Content[1] == 0) { return(OperateResult.CreateSuccessResult( )); } else { // 在A兼容1E协议中,结束代码后面紧跟的是异常信息的代码} return(new OperateResult(read.Content[1], StringResources.Language.MelsecPleaseReferToManulDocument)); } }
/// <summary> /// 以位为单位,创建数据写入的核心报文 /// </summary> /// <param name="addressData">三菱Mc协议的数据地址</param> /// <param name="value">原始的bool数组数据</param> /// <returns>带有成功标识的报文对象</returns> public static byte[] BuildWriteBitCoreCommand(McAddressData addressData, bool[] value) { if (value == null) { value = new bool[0]; } byte[] buffer = MelsecHelper.TransBoolArrayToByteData(value); byte[] command = new byte[10 + buffer.Length]; command[0] = 0x01; // 批量写入数据命令 command[1] = 0x14; command[2] = 0x01; // 以位为单位成批写入 command[3] = 0x00; command[4] = BitConverter.GetBytes(addressData.AddressStart)[0]; // 起始地址的地位 command[5] = BitConverter.GetBytes(addressData.AddressStart)[1]; command[6] = BitConverter.GetBytes(addressData.AddressStart)[2]; command[7] = addressData.McDataType.DataCode; // 指明写入的数据 command[8] = (byte)(value.Length % 256); // 软元件长度的地位 command[9] = (byte)(value.Length / 256); buffer.CopyTo(command, 10); return(command); }
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 { 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) { 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); } } }
/// <summary> /// 根据类型地址以及需要写入的数据来生成指令头 /// </summary> /// <param name="address">起始地址</param> /// <param name="value">数据值,对于写入位地址来说,应该传入{0x01,0x00,0x01} 通断通这样的数组</param> /// <param name="networkNumber">网络号</param> /// <param name="networkStationNumber">网络站号</param> /// <returns>解析后的指令</returns> public static OperateResult <byte[]> BuildWriteCommand(string address, byte[] value, byte networkNumber = 0, byte networkStationNumber = 0) { OperateResult <MelsecMcDataType, int> analysis = MelsecHelper.McAnalysisAddress(address); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } int length = -1; if (analysis.Content1.DataType == 1) { // 按照位写入的操作,数据需要重新计算 length = value.Length; value = MelsecHelper.TransBoolArrayToByteData(value); } byte[] _PLCCommand = new byte[21 + value.Length]; _PLCCommand[0] = 0x50; // 副标题 _PLCCommand[1] = 0x00; _PLCCommand[2] = networkNumber; // 网络号 _PLCCommand[3] = 0xFF; // PLC编号 _PLCCommand[4] = 0xFF; // 目标模块IO编号 _PLCCommand[5] = 0x03; _PLCCommand[6] = networkStationNumber; // 目标模块站号 _PLCCommand[7] = (byte)((_PLCCommand.Length - 9) % 256); // 请求数据长度 _PLCCommand[8] = (byte)((_PLCCommand.Length - 9) / 256); _PLCCommand[9] = 0x0A; // CPU监视定时器 _PLCCommand[10] = 0x00; _PLCCommand[11] = 0x01; // 批量读取数据命令 _PLCCommand[12] = 0x14; _PLCCommand[13] = analysis.Content1.DataType; // 以点为单位还是字为单位成批读取 _PLCCommand[14] = 0x00; _PLCCommand[15] = BitConverter.GetBytes(analysis.Content2)[0]; // 起始地址的地位 _PLCCommand[16] = BitConverter.GetBytes(analysis.Content2)[1]; _PLCCommand[17] = BitConverter.GetBytes(analysis.Content2)[2]; _PLCCommand[18] = analysis.Content1.DataCode; // 指明写入的数据 // 判断是否进行位操作 if (analysis.Content1.DataType == 1) { if (length > 0) { _PLCCommand[19] = (byte)(length % 256); // 软元件长度的地位 _PLCCommand[20] = (byte)(length / 256); } else { _PLCCommand[19] = (byte)(value.Length * 2 % 256); // 软元件长度的地位 _PLCCommand[20] = (byte)(value.Length * 2 / 256); } } else { _PLCCommand[19] = (byte)(value.Length / 2 % 256); // 软元件长度的地位 _PLCCommand[20] = (byte)(value.Length / 2 / 256); } Array.Copy(value, 0, _PLCCommand, 21, value.Length); return(OperateResult.CreateSuccessResult(_PLCCommand)); }