C# OPCUA 读写结构体

2 篇文章 1 订阅

OPCUA结构体的读写说白了就是对ExtensionObject中按规则对byte的转换

读取步骤:

1.首先可以先用UAExpert查看结构体

2.读取出结构体DataValue的值

3.把读取出来的值转换成ExtensionObject[]

4.把ExtensionObject中每项进行解析。

具体步骤解析:

1.首先可以先用UAExpert查看

        如图1我们能看到有一个结构体的数据类型ExtensionObject。这个结构体的有5项,且每个字段都是什么。(这里主要验证我们后期自己读取的数据对不对)

 图1

2.读取出结构体DataValue的值

        这里我们通过session中的ReadValue()方法读取出结构体DataValue的值,这里和正常的已知nodeID读值方法一样(怎么建立连接,大家可以搜随便搜一下就能找到,或者也可以看我前面OPCUA的文章)。

           DataValue item= m_session.ReadValue(new NodeId(ItemAdress));

3.把读取出来的值转换成ExtensionObject[]       

        读取后我们可以看到value的值,如图2,它是一个ExtensionObject类型长为100的数据。而且每项都是byte[],我们要做的就是如何把byte按照规则转换成字符

 4.把ExtensionObject中每项进行解析。

        首先我们先得到ExtensionObject中的结构体的项,下面代码中typeDefine中就能看到结构体中的所有项,大家可以打个断点看看

            NodeId node = new NodeId(ItemAdress);
            //获取Node 信息 验证Node的数据类型
            VariableNode nodeInfo = m_session.ReadNode(node) as VariableNode;
            //DataValue value = m_session.ReadValue(node);
            var datatypeNode = (m_session.ReadNode(nodeInfo.DataType)) as DataTypeNode;
            var typeDefine = datatypeNode.DataTypeDefinition.Body as StructureDefinition;

        然后就是遍历所有项,其中GetJsonFromExtensionObject就是对每项就行解析

            if (value.Value is ExtensionObject[])//数组
            {
                JArray res = new JArray();
                foreach (var item in value.Value as ExtensionObject[])
                {
                    
                    res.Add(GetJsonFromExtensionObject(item, typeDefine,ref index));
                }
                return res.ToString();
            }

        最后对每项项进行解析时,要和相关人员确定byte[]拼接的规则。比如我这里如果该项是字符串,那么首先需要先读取该字符串所占的长度,然后根据长度读取字符串。当然具体项目中的规则也可能不完全相同,但是思路是一样的。如果是int,float直接读取4个byte,bool读取1个byte,double读取8个byte,根据一个类型占多少位决定。下面代码可供参考

        private JObject GetJsonFromExtensionObject(ExtensionObject value, StructureDefinition structure,ref int index)
        {
            JObject res = new JObject();
            var data = value.Body as byte[];
            foreach (var field in structure.Fields)
            {
                if (field.DataType.NamespaceIndex==2)
                {
                    var count = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    var datatypeNode1 = (m_session.ReadNode(field.DataType)) as DataTypeNode;
                    var typeDefine = datatypeNode1.DataTypeDefinition.Body as StructureDefinition;
                    for (int i = 0; i < count; i++)
                    {
                        res[field.Name+i] =GetJsonFromExtensionObject(value, typeDefine,ref index);
                    }
                }
                string name = field.Name;
                if (field.DataType == DataTypeIds.String)
                {
                    int length = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);//读取字符串所占长度
                    index += 4;
                    string re = Encoding.Default.GetString(data.Skip(index).Take(length).ToArray());//根据字符串长度读取字符串
                    res[name] = re;
                    index += length;
                }
                if (field.DataType == DataTypeIds.UInt32)
                {
                    UInt32 re = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    res[name] = re;
                }
                if (field.DataType == DataTypeIds.Float)
                {
                    float re = BitConverter.ToSingle(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    res[name] = re;
                }
                if (field.DataType == DataTypeIds.Boolean)
                {
                    bool re = BitConverter.ToBoolean(data.Skip(index).Take(1).ToArray());
                    res[name] = re;
                    index += 1;
                }
                if (field.DataType == DataTypeIds.Double)
                {
                    double re = BitConverter.ToDouble(data.Skip(index).Take(8).ToArray());
                    res[name] = re;
                    index += 8;
                }
            }
            return res;
        }

