OPCUA结构体的读写说白了就是对ExtensionObject中按规则对byte的转换
读取步骤:
1.首先可以先用UAExpert查看结构体
2.读取出结构体DataValue的值
3.把读取出来的值转换成ExtensionObject[]
4.把ExtensionObject中每项进行解析。
具体步骤解析:
如图1我们能看到有一个结构体的数据类型ExtensionObject。这个结构体的有5项,且每个字段都是什么。(这里主要验证我们后期自己读取的数据对不对)
图1
这里我们通过session中的ReadValue()方法读取出结构体DataValue的值,这里和正常的已知nodeID读值方法一样(怎么建立连接,大家可以搜随便搜一下就能找到,或者也可以看我前面OPCUA的文章)。
DataValue item= m_session.ReadValue(new NodeId(ItemAdress));
读取后我们可以看到value的值,如图2,它是一个ExtensionObject类型长为100的数据。而且每项都是byte[],我们要做的就是如何把byte按照规则转换成字符
首先我们先得到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;
- }
- ///
- /// 读取结构体数据
- ///
- 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[]
同读取,省略
首先定义一个结构体类,同UAExpert查看结构体,注意结构体顺序也不能乱
- ///
- /// writevar对象
- ///
- public class WriteVar
- {
- ///
- /// 数组索引
- ///
- public int index = 0;
- ///
- /// 数据项名称
- ///
- public string Name = "";
- ///
- /// 数据类型
- ///
- public int DataType = 0;
- ///
- /// 字符串值
- ///
- public string StringValue = "";
- ///
- /// 整数值
- ///
- public int IntValue = 0;
- ///
- /// 浮点数值
- ///
- 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);
-
- ///
- /// 从对象中获取对象所有的值,并转化为byte[]
- ///
- /// 需要写入节点的值组成的byte数组列表
- ///
- 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() } ;
- }
其实拼接好ExtensionObject[]后按照通用写OPCUA的方法就可以了
- }
- ///
- /// OPCUATag写入
- ///
- /// 需要写入节点的值组成的byte数组列表
- ///
- 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);
- }
-
-
- ///
- /// OPCUATag写入
- ///
- /// 需要写入节点的地址
- /// 需要写入节点的值
- ///
- 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");
- }
-
- ///
- /// OPCUATag写入
- ///
- /// 需要写入节点的值组成的byte数组列表
- ///
- 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);
- }
-
- ///
- /// OPCUATag写入
- ///
- /// 需要写入节点的地址
- /// 需要写入节点的值
- ///
- 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);
- }
- }
项目地址: