using System; using System.Collections.Generic; using System.Linq; using System.Text; using HslCommunication.Core.Net; using HslCommunication.Core; using System.Net; namespace HslCommunication.Profinet.Omron { /// /// 欧姆龙的Udp的数据对象 /// /// /// 如果在测试的时候报错误码64,经网友 上海-Lex 指点,是因为PLC中产生了报警,如伺服报警,模块错误等产生的,但是数据还是能正常读到的,屏蔽64报警或清除plc错误可解决 /// 地址支持的列表如下: /// /// /// 地址名称 /// 地址代号 /// 示例 /// 地址进制 /// 字操作 /// 位操作 /// 备注 /// /// /// DM Area /// D /// D100,D200 /// 10 /// /// /// /// /// /// CIO Area /// C /// C100,C200 /// 10 /// /// /// /// /// /// Work Area /// W /// W100,W200 /// 10 /// /// /// /// /// /// Holding Bit Area /// H /// H100,H200 /// 10 /// /// /// /// /// /// Auxiliary Bit Area /// A /// A100,A200 /// 10 /// /// /// /// /// /// public class OmronFinsUdp : NetworkUdpDeviceBase { #region Constructor /// /// 实例化一个默认的欧姆龙Udp的对象 /// /// Ip地址 /// 端口号 public OmronFinsUdp(string ipAddress, int port ) { WordLength = 1; IpAddress = ipAddress; Port = port; ByteTransform.DataFormat = DataFormat.CDAB; } /// /// 实例化一个默认的欧姆龙Udp的对象 /// public OmronFinsUdp( ) { WordLength = 1; ByteTransform.DataFormat = DataFormat.CDAB; } #endregion #region IpAddress Override /// /// 设备的Ip地址信息 /// public override string IpAddress { get => base.IpAddress; set { DA1 = Convert.ToByte( value.Substring( value.LastIndexOf( "." ) + 1 ) ); base.IpAddress = value; } } #endregion #region Public Member /// /// 信息控制字段,默认0x80 /// public byte ICF { get; set; } = 0x80; /// /// 系统使用的内部信息 /// public byte RSV { get; private set; } = 0x00; /// /// 网络层信息,默认0x02,如果有八层消息,就设置为0x07 /// public byte GCT { get; set; } = 0x02; /// /// PLC的网络号地址,默认0x00 /// public byte DNA { get; set; } = 0x00; /// /// PLC的节点地址,这个值在配置了ip地址之后是默认赋值的,默认为Ip地址的最后一位 /// /// /// 假如你的PLC的Ip地址为192.168.0.10,那么这个值就是10 /// public byte DA1 { get; set; } = 0x13; /// /// PLC的单元号地址 /// /// /// 通常都为0 /// public byte DA2 { get; set; } = 0x00; /// /// 上位机的网络号地址 /// public byte SNA { get; set; } = 0x00; /// /// 上位机的节点地址,假如你的电脑的Ip地址为192.168.0.13,那么这个值就是13 /// /// /// 假如你的电脑的Ip地址为192.168.0.13,那么这个值就是13 /// public byte SA1 { get; set; } = 13; /// /// 上位机的单元号地址 /// public byte SA2 { get; set; } /// /// 设备的标识号 /// public byte SID { get; set; } = 0x00; #endregion #region Build Command /// /// 将普通的指令打包成完整的指令 /// /// /// private byte[] PackCommand( byte[] cmd ) { byte[] buffer = new byte[10 + cmd.Length]; buffer[0] = ICF; buffer[1] = RSV; buffer[2] = GCT; buffer[3] = DNA; buffer[4] = DA1; buffer[5] = DA2; buffer[6] = SNA; buffer[7] = SA1; buffer[8] = SA2; buffer[9] = SID; cmd.CopyTo( buffer, 10 ); return buffer; } /// /// 根据类型地址长度确认需要读取的指令头 /// /// 起始地址 /// 长度 /// 是否是位读取 /// 带有成功标志的报文数据 public OperateResult BuildReadCommand( string address, ushort length, bool isBit ) { var command = OmronFinsNetHelper.BuildReadCommand( address, length, isBit ); if (!command.IsSuccess) return command; return OperateResult.CreateSuccessResult( PackCommand( command.Content ) ); } /// /// 根据类型地址以及需要写入的数据来生成指令头 /// /// 起始地址 /// 真实的数据值信息 /// 是否是位操作 /// 带有成功标志的报文数据 public OperateResult BuildWriteCommand( string address, byte[] value, bool isBit ) { var command = OmronFinsNetHelper.BuildWriteWordCommand( address, value, isBit ); if (!command.IsSuccess) return command; return OperateResult.CreateSuccessResult( PackCommand( command.Content ) ); } #endregion #region Read Support /// /// 从欧姆龙PLC中读取想要的数据,返回读取结果,读取单位为字 /// /// 读取地址,格式为"D100","C100","W100","H100","A100" /// 读取的数据长度 /// 带成功标志的结果数据对象 /// /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,读取如下: /// /// 以下是读取不同类型数据的示例 /// /// public override OperateResult Read( string address, ushort length ) { // 获取指令 var command = BuildReadCommand( address, length, false ); if (!command.IsSuccess) return OperateResult.CreateFailedResult( command ); // 核心数据交互 OperateResult read = ReadFromCoreServer( command.Content ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); // 数据有效性分析 OperateResult valid = OmronFinsNetHelper.UdpResponseValidAnalysis( read.Content, true ); if (!valid.IsSuccess) return OperateResult.CreateFailedResult( valid ); // 读取到了正确的数据 return OperateResult.CreateSuccessResult( valid.Content ); } /// /// 从欧姆龙PLC中批量读取位软元件,返回读取结果 /// /// 读取地址,格式为"D100","C100","W100","H100","A100" /// 读取的长度 /// 带成功标志的结果数据对象 /// /// /// public OperateResult ReadBool( string address, ushort length ) { // 获取指令 var command = BuildReadCommand( address, length, true ); if (!command.IsSuccess) return OperateResult.CreateFailedResult( command ); // 核心数据交互 OperateResult read = ReadFromCoreServer( command.Content ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); // 数据有效性分析 OperateResult valid = OmronFinsNetHelper.UdpResponseValidAnalysis( read.Content, true ); if (!valid.IsSuccess) return OperateResult.CreateFailedResult( valid ); // 返回正确的数据信息 return OperateResult.CreateSuccessResult( valid.Content.Select( m => m != 0x00 ? true : false ).ToArray( ) ); } /// /// 从欧姆龙PLC中批量读取位软元件,返回读取结果 /// /// 读取地址,格式为"D100.0","C100.15","W100.7","H100.4","A100.9" /// 带成功标志的结果数据对象 /// /// 地址的格式请参照方法 /// /// /// /// public OperateResult ReadBool( string address ) { OperateResult read = ReadBool( address, 1 ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); return OperateResult.CreateSuccessResult( read.Content[0] ); } #endregion #region Write Base /// /// 向PLC写入数据,数据格式为原始的字节类型 /// /// 初始地址 /// 原始的字节数据 /// 结果 /// /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,读取如下: /// /// 以下是写入不同类型数据的示例 /// /// public override OperateResult Write( string address, byte[] value ) { // 获取指令 var command = BuildWriteCommand( address, value, false ); if (!command.IsSuccess) return command; // 核心数据交互 OperateResult read = ReadFromCoreServer( command.Content ); if (!read.IsSuccess) return read; // 数据有效性分析 OperateResult valid = OmronFinsNetHelper.UdpResponseValidAnalysis( read.Content, false ); if (!valid.IsSuccess) return valid; // 成功 return OperateResult.CreateSuccessResult( ); } #endregion #region Write bool[] /// /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0 /// /// 要写入的数据地址 /// 要写入的实际数据,长度为8的倍数 /// 返回写入结果 /// /// /// public OperateResult Write( string address, bool value ) { return Write( address, new bool[] { value } ); } /// /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0 /// /// 要写入的数据地址 /// 要写入的实际数据,可以指定任意的长度 /// 返回写入结果 /// /// /// public OperateResult Write( string address, bool[] values ) { // 获取指令 var command = BuildWriteCommand( address, values.Select( m => m ? (byte)0x01 : (byte)0x00 ).ToArray( ), true ); if (!command.IsSuccess) return command; // 核心数据交互 OperateResult read = ReadFromCoreServer( command.Content ); if (!read.IsSuccess) return read; // 数据有效性分析 OperateResult valid = OmronFinsNetHelper.UdpResponseValidAnalysis( read.Content, false ); if (!valid.IsSuccess) return valid; // 写入成功 return OperateResult.CreateSuccessResult( ); } #endregion #region Object Override /// /// 返回表示当前对象的字符串 /// /// 字符串 public override string ToString( ) { return $"OmronFinsUdp[{IpAddress}:{Port}]"; } #endregion } }