I ended up generating specific structs for each type of variable I would need, because to generate the HDF5 file it was necessary to allocate a specific space for each type, so I chose to make a generic class (a helper) and then instantiate the flow I needed based on the kind of data I read:
public class OpcToHdfHelper
{
public dynamic opcToRun;
public void SetTypeAndWriteHdf(string bvtag, IOpcUaSession uaSession, Opc.Ua.ReadRawModifiedDetails readDetails,
Opc.Ua.NodeId sourceId, H5GroupId group)
{
var data = HistoryReadEnu(uaSession, readDetails, sourceId);
int i = 0;
var p = data.ToArray()[i].Value;
i = 1;
while (p == null && i < 10)
{
p = data.ToArray()[i].Value;
i++;
} ;
if (p.GetType() == typeof(int))
{
opcToRun = new OpcInt32(data, bvtag, group);
}
if (p.GetType() == typeof(Int64))
{
opcToRun = new OpcInt64();
}
if (p.GetType() == typeof(float))
{
opcToRun = new OpcFloat();
}
if (p.GetType() == typeof(double))
{
opcToRun = new OpcDouble(data, bvtag, group);
}
if(p.GetType() == typeof(string))
{
opcToRun = new OpcString(data, bvtag, group);
}
if(p.GetType() == typeof(bool))
{
opcToRun = new OpcBoolean(data, bvtag, group);
}
}
Edit to clarify why different structs were needed:
struct OpcString
{
public Int64 dt;
public Int64 qlt;
public IntPtr vl;
public OpcString(Int64 timestamp = 0, Int64 quality = 0, string value="0")
{
dt = timestamp;
qlt = quality;
vl = new IntPtr();
vl = ConvertTo(value);
}
IntPtr ConvertTo(string s)
{
var x = Marshal.StringToHGlobalAnsi(s);
return x;
}
public OpcString(IEnumerable<Opc.Ua.DataValue> dados, string bvTag, H5GroupId groupId)
{
dt = 0;
qlt = 0;
vl = new IntPtr();
GenerateHdf5(dados, bvTag, groupId);
}
public void GenerateHdf5(IEnumerable<Opc.Ua.DataValue> dados, string bvTag, H5GroupId groupId)
{
long[] dims = new long[1];
dims[0] = dados.Count<Opc.Ua.DataValue>();
H5DataSpaceId dataSpaceId = H5S.create_simple(1, dims);
string auxLen = "";
foreach(Opc.Ua.DataValue vc in dados)
{
if (vc.Value != null) {
if(vc.Value.ToString().Length > auxLen.Length)
{
auxLen = vc.Value.ToString();
}
}
}
H5DataTypeId stringTypeId = H5T.create(H5T.CreateClass.STRING, -1);
OpcString opcHelper = new OpcString();
H5DataTypeId dataTypeId = H5T.create(H5T.CreateClass.COMPOUND, Marshal.SizeOf(opcHelper));
H5T.insert(dataTypeId, "Timestamp", 0, new H5DataTypeId(H5T.H5Type.NATIVE_LONG));
H5T.insert(dataTypeId, "Quality", 8, new H5DataTypeId(H5T.H5Type.NATIVE_LONG));
H5T.insert(dataTypeId, "Value", 16, stringTypeId);
var list = new List<OpcString>();
foreach (Opc.Ua.DataValue dv in dados)
{
string t = "NullValue";
if(dv.Value != null)
{
t = dv.Value.ToString();
}
OpcString aux = new OpcString((Int64)dv.SourceTimestamp.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds, dv.StatusCode.Code, t);
list.Add(aux);
}
H5DataSetId bvDset = H5D.create(groupId, bvTag, dataTypeId, dataSpaceId);
H5D.write(bvDset, dataTypeId, new H5Array<OpcString>(list.ToArray()));
H5D.close(bvDset);
H5S.close(dataSpaceId);
}
}
struct OpcBoolean
{
public Int64 dt;
public Int64 qlt;
public bool vl;
public OpcBoolean(Int64 timestamp = 0, Int64 quality = 0, bool value = false)
{
dt = timestamp;
qlt = quality;
vl = value;
}
public OpcBoolean(IEnumerable<Opc.Ua.DataValue> dados, string bvTag, H5GroupId groupId)
{
dt = 0;
qlt = 0;
vl = false;
GenerateHdf5(dados, bvTag, groupId);
}
public void GenerateHdf5(IEnumerable<Opc.Ua.DataValue> dados, string bvTag, H5GroupId groupId)
{
long[] dims = new long[1];
dims[0] = dados.Count<Opc.Ua.DataValue>();
H5DataSpaceId dataSpaceId = H5S.create_simple(1, dims);
OpcBoolean opcHelper = new OpcBoolean();
H5DataTypeId dataTypeId = H5T.create(H5T.CreateClass.COMPOUND, Marshal.SizeOf(opcHelper));
H5T.insert(dataTypeId, "Timestamp", 0, new H5DataTypeId(H5T.H5Type.NATIVE_LONG));
H5T.insert(dataTypeId, "Quality", 8, new H5DataTypeId(H5T.H5Type.NATIVE_LONG));
H5T.insert(dataTypeId, "Value", 16, new H5DataTypeId(H5T.H5Type.NATIVE_HBOOL));
var list = new List<OpcBoolean>();
foreach (Opc.Ua.DataValue dv in dados)
{
OpcBoolean aux = new OpcBoolean((Int64)dv.SourceTimestamp.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds, dv.StatusCode.Code, Convert.ToBoolean(dv.Value));
list.Add(aux);
}
H5DataSetId bvDset = H5D.create(groupId, bvTag, dataTypeId, dataSpaceId);
H5D.write(bvDset, dataTypeId, new H5Array<OpcBoolean>(list.ToArray()));
H5D.close(bvDset);
H5S.close(dataSpaceId);
}
}
I’m not sure what the problem is. I even think I understand what you want to do and I have doubts if you should do so, including because the code is unreadable by C#. What is this
Opc.Ua.DataValue
, how is it composed? Anyway it is almost certain that even need it, almost should never usedynamic
and it’s rare enough to needobject
.– Maniero
i need to instantiate my "opcSt" struct, which is described up there, this datavalue returns a double, in the case that wanted to instantiate my "opcSt" struct by passing a double instead of "Vl", the type of the same would change from "Dynamic" to "double" however, C# converts this to a very strange type that is "Dynamic {double}" and not just "double" and so is my method that writes these records to a file (which only recognizes the primitive types of data) when receiving an "Object{double}" locks and plays an Exception saying it does not recognize this kind of data
– Arthuro Verissimo
An example of a way that I will try to circumvent now, creating a struct for the most used types that I will have and after taking the datavalue I instate an array of objects of that struct
– Arthuro Verissimo
You kind of repeated what was already written, it still doesn’t make sense to me, but it might not. Or it’s just not clear what the real problem is. This is probably just wrong architecture.
– Maniero