************************************************************************************************************************** Compatible to Elvis since Version 1.3 This file contains the global script for a scene solution running in the Elvis process server, additional information and instructions. ************************************************************************************************************************** Instructions: 1. Open the project and the datapoint list. 2. Execute the macro szene_svr.idm. 3. Enter the path where the scene files should be stored into the persistent property ActualValue of the datapoint _Szene_PathName. 4. The datapoints: _Szene_Spielen_Start (for starting the scene playback) _Szene_SzeneName (for specifying the scene name) have to be represented in a page in Elvis terminal. The scene name can e.g. be either entered by a Elvis TextInput Control or selected from a fixed list (e.g. via a StateButton Control; in this case the scene names are the state numbers 0, 1, ...) 5. Optionally also the datapoints: _Szene_Aufzeichnen (for starting the scene recording) _Szene_Optimieren_Start (for removing multiple entries for the same datapoints, only the last entry will be kept) can be added to a terminal page. 6. The value of _Szene_Aufzeichnen is checked in some calculations and therefore should be set to True or False in any case. ************************************************************************************************************************** Information: The scene file: The scene file is a text file with a path name combined from the path (_Szene_PathName), the scene name (_Szene_SzeneName) and the extension .txt. Its content is: Counter (_Szene_Zähler); Datapoint name; Nominal value Example: 1;light4; 30 2;light1; True 3;light2; True 4;light3; False 5;light5; False 6;light4; 50 7;light1; False The scene recording: If the datapoint _Szene_Aufzeichnen has the value True, all changes in the NominalValue of all datapoints (except if the datapoint name starts with _Szene) are written to the selected scene file (OnDatapointChanged in global script). If the file does not yet exist, it will be created. If the file exists, new entries will be appended! The scene playback: By writing to _Szene_Spielen_Start, the calculation of _Szene_Spielen is executed. This reads in the scene file and sets the contained NominalValues. Optimizing the scene file: During recording a datapoint may be recorded mor ethan once (see example above). The calculation in _Szene_Optimieren removes such double entries for the same datapoint from the scene file. The last entry for each datapoint is kept. After optimizing, the above example looks like this: 3;light2; True 4;light3; False 5;light5; False 6;light4; 50 7;light1; False ************************************************************************************************************************** The global script: please copy everything below this list into the global script! Option Explicit '************************************************************************ Function OpenSequence(sFileName As String, nMode As Integer) As Integer Print "Try to open sequence for: " & sFileName 'mode 0 = open file for input 'mode 1 = open file for append 'mode 2 = open file for output Dim nFile As Integer nFile = FreeFile If nFile Then If nMode = 0 Then Print "mode = 0 File Name: " & sFileName Open sFileName For Input As nFile ElseIf nMode = 1 Then Print "mode = 1 File Name: " & sFileName Open sFileName For Append As nFile ElseIf nMode = 2 Then Print "mode = 2 File Name: " & sFileName Open sFileName For Output As nFile End If End If OpenSequence = nFile End Function '************************************************************************ Function CloseSequence (nFileHandle As Integer) As Boolean If nFileHandle Then Close #nFileHandle CloseSequence = True Else 'hier werden zur Sicherheit alle Dateien geschlossen Print "In die Funktion CloseSequence wurde ein ungültiges file handle übergeben." Print "Zur Sicherheit wurden alle Dateien geschlossen." Close CloseSequence = False End If End Function '************************************************************************ 'Hier wird die Sequenz aufgezeichnet (es können doppelte Einträge enthalten sein) Sub OnDatapointChanged(ByVal DP As Object, ByVal prop As String) If Left(DP.Name, 6) <> "_Szene" Then If prop = "NominalValue" And Database.Datapoint("_Szene_Aufzeichnen").ActualValue = True Then Dim nFile As Integer Dim sFile As String Dim OutputLine As String Dim Zähler As Integer sFile = Database.Datapoint("_Szene_PathName").ActualValue & Database.Datapoint("_Szene_SzeneName").ActualValue & ".txt" 'Print "jetzt Zähler ermitteln" Zähler = GetZaehler(sFile) + 1 'Print "jetzt Datei zum Schreiben öffnen" nFile = OpenSequence(sFile, 1) OutputLine = Zähler & ";" & DP.Name & ";" & Str(DP.NominalValue) 'Database.Datapoint("_Szene_Zähler").ActualValue = Zähler + 1 Beep Print #nFile, OutputLine 'Line Output #nFile, OutputLine Call CloseSequence(nFile) End If End If End Sub '************************************************************************ Function GetZaehler(sFileSource As String) As Integer 'Hier wird der Zähler aus der Datei ermittelt. Dazu wird der letzte Eintrag in der Datei geholt und um eins erhöht. Dim nFileSource As Integer Dim sInputLine As String Dim sSeqNum As String Dim nMaxZaehler As Integer Dim sDPName As String Dim sValue As String nMaxZaehler = 0 On Error GoTo FileExistError nFileSource = OpenSequence(sFileSource, 0) If nFileSource Then While Not EOF(nFileSource) Line Input #nFileSource, sInputLine ' Sonderzeichen (CR/LF) am Ende entfernen Do If sInputLine = "" Then Exit Do If Asc(Right(sInputLine, 1)) < 0 Or Asc(Right(sInputLine, 1)) > 32 Then Exit Do sInputLine = Left(sInputLine, Len(sInputLine) - 1) Loop Call ParseInputLine(sInputLine, sSeqNum, sDPName, sValue) If Int(sSeqNum) > nMaxZaehler Then nMaxZaehler = Int(sSeqNum) Wend Call CloseSequence(nFileSource) End If FileExistError: GetZaehler = nMaxZaehler End Function '************************************************************************ Function ParseFile(sFileSource As String, sSeqNumToCheck As String, sDPNameToCheck As String) As Boolean Dim nFileSource As Integer Dim sInputLine As String Dim sSeqNum As String Dim sDPName As String Dim sValue As String nFileSource = OpenSequence(sFileSource, 0) 'zuerst den Datenpunktname suchen und dann vergleichen ob die SeqNum größer ist oder noch kleiner While Not EOF(nFileSource) Line Input #nFileSource, sInputLine If InStr(1, sInputLine, sDPNameToCheck) Then ' Sonderzeichen (CR/LF) am Ende entfernen Do If sInputLine = "" Then Exit Do If Asc(Right(sInputLine, 1)) < 0 Or Asc(Right(sInputLine, 1)) > 32 Then Exit Do sInputLine = Left(sInputLine, Len(sInputLine) - 1) Loop Call ParseInputLine(sInputLine, sSeqNum, sDPName, sValue) If Int(sSeqNum) > Int(sSeqNumToCheck) Then 'der Datenpunkt wurde nochmal gefunden ParseFile = True GoTo ExitFunction End If End If Wend ParseFile = False ExitFunction: If nFileSource Then Call CloseSequence(nFileSource) End Function '************************************************************************ Function ParseInputLine(InputLine As String, ByRef InputSeqNum As String, ByRef InputName As String, ByRef InputValue As String) As Boolean Dim iSep1 As Integer, iSep2 As Integer Dim sSep As String sSep = ";" 'Dim InputSeqNum As String 'Dim InputName As String 'Dim InputValue As String ' Sequence Number iSep1 = InStr(1, InputLine, sSep) If iSep1 = 0 Then ParseInputLine = 0 : Exit Function InputSeqNum = Trim(Left(InputLine, iSep1 - 1)) ' Datapoint Name iSep2 = InStr(iSep1+1, InputLine, sSep) If iSep2 = 0 Then ParseInputLine = 0 : Exit Function Else InputName = Trim(Mid(InputLine, iSep1 + 1, iSep2 - iSep1 - 1)) End If ' Nominal Value InputValue = Trim(Right(InputLine, Len(InputLine) - iSep2)) ' Anführungszeichen um InputSeqNum entfernen If Len(InputSeqNum) >= 2 Then If Left(InputSeqNum, 1) = Chr$(34) Then InputSeqNum = Right(InputSeqNum, Len(InputSeqNum) - 1) If Right(InputSeqNum, 1) = Chr$(34) Then InputSeqNum = Left(InputSeqNum, Len(InputSeqNum) - 1) End If ' Anführungszeichen um InputName entfernen If Len(InputName) >= 2 Then If Left(InputName, 1) = Chr$(34) Then InputName = Right(InputName, Len(InputName) - 1) If Right(InputName, 1) = Chr$(34) Then InputName = Left(InputName, Len(InputName) - 1) End If ' Anführungszeichen um InputValue entfernen If Len(InputValue) >= 2 Then If Left(InputValue, 1) = Chr$(34) Then InputValue = Right(InputValue, Len(InputValue) - 1) If Right(InputValue, 1) = Chr$(34) Then InputValue = Left(InputValue, Len(InputValue) - 1) End If If InStr(iSep2, InputValue, "True") Then InputValue = "True" ElseIf InStr(iSep2, InputValue, "False") Then InputValue = "False" End If ParseInputLine = -1 End Function '************************************************************************ Function SetNominalValue(InputName As String, InputValue As String) As Boolean Dim sDP_Name As String Print "*** Jetzt wird der Wert von: " & InputName & " auf: " & InputValue & " gesetzt." sDP_Name = CStr(InputName) If InputValue = "True" Then Database.Datapoint(sDP_Name).NominalValue = True ElseIf InputValue = "False" Then Database.Datapoint(sDP_Name).NominalValue = False Else Database.Datapoint(sDP_Name).NominalValue = Val(InputValue) End If SetNominalValue = -1 End Function