Skip to content

Commit 2edbc13

Browse files
authored
Merge pull request #208 from ryan2445/master
Step7v5: add option to use MC7 interface when there are timestamp conflicts
2 parents 1e5db9a + 303cc92 commit 2edbc13

File tree

5 files changed

+130
-23
lines changed

5 files changed

+130
-23
lines changed

LibNoDaveConnectionLibrary/DataTypes/AWL/Step7V5/S7ConvertingOptions.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ protected bool Equals(S7ConvertingOptions other)
1717
&& this.ReplaceDIAccessesWithSymbolNames.Equals(other.ReplaceDIAccessesWithSymbolNames)
1818
&& this.GenerateCallsfromUCs.Equals(other.GenerateCallsfromUCs)
1919
&& this.UseInFCStoredFCsForCalls.Equals(other.UseInFCStoredFCsForCalls)
20-
&& this.UseFBDeclarationForInstanceDB.Equals(other.UseFBDeclarationForInstanceDB);
20+
&& this.UseFBDeclarationForInstanceDB.Equals(other.UseFBDeclarationForInstanceDB)
21+
&& this.UseDBActualValues.Equals(other.UseDBActualValues)
22+
&& this.ExpandArrays.Equals(other.ExpandArrays)
23+
&& this.CheckForInterfaceTimestampConflicts.Equals(other.CheckForInterfaceTimestampConflicts);
2124
}
2225

2326
public override int GetHashCode()
@@ -33,6 +36,9 @@ public override int GetHashCode()
3336
hashCode = (hashCode * 397) ^ this.GenerateCallsfromUCs.GetHashCode();
3437
hashCode = (hashCode * 397) ^ this.UseInFCStoredFCsForCalls.GetHashCode();
3538
hashCode = (hashCode * 397) ^ this.UseFBDeclarationForInstanceDB.GetHashCode();
39+
hashCode = (hashCode * 397) ^ this.UseDBActualValues.GetHashCode();
40+
hashCode = (hashCode * 397) ^ this.ExpandArrays.GetHashCode();
41+
hashCode = (hashCode * 397) ^ this.CheckForInterfaceTimestampConflicts.GetHashCode();
3642
return hashCode;
3743
}
3844
}
@@ -55,6 +61,7 @@ public S7ConvertingOptions(MnemonicLanguage Mnemonic)
5561
this.UseFBDeclarationForInstanceDB = true; //Default to Simatic Mamager Behavior
5662
this.UseDBActualValues = false;
5763
this.ExpandArrays = false;
64+
this.CheckForInterfaceTimestampConflicts = false;
5865
}
5966

6067
public bool UseComments { get; set; }
@@ -71,6 +78,8 @@ public S7ConvertingOptions(MnemonicLanguage Mnemonic)
7178
public bool GenerateCallsfromUCs { get; set;}
7279
public bool UseInFCStoredFCsForCalls { get; set; }
7380

81+
public bool CheckForInterfaceTimestampConflicts { get; set; }
82+
7483
/// <summary>
7584
/// use the FB instance declartion symbolics for displaying Instance DB Variables
7685
/// Otherwise it is using the Symbolics stored for each individual instance DB, which may be different than the Function Block

LibNoDaveConnectionLibrary/DataTypes/Blocks/Step7V5/S7Block.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,31 @@ public class S7Block : Block
9292
/// </summary>
9393
public DateTime LastInterfaceChange { get; set; }
9494

95+
/// <summary>
96+
/// Timestamp of the last interface change associated with the plaintext database record
97+
/// If a block is uploaded to the project with a timestamp conflict, this field contains the previous modified date of the interface before the upload
98+
/// </summary>
99+
public DateTime LastInterfaceChangeHistory { get; set; }
100+
101+
/// <summary>
102+
/// Returns true if the plaintext interface timestamp is different from the MC7 interface timestamp
103+
/// The default value of DateTime is DateTime.MinValue, so also check to make sure that both values are set
104+
/// </summary>
105+
public bool HasInterfaceTimestampConflict
106+
{
107+
get
108+
{
109+
if (!LastInterfaceChangeHistory.Equals(DateTime.MinValue) &&
110+
!LastInterfaceChange.Equals(DateTime.MinValue) &&
111+
!LastInterfaceChangeHistory.Equals(LastInterfaceChange))
112+
{
113+
return true;
114+
}
115+
116+
return false;
117+
}
118+
}
119+
95120
/// <summary>
96121
/// The total size of the Interface table
97122
/// </summary>

