Skip to content

Commit af6a0da

Browse files
committed
2 parents 3491510 + 27600bb commit af6a0da

File tree

3 files changed

+279
-29
lines changed

3 files changed

+279
-29
lines changed

src/S7CommPlusDriver/ClientApi/Browser.cs

Lines changed: 275 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ public void BuildFlatList()
6060
// Skip empty lists in any area like marker or timers.
6161
if (node.Childs.Count > 0)
6262
{
63-
AddFlatSubnodes(node, String.Empty, String.Empty);
63+
uint OptOffset = 0;
64+
uint NonOptOffset = 0;
65+
AddFlatSubnodes(node, String.Empty, String.Empty, OptOffset, NonOptOffset);
6466
}
6567
}
6668
}
6769

68-
private void AddFlatSubnodes(Node node, string names, string accessIds)
70+
private void AddFlatSubnodes(Node node, string names, string accessIds, uint OptOffset, uint NonOptOffset)
6971
{
7072
switch (node.NodeType)
7173
{
@@ -97,16 +99,85 @@ private void AddFlatSubnodes(Node node, string names, string accessIds)
9799
{
98100
Name = names,
99101
AccessSequence = accessIds,
100-
Softdatatype = node.Softdatatype
102+
Softdatatype = node.Softdatatype,
101103
};
104+
// If an Array element of basic datatype, the Vte is here from the parent array base element and offsets not valid here.
105+
if (node.NodeType == eNodeType.Array)
106+
{
107+
info.OptAddress = OptOffset;
108+
info.NonOptAddress = NonOptOffset;
109+
}
110+
else
111+
{
112+
info.OptAddress = OptOffset + node.Vte.OffsetInfoType.OptimizedAddress;
113+
info.NonOptAddress = NonOptOffset + node.Vte.OffsetInfoType.NonoptimizedAddress;
114+
}
115+
// Special case #1:
116+
// There is a strange behaviour when transmitting bitoffsets in not-optmized DBs.
117+
// If a bool is inside a struct, the offsetinformation is in the attributes (last 3 bits.
118+
// Bitoffsetinfo bit classic is false in this case.
119+
// Don't know if this a bug in Plcsim (where I tested with) or intentional.
120+
//
121+
// Special case #2:
122+
// System datatypes like IEC_COUNTER, etc. have Bools with Bitoffsets, even when they are locates in optimized DBs.
123+
// The bitoffset is then located in the Attributes and not in the bitoffset
124+
if (node.Softdatatype == Softdatatype.S7COMMP_SOFTDATATYPE_BOOL)
125+
{
126+
info.OptBitoffset = node.Vte.GetAttributeBitoffset();
127+
if (node.Vte.GetBitoffsetinfoFlagClassic())
128+
{
129+
info.NonOptBitoffset = node.Vte.GetBitoffsetinfoNonoptimizedBitoffset();
130+
}
131+
else
132+
{
133+
info.NonOptBitoffset = node.Vte.GetAttributeBitoffset();
134+
}
135+
}
136+
else if (node.Softdatatype == Softdatatype.S7COMMP_SOFTDATATYPE_BBOOL)
137+
{
138+
info.OptBitoffset = node.Vte.GetBitoffsetinfoOptimizedBitoffset();
139+
}
140+
else
141+
{
142+
info.OptBitoffset = 0;
143+
info.NonOptBitoffset = 0;
144+
}
145+
102146
m_varInfoList.Add(info);
103147
}
104148
}
105149
else
106150
{
151+
// root node (the DB itself) has no VarTypeListElement, but we don't need it here.
152+
if (node.Vte != null)
153+
{
154+
switch (node.NodeType)
155+
{
156+
case eNodeType.Array:
157+
// This is an array element of basic datatype. Offset comes from fixed size multiplied by array index.
158+
OptOffset = node.Vte.OffsetInfoType.OptimizedAddress;
159+
NonOptOffset = node.Vte.OffsetInfoType.NonoptimizedAddress;
160+
break;
161+
case eNodeType.StructArray:
162+
OptOffset += node.ArrayAdrOffsetOpt;
163+
NonOptOffset += node.ArrayAdrOffsetNonOpt;
164+
break;
165+
default:
166+
OptOffset += node.Vte.OffsetInfoType.OptimizedAddress;
167+
NonOptOffset += node.Vte.OffsetInfoType.NonoptimizedAddress;
168+
break;
169+
}
170+
}
107171
foreach (var sub in node.Childs)
108172
{
109-
AddFlatSubnodes(sub, names, accessIds);
173+
if (sub.NodeType == eNodeType.Array)
174+
{
175+
AddFlatSubnodes(sub, names, accessIds, OptOffset + sub.ArrayAdrOffsetOpt, NonOptOffset + sub.ArrayAdrOffsetNonOpt);
176+
}
177+
else
178+
{
179+
AddFlatSubnodes(sub, names, accessIds, OptOffset, NonOptOffset);
180+
}
110181
}
111182
}
112183
}
@@ -135,6 +206,8 @@ private void AddSubNodes(ref Node node, PObject o)
135206
int[] MdimArrayLowerBounds;
136207