读取结构体完整代码如下:

public string structItem(string ItemAdress)
        {
           DataValue item= m_session.ReadValue(new NodeId(ItemAdress));
            string aaa = ReadStruct(ItemAdress, item);
            return aaa;
        }
        /// <summary>
        /// 读取结构体数据
        /// </summary>
        public string ReadStruct(string ItemAdress, DataValue value)
        {
            #region 得到ExtensionObject中的结构体的项
            NodeId node = new NodeId(ItemAdress);
            //获取Node 信息 验证Node的数据类型
            VariableNode nodeInfo = m_session.ReadNode(node) as VariableNode;
            //DataValue value = m_session.ReadValue(node);
            var datatypeNode = (m_session.ReadNode(nodeInfo.DataType)) as DataTypeNode;
            var typeDefine = datatypeNode.DataTypeDefinition.Body as StructureDefinition;
            #endregion

            int index = 0;
            if (value.Value is ExtensionObject[])//数组
            {
                JArray res = new JArray();
                foreach (var item in value.Value as ExtensionObject[])
                {
                    
                    res.Add(GetJsonFromExtensionObject(item, typeDefine,ref index));
                }
                return res.ToString();
            }
            else //非数组
            {
                return GetJsonFromExtensionObject(value.Value as ExtensionObject, typeDefine, ref index).ToString();
            }

        }
        private JObject GetJsonFromExtensionObject(ExtensionObject value, StructureDefinition structure,ref int index)
        {
            JObject res = new JObject();
            var data = value.Body as byte[];
            foreach (var field in structure.Fields)
            {
                if (field.DataType.NamespaceIndex==2)
                {
                    var count = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    var datatypeNode1 = (m_session.ReadNode(field.DataType)) as DataTypeNode;
                    var typeDefine = datatypeNode1.DataTypeDefinition.Body as StructureDefinition;
                    for (int i = 0; i < count; i++)
                    {
                        res[field.Name+i] =GetJsonFromExtensionObject(value, typeDefine,ref index);
                    }
                }
                string name = field.Name;
                if (field.DataType == DataTypeIds.String)
                {
                    int length = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);//读取字符串所占长度
                    index += 4;
                    string re = Encoding.Default.GetString(data.Skip(index).Take(length).ToArray());//根据字符串长度读取字符串
                    res[name] = re;
                    index += length;
                }
                if (field.DataType == DataTypeIds.UInt32)
                {
                    UInt32 re = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    res[name] = re;
                }
                if (field.DataType == DataTypeIds.Float)
                {
                    float re = BitConverter.ToSingle(data.Skip(index).Take(4).ToArray(), 0);
                    index += 4;
                    res[name] = re;
                }
                if (field.DataType == DataTypeIds.Boolean)
                {
                    bool re = BitConverter.ToBoolean(data.Skip(index).Take(1).ToArray());
                    res[name] = re;
                    index += 1;
                }
                if (field.DataType == DataTypeIds.Double)
                {
                    double re = BitConverter.ToDouble(data.Skip(index).Take(8).ToArray());
                    res[name] = re;
                    index += 8;
                }
            }
            return res;
        }

写入步骤:

1.首先可以先用UAExpert查看结构体

2.把每项的结构体转成把ExtensionObject,加入到ExtensionObject[]

3.把ExtensionObject[]写入即可

写入结构体的难点就是如何按照规则(就是拼接方式)把结构体转成byte[]然后加入到ExtensionObject[]

1.首先可以先用UAExpert查看结构体

        同读取,省略

2.把每项的结构体转成把ExtensionObject,加入到ExtensionObject[]

        首先定义一个结构体类,同UAExpert查看结构体,注意结构体顺序也不能乱

        

    /// <summary>
    /// writevar对象
    /// </summary>
    public class WriteVar
    {
        /// <summary>
        /// 数组索引
        /// </summary>
        public int index = 0;
        /// <summary>
        /// 数据项名称
        /// </summary>
        public string Name = "";
        /// <summary>
        /// 数据类型
        /// </summary>
        public int DataType = 0;
        /// <summary>
        /// 字符串值
        /// </summary>
        public string StringValue = "";
        /// <summary>
        /// 整数值
        /// </summary>
        public int IntValue = 0;
        /// <summary>
        /// 浮点数值
        /// </summary>
        public float FloatValue = 0.0F;
    }

        然后赋值给结构体,并转成ExtensionObject,这里我定义的规则就是如果是字符串就要把长度也拼接上

            WriteVar structs = new WriteVar
            {
                index = 4,
                Name = "重量",
                DataType = 0,
                StringValue = "",
                IntValue = 25,
                FloatValue = 0.0F
            };
            var result = Pro_OPCUA.GetValueByteFromObj(structs);

        /// <summary>
        /// 从对象中获取对象所有的值,并转化为byte[]
        /// </summary>
        /// <param name="value">需要写入节点的值组成的byte数组列表</param>
        /// <returns></returns>
        public static ExtensionObject GetValueByteFromObj(WriteVar value)
        {
            List<byte> result = new List<byte>();
            //前4位为字符串数据长度
            var length = BitConverter.GetBytes(value.Name.Length);
            result.AddRange(length);
            //数据项名称
            var Name = Encoding.Default.GetBytes(value.Name);
            result.AddRange(Name);
            //数据类型
            var DataType = BitConverter.GetBytes(value.DataType);
            result.AddRange(DataType);
            //字符串数据转换
            if (value.StringValue.Length==0)
            {
                result.AddRange(new byte[4] { 0,0,0,0});
            }
            else
            {
                //前4位为字符串数据长度
                length = BitConverter.GetBytes(value.StringValue.Length);
                result.AddRange(length);
                //字符串数据
                var StringValue = Encoding.Default.GetBytes(value.StringValue);
                result.AddRange(StringValue);
            }
            //整数数据
            var IntValue = BitConverter.GetBytes(value.IntValue);
            result.AddRange(IntValue);
            //浮点数数据
            var FloatValue = BitConverter.GetBytes(value.FloatValue);
            result.AddRange(FloatValue);

            return new ExtensionObject {Body= result.ToArray() } ;
        }

3.把ExtensionObject[]写入即可

        其实拼接好ExtensionObject[]后按照通用写OPCUA的方法就可以了

        

        }
        /// <summary>
        /// OPCUATag写入
        /// </summary>
        /// <param name="value">需要写入节点的值组成的byte数组列表</param>
        /// <returns></returns>
        public void WriteVarStruct(ExtensionObject[] value,string nodeId)
        {
            WriteValueCollection nodesToWrite = new WriteValueCollection();
            nodesToWrite.Add(new WriteValue()
            {
                NodeId = new NodeId(nodeId),
                AttributeId = Attributes.Value,
                Value = new DataValue()
                {
                    Value = value
                }
            });
            WriteNode(nodesToWrite);
        }


        /// <summary>
        /// OPCUATag写入
        /// </summary>
        /// <param name="adress">需要写入节点的地址</param>
        /// <param name="value">需要写入节点的值</param>
        /// <returns></returns>
        public bool WriteNode(WriteValueCollection value)
        {
            try
            {
                //if (isCconnect)
                //{
                    StatusCodeCollection resultsValues = null;
                    DiagnosticInfoCollection diagnosticInfos = null;

                    //Console.WriteLine("数据读取开始");
                    // Call Read Service
                    var result = m_session.Write(
                          null,
                          value,
                          out resultsValues,
                          out diagnosticInfos);
                    //写入返回值为bad,则写入失败
                    if (StatusCode.IsBad(result.ServiceResult))
                    {
                        return false;
                    }
                    //验证结果
                    ClientBase.ValidateResponse(resultsValues, value);
                    return true;
                //}
                //return false;
            }
            catch (Exception ex)
            {
                throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);
            }
        }

写结构体的完整代码:

        private void button6_Click(object sender, EventArgs e)
        {
            ExtensionObject[] AA = new ExtensionObject[100];
            for (int i = 0; i < AA.Length; i++)
            {
                AA[i] = new ExtensionObject { Body = getNewByte() };
            }
            WriteVar structs = new WriteVar
            {
                index = 4,
                Name = "重量",
                DataType = 0,
                StringValue = "",
                IntValue = 25,
                FloatValue = 0.0F
            };
            var result = Pro_OPCUA.GetValueByteFromObj(structs);
            AA[4] = result;
            float a = 1.23F;
            WriteVar structs1 = new WriteVar
            {
                index = 5,
                Name = "形状",
                DataType = 1,
                StringValue = "",
                IntValue = 0,
                FloatValue = a
            };
            var result1 = Pro_OPCUA.GetValueByteFromObj(structs1);
            AA[5] = result1;


            WriteVar structs2 = new WriteVar
            {
                index = 6,
                Name = "C",
                DataType = 2,
                StringValue = "WUXE",
                IntValue = 0,
                FloatValue = 0.0F
            };
            var result2= Pro_OPCUA.GetValueByteFromObj(structs2);
            AA[6] = result2;
            //byte[] re = new byte[23] { 3,0,0,0,56,56,56,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0};

            string aaa= AA.ToString();

            pro_OPCUAp.WriteVarStruct(AA, "ns=2;s=writeStrucat");
        }

        /// <summary>
        /// OPCUATag写入
        /// </summary>
        /// <param name="value">需要写入节点的值组成的byte数组列表</param>
        /// <returns></returns>
        public void WriteVarStruct(ExtensionObject[] value,string nodeId)
        {
            WriteValueCollection nodesToWrite = new WriteValueCollection();
            nodesToWrite.Add(new WriteValue()
            {
                NodeId = new NodeId(nodeId),
                AttributeId = Attributes.Value,
                Value = new DataValue()
                {
                    Value = value
                }
            });
            WriteNode(nodesToWrite);
        }

        /// <summary>
        /// OPCUATag写入
        /// </summary>
        /// <param name="adress">需要写入节点的地址</param>
        /// <param name="value">需要写入节点的值</param>
        /// <returns></returns>
        public bool WriteNode(WriteValueCollection value)
        {
            try
            {
                //if (isCconnect)
                //{
                    StatusCodeCollection resultsValues = null;
                    DiagnosticInfoCollection diagnosticInfos = null;

                    //Console.WriteLine("数据读取开始");
                    // Call Read Service
                    var result = m_session.Write(
                          null,
                          value,
                          out resultsValues,
                          out diagnosticInfos);
                    //写入返回值为bad,则写入失败
                    if (StatusCode.IsBad(result.ServiceResult))
                    {
                        return false;
                    }
                    //验证结果
                    ClientBase.ValidateResponse(resultsValues, value);
                    return true;
                //}
                //return false;
            }
            catch (Exception ex)
            {
                throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);
            }
        }

项目地址:

OPCUA读写结构体示例-C#文档类资源-CSDN文库

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
OPCUA(即基于OPC传输协议的通用架构)提供了一种访问和交互结构体数据的方法。OPCUA使用统一的对象模型(UOM)来表示结构体类型,并通过节点和属性来进行读写操作。 读取结构体数据时,首先需要通过OPCUA客户端连接到OPCUA服务器,并通过服务器提供的方法获取结构体节点的引用。获取到节点引用后,可以使用ReadValue或者Browse方法来读取结构体的属性值。通常,结构体的属性会在OPCUA服务器端定义,并在OPCUA客户端中进行订阅或查询。 写入结构体数据时,需要先获取结构体节点的引用,然后通过WriteValue方法来写入属性的值。写入操作需要注意属性的数据类型和权限,确保写入的数据类型与属性定义匹配,并且具备足够的权限来进行写入操作。 读写结构体数据需要注意以下几点: 1. 首先要了解结构体的定义和属性信息,在OPCUA服务器端进行配置和定义。 2. 使用OPCUA客户端连接到OPCUA服务器,并获取结构体节点的引用。 3. 读取结构体数据时,可以使用ReadValue或Browse方法获取属性值。 4. 写入结构体数据时,使用WriteValue方法写入属性值,确保数据类型和权限匹配。 总结来说,OPCUA提供了一种便捷的方法来读取和写入结构体数据。使用OPCUA客户端连接到服务器,获取结构体节点的引用,然后可以通过读取和写入方法来操作结构体的属性值。通过遵循OPCUA的规范和标准,可以实现安全、可靠地读写结构体数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@榴莲酥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值