LibNoDaveConnectionLibrary/DataTypes/Blocks/Step7V5/S7DataBlock.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ public IDataRow Structure
5353
{
5454
get
5555
{
56-
if (StructureFromString != null)
56+
bool checkIFaceConflict = usedS7ConvertingOptions != null && usedS7ConvertingOptions.CheckForInterfaceTimestampConflicts;
57+
58+
if ((!checkIFaceConflict && StructureFromString != null) || (checkIFaceConflict && !HasInterfaceTimestampConflict))
59+
{
5760
return StructureFromString;
61+
}
62+
5863
return StructureFromMC7;
5964
}
6065
set

LibNoDaveConnectionLibrary/DataTypes/Projectfolders/Step7V5/BlocksOfflineFolder.cs

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Data;
44
using System.Text;
@@ -154,6 +154,7 @@ public class TmpBlock
154154
public string version;
155155
public DateTime LastCodeChange;
156156
public DateTime LastInterfaceChange;
157+
public DateTime LastInterfaceChangeHistory;
157158
public bool IsInstanceDB;
158159
public bool IsSFB;
159160
public int FBNumber;
@@ -323,6 +324,8 @@ public TmpBlock GetBlockBytes(ProjectBlockInfo blkInfo)
323324
myTmpBlk.nwinfo = addinfo;
324325
//This line contains Network Information, and after it the Position of the JumpMarks
325326

327+
// ssbpart contains the MC7 interface from the PLC
328+
myTmpBlk.blkinterfaceInMC5 = ssbpart;
326329
myTmpBlk.LastCodeChange = GetTimeStamp((string)row["TIMESTAMP1"]);
327330
myTmpBlk.LastInterfaceChange = GetTimeStamp((string)row["TIMESTAMP2"]);
328331

@@ -335,10 +338,12 @@ public TmpBlock GetBlockBytes(ProjectBlockInfo blkInfo)
335338
}
336339
else if (subblktype == 5 || subblktype == 3 || subblktype == 4 || subblktype == 7 || subblktype == 9) //FC, OB, FB, SFC, SFB
337340
{
338-
//Interface in mc5code
341+
// Interface in plaintext
339342
if (mc5code != null)
340-
myTmpBlk.blkinterface =
341-
Project.ProjectEncoding.GetString(mc5code);
343+
{
344+
myTmpBlk.blkinterface = Project.ProjectEncoding.GetString(mc5code);
345+
myTmpBlk.LastInterfaceChangeHistory = GetTimeStamp((string)row["TIMESTAMP2"]);
346+
}
342347
}
343348
else if (subblktype == 19 || subblktype == 17 || subblktype == 18 || subblktype == 22 ||
344349
subblktype == 21) //FC, OB, FB, SFC, SFB
@@ -348,23 +353,30 @@ public TmpBlock GetBlockBytes(ProjectBlockInfo blkInfo)
348353
myTmpBlk.jumpmarks = addinfo;
349354
//The Text of the Jump Marks, Before the Jumpmarks there is some Network Information, but don't know what!
350355
}
351-
352356
else if (subblktype == 6 || subblktype == 1) //DB, UDT
353357
{
354358
//DB Structure in Plain Text (Structure and StartValues!)
355359
if (mc5code != null)
356-
myTmpBlk.blkinterface =
357-
Project.ProjectEncoding.GetString(mc5code);
360+
{
361+
myTmpBlk.blkinterface = Project.ProjectEncoding.GetString(mc5code);
362+
myTmpBlk.LastInterfaceChangeHistory = GetTimeStamp((string)row["TIMESTAMP2"]);
363+
}
364+
365+
// DB blocks get their timestamps from the MC7 interface record (when subblktype == 10). UDT blocks can't be downloaded and don't have this same record.
366+
if (blkInfo.BlockType == PLCBlockType.UDT)
367+
{
368+
myTmpBlk.LastCodeChange = GetTimeStamp((string)row["TIMESTAMP1"]);
369+
myTmpBlk.LastInterfaceChange = GetTimeStamp((string)row["TIMESTAMP2"]);
370+
}
371+
358372
//Maybe compiled DB Structure?
359373
myTmpBlk.addinfo = addinfo;
360-
361-
myTmpBlk.LastCodeChange = GetTimeStamp((string)row["TIMESTAMP1"]);
362-
myTmpBlk.LastInterfaceChange = GetTimeStamp((string)row["TIMESTAMP2"]);
363374
}
364375
else if (subblktype == 10) //DB
365376
{
366-
//Need to check wich Information is stored here
377+
// mc7code contains the actual values of the DB from the PLC
367378
myTmpBlk.mc7code = mc5code;
379+
// ssbpart contains the MC7 interface from the PLC
368380
myTmpBlk.blkinterfaceInMC5 = ssbpart;
369381
myTmpBlk.LastCodeChange = GetTimeStamp((string)row["TIMESTAMP1"]);
370382
myTmpBlk.LastInterfaceChange = GetTimeStamp((string)row["TIMESTAMP2"]);
@@ -552,6 +564,9 @@ public Block GetBlock(ProjectBlockInfo blkInfo, S7ConvertingOptions myConvOpt)
552564
List<string> tmpPar = new List<string>();
553565
if (InstFB != null)
554566
{
567+
// Set the InstanceDB's history time to the most recent change of the FB
568+
myTmpBlk.LastInterfaceChangeHistory = InstFB.LastInterfaceChange;
569+
555570
S7DataRow InterfaceFB =
556571
Parameter.GetInterfaceOrDBFromStep7ProjectString(InstFB.blkinterface, ref tmpPar,
557572
PLCBlockType.FB, false, this, null, myConvOpt);
@@ -568,21 +583,19 @@ public Block GetBlock(ProjectBlockInfo blkInfo, S7ConvertingOptions myConvOpt)
568583
if (myTmpBlk.mc7code != null)
569584
retVal.CodeSize = myTmpBlk.mc7code.Length;
570585

586+
retVal.LastCodeChange = myTmpBlk.LastCodeChange;
587+
retVal.LastInterfaceChange = myTmpBlk.LastInterfaceChange;
588+
retVal.LastInterfaceChangeHistory = myTmpBlk.LastInterfaceChangeHistory;
589+
590+
retVal.StructureFromMC7 = GetInterfaceStructureFromMC7(blkInfo, myTmpBlk, retVal, ref tmpList);
571591
retVal.StructureFromString = Parameter.GetInterfaceOrDBFromStep7ProjectString(myTmpBlk.blkinterface, ref tmpList, blkInfo.BlockType, false, this, retVal, myConvOpt, myTmpBlk.mc7code);
572-
if (myTmpBlk.blkinterfaceInMC5 != null)
573-
{
574-
//List<string> tmp = new List<string>();
575-
//retVal.StructureFromMC7 = Parameter.GetInterface(myTmpBlk.blkinterfaceInMC5, myTmpBlk.mc7code, ref tmp, blkInfo.BlockType, myTmpBlk.IsInstanceDB, retVal);
576-
}
592+
577593
retVal.BlockNumber = plcblkifo.BlockNumber;
578594
retVal.Name = plcblkifo.Name;
579595
retVal.Family = ((S7ProjectBlockInfo)plcblkifo).Family;
580596
retVal.BlockType = blkInfo.BlockType;
581597
retVal.Attributes = step7Attributes;
582598

583-
retVal.LastCodeChange = myTmpBlk.LastCodeChange;
584-
retVal.LastInterfaceChange = myTmpBlk.LastInterfaceChange;
585-
586599
retVal.ParentFolder = this;
587600
retVal.usedS7ConvertingOptions = myConvOpt;
588601
retVal.CheckSum = myTmpBlk.CheckSum;
@@ -599,6 +612,7 @@ public Block GetBlock(ProjectBlockInfo blkInfo, S7ConvertingOptions myConvOpt)
599612

600613
retVal.LastCodeChange = myTmpBlk.LastCodeChange;
601614
retVal.LastInterfaceChange = myTmpBlk.LastInterfaceChange;
615+
retVal.LastInterfaceChangeHistory = myTmpBlk.LastInterfaceChangeHistory;
602616

603617
retVal.BlockNumber = plcblkifo.BlockNumber;
604618
retVal.Name = plcblkifo.Name;
@@ -611,7 +625,14 @@ public Block GetBlock(ProjectBlockInfo blkInfo, S7ConvertingOptions myConvOpt)
611625
retVal.Author = myTmpBlk.username;
612626
retVal.Version = myTmpBlk.version;
613627

614-
retVal.Parameter = Parameter.GetInterfaceOrDBFromStep7ProjectString(myTmpBlk.blkinterface, ref ParaList, blkInfo.BlockType, false, this, retVal, myConvOpt);
628+
if (myConvOpt.CheckForInterfaceTimestampConflicts && retVal.HasInterfaceTimestampConflict)
629+
{
630+
retVal.Parameter = GetInterfaceStructureFromMC7(blkInfo, myTmpBlk, retVal, ref ParaList);
631+
}
632+
else
633+
{
634+
retVal.Parameter = Parameter.GetInterfaceOrDBFromStep7ProjectString(myTmpBlk.blkinterface, ref ParaList, blkInfo.BlockType, false, this, retVal, myConvOpt);
635+
}
615636

616637
if (myTmpBlk.blockdescription != null)
617638
{
@@ -805,7 +826,46 @@ public Block GetBlock(ProjectBlockInfo blkInfo, S7ConvertingOptions myConvOpt)
805826
}
806827
}
807828
return null;
808-
}
829+
}
830+
831+
/// <summary>
832+
/// Converts the MC7 code of the block interface to S7DataRow
833+
/// </summary>
834+
public S7DataRow GetInterfaceStructureFromMC7(ProjectBlockInfo blkInfo, TmpBlock myTmpBlk, S7Block block, ref List<string> paramList)
835+
{
836+
if (myTmpBlk.blkinterfaceInMC5 == null || myTmpBlk.blkinterfaceInMC5.Length == 0)
837+
{
838+
return null;
839+
}
840+
841+
try
842+
{
843+
// Not sure what bytes 0-2 in the header are for
844+
// Bytes 3-4 are the interface length (not including header)
845+
var interfaceLen = BitConverter.ToUInt16(myTmpBlk.blkinterfaceInMC5, 3);
846+
var headerPlusInterfaceLen = 7 + interfaceLen;
847+
var interfaceBytes = new byte[headerPlusInterfaceLen];
848+
Array.Copy(myTmpBlk.blkinterfaceInMC5, 0, interfaceBytes, 0, headerPlusInterfaceLen);
849+
850+
// Bytes 5-6 are the start values length
851+
var startValuesLen = BitConverter.ToUInt16(myTmpBlk.blkinterfaceInMC5, 5);
852+
byte[] startValuesBytes = null;
853+
if (startValuesLen > 0)
854+
{
855+
startValuesBytes = new byte[startValuesLen];
856+
Array.Copy(myTmpBlk.blkinterfaceInMC5, headerPlusInterfaceLen, startValuesBytes, 0, startValuesLen);
857+
}
858+
859+
// Only DB blocks have actual values
860+
var actualValuesBytes = blkInfo.BlockType == PLCBlockType.DB ? myTmpBlk.mc7code : null;
861+
862+
return Parameter.GetInterface(interfaceBytes, startValuesBytes, actualValuesBytes, ref paramList, blkInfo.BlockType, myTmpBlk.IsInstanceDB, block);
863+
}
864+
catch
865+
{
866+
return null;
867+
}
868+
}
809869

810870
/// <summary>
811871
/// With this Function you get the AWL Source of a Block, so that it can be imported into Step7

LibNoDaveConnectionLibrary/PLCs/S7_xxx/MC7/Parameter.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,14 @@ internal static S7DataRow GetInterface(byte[] interfaceBytes, byte[] startValueB
642642
S7DataRow parameterTEMP = new S7DataRow("TEMP", S7DataRowType.STRUCT, myBlk);
643643
S7DataRow parameterRETVAL = new S7DataRow("RET_VAL", S7DataRowType.STRUCT, myBlk);
644644

645+
parameterIN.isRootBlock = true;
646+
parameterOUT.isRootBlock = true;
647+
parameterINOUT.isRootBlock = true;
648+
parameterINOUT.isInOut = true;
649+
parameterSTAT.isRootBlock = true;
650+
parameterTEMP.isRootBlock = true;
651+
parameterRETVAL.isRootBlock = true;
652+
645653
//All blocks may have In, Out or In/Out parameters
646654
//Info: the order in which they are added to the Root is important
647655
parameterRoot.Add(parameterIN);

0 commit comments

Comments
 (0)