137208
int element_index = 0;
209+
uint TComSize;
210+
138211
// If there are no variables at all in an area, then this list does not exist (no error).
139212
if (o.VartypeList != null)
140213
{
@@ -144,8 +217,10 @@ private void AddSubNodes(ref Node node, PObject o)
144217
{
145218
Name = o.VarnameList.Names[element_index],
146219
Softdatatype = vte.Softdatatype,
147-
AccessId = vte.LID
220+
AccessId = vte.LID,
221+
Vte = vte,
148222
};
223+
149224
node.Childs.Add(subnode);
150225
// Process arrays. TODO: Put the processing to separate methods, to shorten this method.
151226
if (vte.OffsetInfoType.Is1Dim())
@@ -166,7 +241,8 @@ private void AddSubNodes(ref Node node, PObject o)
166241
NodeType = eNodeType.StructArray,
167242
Name = "[" + (i + ArrayLowerBounds) + "]",
168243
Softdatatype = vte.Softdatatype,
169-
AccessId = i
244+
AccessId = i,
245+
Vte = vte,
170246
};
171247
subnode.Childs.Add(arraynode);
172248

@@ -177,6 +253,11 @@ private void AddSubNodes(ref Node node, PObject o)
177253
{
178254
if (ob.RelationId == ioit2.GetRelationId())
179255
{
256+
// Get the size of a struct element
257+
TComSize = ((ValueUDInt)ob.GetAttribute(Ids.TI_TComSize)).GetValue();
258+
arraynode.ArrayAdrOffsetOpt = i * TComSize;
259+
arraynode.ArrayAdrOffsetNonOpt = i * TComSize;
260+
180261
AddSubNodes(ref arraynode, ob);
181262
break;
182263
}
@@ -189,8 +270,14 @@ private void AddSubNodes(ref Node node, PObject o)
189270
NodeType = eNodeType.Array,
190271
Name = "[" + (i + ArrayLowerBounds) + "]",
191272
Softdatatype = vte.Softdatatype,
192-
AccessId = i
273+
AccessId = i,
274+
Vte = vte,
193275
};
276+
// Get the size of the basic datatype
277+
TComSize = GetSizeOfDatatype(vte);
278+
arraynode.ArrayAdrOffsetOpt = i * TComSize;
279+
arraynode.ArrayAdrOffsetNonOpt = i * TComSize;
280+
194281
subnode.Childs.Add(arraynode);
195282
}
196283
}
@@ -216,7 +303,7 @@ private void AddSubNodes(ref Node node, PObject o)
216303
}
217304

218305
string aname = "";
219-
int n = 1;
306+
uint n = 1;
220307
uint id = 0;
221308
uint[] xx = new uint[6] { 0, 0, 0, 0, 0, 0 };
222309
do
@@ -242,7 +329,8 @@ private void AddSubNodes(ref Node node, PObject o)
242329
NodeType = eNodeType.StructArray,
243330
Name = aname,
244331
Softdatatype = vte.Softdatatype,
245-
AccessId = id
332+
AccessId = id,
333+
Vte = vte,
246334
};
247335
subnode.Childs.Add(arraynode);
248336

@@ -253,6 +341,11 @@ private void AddSubNodes(ref Node node, PObject o)
253341
{
254342
if (ob.RelationId == ioit2.GetRelationId())
255343
{
344+
// Get the size of a struct element
345+
TComSize = ((ValueUDInt)ob.GetAttribute(Ids.TI_TComSize)).GetValue();
346+
arraynode.ArrayAdrOffsetOpt = (n - 1) * TComSize;
347+
arraynode.ArrayAdrOffsetNonOpt = (n - 1) * TComSize;
348+
256349
AddSubNodes(ref arraynode, ob);
257350
break;
258351
}
@@ -265,8 +358,13 @@ private void AddSubNodes(ref Node node, PObject o)
265358
NodeType = eNodeType.Array,
266359
Name = aname,
267360
Softdatatype = vte.Softdatatype,
268-
AccessId = id
361+
AccessId = id,
362+
Vte = vte,
269363
};
364+
TComSize = GetSizeOfDatatype(vte);
365+
arraynode.ArrayAdrOffsetOpt = (n - 1) * TComSize;
366+
arraynode.ArrayAdrOffsetNonOpt = (n - 1) * TComSize;
367+
270368
subnode.Childs.Add(arraynode);
271369
}
272370
xx[0]++;
@@ -312,6 +410,165 @@ private void AddSubNodes(ref Node node, PObject o)
312410
}
313411
}
314412

413+
private uint GetSizeOfDatatype(PVartypeListElement vte)
414+
{
415+
// Returns the size of an element if stored as an array
416+
switch (vte.Softdatatype)
417+
{
418+
case Softdatatype.S7COMMP_SOFTDATATYPE_BOOL:
419+
// TODO: Bit Bool?
420+
return 1;
421+
case Softdatatype.S7COMMP_SOFTDATATYPE_BYTE:
422+
return 1;
423+
case Softdatatype.S7COMMP_SOFTDATATYPE_CHAR:
424+
return 1;
425+
case Softdatatype.S7COMMP_SOFTDATATYPE_WORD:
426+
return 2;
427+
case Softdatatype.S7COMMP_SOFTDATATYPE_INT:
428+
return 2;
429+
case Softdatatype.S7COMMP_SOFTDATATYPE_DWORD:
430+
return 4;
431+
case Softdatatype.S7COMMP_SOFTDATATYPE_DINT:
432+
return 4;
433+
case Softdatatype.S7COMMP_SOFTDATATYPE_REAL:
434+
return 4;
435+
case Softdatatype.S7COMMP_SOFTDATATYPE_DATE:
436+
return 2;
437+
case Softdatatype.S7COMMP_SOFTDATATYPE_TIMEOFDAY:
438+
return 4;
439+
case Softdatatype.S7COMMP_SOFTDATATYPE_TIME:
440+
return 4;
441+
case Softdatatype.S7COMMP_SOFTDATATYPE_S5TIME:
442+
return 2;
443+
case Softdatatype.S7COMMP_SOFTDATATYPE_DATEANDTIME:
444+
return 8;
445+
case Softdatatype.S7COMMP_SOFTDATATYPE_STRING:
446+
case Softdatatype.S7COMMP_SOFTDATATYPE_WSTRING:
447+
// TODO:
448+
// If an array of String or WString, offsetinfo1 is the string length.
449+
// First though was, that offsetinfo2 is length including header of 2 bytes.
450+
// but with an Multidim Array [0..2, 0..1] of String[5] offsetinfo is 8, which is not
451+
// correct when you look at the data.
452+
// Tested only with Plcsim, which may be a bug in Plcsim?
453+
if (vte.OffsetInfoType.Is1Dim())
454+
{
455+
return ((POffsetInfoType_Array1Dim)(vte.OffsetInfoType)).UnspecifiedOffsetinfo1 + (uint)2;
456+
}
457+
else
458+
{
459+
return ((POffsetInfoType_ArrayMDim)(vte.OffsetInfoType)).UnspecifiedOffsetinfo1 + (uint)2;
460+
}
461+
case Softdatatype.S7COMMP_SOFTDATATYPE_POINTER:
462+
return 6;
463+
case Softdatatype.S7COMMP_SOFTDATATYPE_ANY:
464+
return 10;
465+
case Softdatatype.S7COMMP_SOFTDATATYPE_BLOCKFB:
466+
return 2;
467+
case Softdatatype.S7COMMP_SOFTDATATYPE_BLOCKFC:
468+
return 2;
469+
case Softdatatype.S7COMMP_SOFTDATATYPE_COUNTER:
470+
return 2;
471+
case Softdatatype.S7COMMP_SOFTDATATYPE_TIMER:
472+
return 2;
473+
case Softdatatype.S7COMMP_SOFTDATATYPE_BBOOL:
474+
return 1; // Bool of size 1 byte here
475+
case Softdatatype.S7COMMP_SOFTDATATYPE_LREAL:
476+
return 8;
477+
case Softdatatype.S7COMMP_SOFTDATATYPE_ULINT:
478+
return 8;
479+
case Softdatatype.S7COMMP_SOFTDATATYPE_LINT:
480+
return 8;
481+
case Softdatatype.S7COMMP_SOFTDATATYPE_LWORD:
482+
return 8;
483+
case Softdatatype.S7COMMP_SOFTDATATYPE_USINT:
484+
return 1;
485+
case Softdatatype.S7COMMP_SOFTDATATYPE_UINT:
486+
return 2;
487+
case Softdatatype.S7COMMP_SOFTDATATYPE_UDINT:
488+
return 4;
489+
case Softdatatype.S7COMMP_SOFTDATATYPE_SINT:
490+
return 1;
491+
case Softdatatype.S7COMMP_SOFTDATATYPE_WCHAR:
492+
return 2;
493+
case Softdatatype.S7COMMP_SOFTDATATYPE_LTIME:
494+
return 8;
495+
case Softdatatype.S7COMMP_SOFTDATATYPE_LTOD:
496+
return 8;
497+
case Softdatatype.S7COMMP_SOFTDATATYPE_LDT:
498+
return 8;
499+
case Softdatatype.S7COMMP_SOFTDATATYPE_DTL:
500+
return 12; // In most cases as a struct of system type
501+
case Softdatatype.S7COMMP_SOFTDATATYPE_REMOTE:
502+
return 10;
503+
case Softdatatype.S7COMMP_SOFTDATATYPE_AOMIDENT:
504+
return 4;
505+
case Softdatatype.S7COMMP_SOFTDATATYPE_EVENTANY:
506+
return 4;
507+
case Softdatatype.S7COMMP_SOFTDATATYPE_EVENTATT:
508+
return 4;
509+
case Softdatatype.S7COMMP_SOFTDATATYPE_AOMAID:
510+
// TODO: Not possible to define this type
511+
return 0;
512+
case Softdatatype.S7COMMP_SOFTDATATYPE_AOMLINK:
513+
// TODO: Not possible to define this type
514+
return 0;
515+
case Softdatatype.S7COMMP_SOFTDATATYPE_EVENTHWINT:
516+
return 4;
517+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWANY:
518+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWIOSYSTEM:
519+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWDPMASTER:
520+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWDEVICE:
521+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWDPSLAVE:
522+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWIO:
523+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWMODULE:
524+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWSUBMODULE:
525+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWHSC:
526+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWPWM:
527+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWPTO:
528+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWINTERFACE:
529+
case Softdatatype.S7COMMP_SOFTDATATYPE_HWIEPORT:
530+
return 2;
531+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBANY:
532+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBDELAY:
533+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBTOD:
534+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBCYCLIC:
535+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBATT:
536+
return 2;
537+
case Softdatatype.S7COMMP_SOFTDATATYPE_CONNANY:
538+
return 2;
539+
case Softdatatype.S7COMMP_SOFTDATATYPE_CONNPRG:
540+
return 2;
541+
case Softdatatype.S7COMMP_SOFTDATATYPE_CONNOUC:
542+
return 2;
543+
case Softdatatype.S7COMMP_SOFTDATATYPE_CONNRID:
544+
return 4;
545+
case Softdatatype.S7COMMP_SOFTDATATYPE_PORT:
546+
return 2;
547+
case Softdatatype.S7COMMP_SOFTDATATYPE_RTM:
548+
return 2;
549+
case Softdatatype.S7COMMP_SOFTDATATYPE_PIP:
550+
return 2;
551+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBPCYCLE:
552+
return 2;
553+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBHWINT:
554+
return 2;
555+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBDIAG:
556+
return 2;
557+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBTIMEERROR:
558+
return 2;
559+
case Softdatatype.S7COMMP_SOFTDATATYPE_OBSTARTUP:
560+
return 2;
561+
case Softdatatype.S7COMMP_SOFTDATATYPE_DBANY:
562+
return 2;
563+
case Softdatatype.S7COMMP_SOFTDATATYPE_DBWWW:
564+
return 2;
565+
case Softdatatype.S7COMMP_SOFTDATATYPE_DBDYN:
566+
return 2;
567+
default:
568+
return 0;
569+
}
570+
}
571+
315572
private bool IsSoftdatatypeSupported(uint softdatatype)
316573
{
317574
switch (softdatatype)
@@ -404,6 +661,10 @@ protected class Node
404661
public UInt32 AccessId;
405662
public UInt32 Softdatatype;
406663
public UInt32 RelationId;
664+
public PVartypeListElement Vte;
665+
public UInt32 ArrayAdrOffsetOpt; // Offset of an Element when it's an array, optimized
666+
public UInt32 ArrayAdrOffsetNonOpt; // Offset of an Element when it's an array, not-optimized
667+
407668
public List<Node> Childs = new List<Node>();
408669

409670
public Node()
@@ -423,6 +684,10 @@ public class VarInfo
423684
public string Name;
424685
public string AccessSequence;
425686
public UInt32 Softdatatype;
687+
public UInt32 OptAddress; // Optimized access: Byte-Offset where the value is located when reading a complete DB content.
688+
public int OptBitoffset; // Optimized access: Bit-Offset where the value is located when reading a complete DB content.
689+
public UInt32 NonOptAddress; // NonOptimized access: Byte-Offset where the value is located when reading a complete DB content.
690+
public int NonOptBitoffset; // NonOptimized access: Bit-Offset where the value is located when reading a complete DB content.
426691
}
427692

428693
public enum eNodeType

0 commit comments

Comments
 (0)