This example shall implement the functionality of a lock object. This means that the value of an input data point shall only be forwarded to an output data point if the value of another input item (called lock object) is not set to a configured Boolean value. This functionality is shown in the following truth table (suppose the configured value for the lock object is "true"):
Input data point | Lock object | Output data point |
---|---|---|
a | false | a |
b | false | b |
... | false | ... |
a | true | x |
b | true | x |
... | true | x |
Creating the command
Within the NETx BMS Studio, start the XLogic Editor using the corresponding icon in the toolbar. Then select the entry "New Command ..." from the menu "File". A new dialog opens that is used to define the name of the command as well as its inputs, outputs, and parameters.
Within this dialog, set the name to "Lock" and define the following inputs:
- Input data point: this is the item ID that specifies the input that shall be monitored.
Then, define following outputs:
- Output data point: this is the item ID that specifies the output where the result shall be written.
Finally, define the following parameters:
- Lock object: this parameter of type "ITEM ID" specifies the data point that is used as lock object. The lock object can also be defined as input. However, the difference between an input and a parameter of type "ITEM ID" is that a change of value of an input triggers the execution of command while a change of value of a parameter does not trigger the command.
- Lock value: this parameter of type "BOOL" specifies the value where the value is not forwarded. This parameter is optional.
The dialog with all correct values is shown in the following figure.
\subsection{\nxatext{Command flow}{Kommandoablauf}}
\nxatext
{
As next the command flow has to be defined. For the proposed command, an "IF THEN ELSE" condition and a "CMD" block is needed. Drag and drop both blocks from the catalog on the left hand side onto the work sheet. For documentation purpose, it is possible to set a comment to each block. Double click the "<comment>" field within each block and enter a comment (e.g. "Verify lock object" for the condition and "Write output" for the command block).
}
{
Als nächsten Schritt muss der Kommandoablauf definiert werden. Für das gewünschte Kommando wird eine "IF THEN ELSE" Bedingung und ein "CMD" Block benötigt. Per Drag and Drop sind beide Blöcke auf die Arbeitsfläche aus dem Katalog in der linken Seite zu ziehen. Zur Dokumentation kann zu jedem Block ein Kommentar hinzugefügt werden. Dies erfolgt mittels Doppelklick auf das Feld "<comment>" des jeweilige Blocks (z.B. "Verify lock object" für die Bedingung und "Write output" für den Kommandoblock).
}
\nxatext
{
To define the command flow, the blocks have to be connected to each other. The command flow is defined from left to right -- starting with the "CMD HEADER" block (begin of the command) and ending with the "CMD END" block (end of command). First, connect the "CMD HEADER" block with "PREV" connector of the "IF THEN ELSE" block. Then connect the "THEN NEXT" connector with the "FINISH" connector of the "CMD END" block and the "ELSE NEXT" connector with the "PREV" connector of "CMD" block. Finally, connect the "NEXT" connector of the "CMD" block with the "FINISH" connector of the "CMD END" block. The idea behind this command flow is as follows. After command start, the lock object is verified with the "IF THEN ELSE" condition. If the condition verifies to true (the object is locked), the command shall finish immediately. If the lock object is false, the output is written by calling the "CMD" block. The final command flow is shown in figure \ref{fig:lock_workflow}.
}
{
Um den Kommandoablauf zu definieren, müssen die Blöcke miteinander verbunden werden. Der Kommandoablauf (von links nach rechts definiert) startet mit dem "CMD HEADER" Block (Anfang des Kommandos) und endet mit dem "CMD END" Block (Ende des Kommandos). Verbinde zunächst den "CMD HEADER" Block mit dem "PREV" Konnektor des "IF THEN ELSE" Blocks. Dann muss der "THEN NEXT" Konnektor mit dem "FINISH" Konnektor des "CMD END" Blocks und der "ELSE NEXT" Konnektor mit dem "PREV" Konnektor des "CMD" Blocks verbunden werden.
Verbinde abschließend den "NEXT" Konnektor des "CMD" Blocks mit dem "FINISH" Konnektor des "CMD END" Blocks. Die Idee hinter dem Kommandoablauf ist folgende. Nach dem Startkommando wird das Sperrobjekt über die "IF THEN ELSE" Bedingung verifiziert. Wenn die Bedingung "`True"' ist (das Objekt ist gesperrt), wird das Kommando sofort beendet. Wenn das Sperrobjekt "`False"' ist, wird der Output per Aufruf des "CMD" Blocks geschrieben. Der Kommandoablauf ist in Abbildung \ref{fig:lock_workflow} dargestellt.
}
\nxagraphic
{examples/fig/lock_workflow.png}
{examples/fig/lock_workflow.png}
{Defining the command flow}
{Definieren des Kommandablaufs}
{lock_workflow}
{300pt}
{0.5pt}
\subsection{\nxatext{Verifying the lock object}{Prüfen des Sperrobjekts}}
\nxatext
{
As next the lock object has to be verified. By doing a double click on "IF THEN ELSE" condition, the work sheet of the condition opens. Within this condition, the value of the lock object shall be compared with the lock value that is provided as parameter. First, the value of lock object has to be retrieved. To do so, place a "PARAMETER VALUE" block and an "ITEM VALUE" block on the work sheet and connect the "VALUE" connector of the "PARAMETER VALUE" block with the "ITEM ID" connector of the "ITEM VALUE" block. Then, double click the "<empty>" field of the "PARAMETER VALUE" block and select "Lock object" from the drop down list. In this way, the current value of the data point behind the lock object is retrieved. The "PARAMETER VALUE" block provides the Item ID of the lock object that the use has to be specified via the parameter "Lock object". Using this Item ID as input, the "ITEM VALUE" block gets the current value of lock object i.e. the item behind the lock object.
}
{
Als nächsten Schritt ist das Sperrobjekt zu verifizieren. Mit einem Doppelklick auf die "IF THEN ELSE" Bedingung wird der Arbeitsbereich der Bedingung geöffnet. In dieser Bedingung soll der Wert des Sperrobjekts mit dem Sperrwert der über den Parameter zur Verfügung steht verglichen werden. Zuerst muss der Wert des Sperrobjekts abgefragt werden. Ein "PARAMETER VALUE" Block und ein "ITEM VALUE" Block muss auf die Arbeitsfläche platziert werden und der "VALUE" Konnektor des "PARAMETER VALUE" Blocks mit dem "ITEM ID" Konnektor des "ITEM VALUE" Blocks verbunden werden. Per Doppelklick auf das "<empty>" Feld des "PARAMETER VALUE" Blocks ist "Lock object" aus dem Auswahlmenü auszuwählen. Auf diesem Weg wird der aktuelle Wert des Datenpunktes hinter dem Sperrobjekt empfangen. Der "PARAMETER VALUE" Block stellt die Item ID des Sperrobjekts zur Verfügung, der über den Parameter "Lock object" definiert werden muss. Wird die Item ID als Eingabe verwendet, wird der aktuelle Wert des Sperrobjekts auf den "ITEM VALUE" Block geschrieben d.h. auf das Item hinter dem Sperrobjekt.
}
\nxagraphic
{examples/fig/lock_condition.png}
{examples/fig/lock_condition.png}
{Defining the condition}
{Definieren der Bedinung}
{lock_condition}
{300pt}
{0.5pt}
\nxatext
{
Afterwards, place another "PARAMETER VALUE" on the work sheet. Double click the "<empty>" field and select "Lock value" as parameter. In this way, this "PARAMETER VALUE" block provides the user-defined lock value that defines when the input shall be forwarded to the output. However, since the "Lock value" parameter is optional, a default value has to set that is used whenever the user does not define a specific lock value. This is done by adding a "BOOL" block. Using a double click on the block, the value "TRUE" has to be selected. Then, the outgoing connector of the "BOOL" block has to linked to incoming connector of the "PARAMETER VALUE" block.
}
{
Nun soll ein weiterer "PARAMETER VALUE" Block auf den Arbeitsbereich platziert werden. Mittels Doppelklick auf das "<empty>" Feld soll "Lock value" als Parameter ausgewählt werden. Dadurch enthält der "PARAMETER VALUE" Block den benutzerdefinierten Sperrwert, welcher definiert, wann der Input auf den Output weitergeleitet werden soll. Da dieser Parameter optional ist, muss ein Standardwert definiert werden, für den Fall dass der Benutzer keinen Sperrwert definiert. Um diesen Wert zu definieren, muss ein "BOOL" Block hinzugefügt werden. Mittels Doppelklick auf den Block kann der Wert "TRUE" selektiert wird. Anschließend muss der ausgehende Konnektor des "BOOL" Blocks mit dem eingehenden Konnektor des "PARAMETER VALUE" Blocks verbunden werden.
}
\nxatext
{
Now place an "EQUALS" block on the workspace and connect the "VALUE" connector of the "ITEM VALUE" block and the "VALUE" connector of the "PARAMETER VALUE(Lock Value)" block with the "INPUT" connectors of the "EQUAL" block. Finally, connect the "Output" connector of the "EQUAL" block with the "RESULT" connector of the "END" block. The final condition is shown in figure \ref{fig:lock_condition}.
}
{
Danach wird ein "EQUALS" Block auf der Arbeitsfläche platziert. Der "VALUE" Konnektor des "ITEM VALUE" Blocks und der "VALUE" Konnektor des "PARAMETER VALUE(Lock Value)" Blocks werden mit den "INPUT" Konnektoren des "EQUAL" Blocks verbunden. Abschließend ist der "Output" Konnektor des "EQUAL" Blocks mit dem "RESULT" Konnektor des "END" block zu verbinden. Die finale Bedingung ist in Abbildung \ref{fig:lock_condition} dargestellt.
}
\subsection{\nxatext{Writing the output}{Schreiben des Ausgangs}}
\nxatext
{
Close the condition and double click the "CMD" block within the command flow. Place an "INPUT ITEM VALUE" block and a "WRITE OUTPUT ITEM" block on the work sheet. Connect the "VALUE" connectors of both blocks with each other. Then double click the "<empty>" field of the "INPUT ITEM VALUE" block and select the "Input data point" input. In addition, double click the "<empty>" field of the "WRITE OUTPUT ITEM" block and select the "Output data point" output. In this way, the current value of the input data point is written to the output data point. The final command definition is shown in figure \ref{fig:lock_cmd}.
}
{
Nun ist die Bedingung zu schließen und auf den "CMD" Block im Kommandoablauf doppelt zu klicken. Ein "INPUT ITEM VALUE" Block und ein "WRITE OUTPUT ITEM" Block ist auf die Arbeitsfläche zu platzieren. Die "VALUE" Konnektoren von beiden Blöcken sollen nun miteinander verbunden werden. Per Doppelklick auf das "<empty>" Feld des "INPUT ITEM VALUE" Block ist "Input data point" als Input auszuwählen. Zusätzlich ist auf "<empty>" Feld des "WRITE OUTPUT ITEM" Blocks doppelt zu klicken, um "Output data point" Output auszuwählen. Dadurch wird der aktuelle Wert des Input Datenpunktes auf den Output Datenpunkt geschrieben. Die abschließende Kommandodefinition ist in Abbildung \ref{fig:lock_cmd} dargestellt.
}
\nxagraphic
{examples/fig/lock_cmd.png}
{examples/fig/lock_cmd.png}
{Writing the output}
{Schreiben des Ausgangs}
{lock_cmd}
{300pt}
{0.5pt}
\subsection{\nxatext{Saving the command and using the command within the \productbmsserver}{Speichern und Verwenden des Kommandos innerhalb des \productbmsserver s}}
\nxagraphic
{examples/fig/lock_compile.png}
{examples/fig/lock_compile.png}
{Compiling the command}
{Kompilieren des Kommandos}
{lock_compile}
{130pt}
{0.5pt}
\nxatext
{
To provide the command to the \productbmsserver, it has to be compiled. This can be done by clicking the "Save" icon within the toolbar which saves and compiles the current command. In addition, it is possible to change several options of a command. To open the "Options" dialog, the entry "Options ..." within the menu "File" has to be selected (cf. figure \ref{fig:lock_compile}). Within this dialog, basic information about the command can be specified. To make the command visible within the catalog of the \productname\ and to reuse it in other commands, the flag "Add to Catalog" has to be activated. If the option "Auto-Compile" is set, the command is automatically compiled whenever the project is saved.
}
{
Um das erstellte Kommando dem \productbmsserver zur Verfügung zu stellen, muss dieses kompiliert werden. Durch Betätigen des "Save" Icons in der Toolbar wird das momentane Kommando kompiliert und gespeichert. Zusätzlich ist es möglich, diverse Einstellungen eines Kommandos zu ändern. Um den "Options" Dialog zu öffnen, muss der Eintrag "Options ..." im Menü "File" gewählt werden (siehe Abbildung \ref{fig:lock_compile}). In diesem Dialog können zusätzliche Informationen hinterlegt werden. Die Markierung "Add to Catalog" definiert ob das Kommando im Katalog des \productname\ sichtbar sein soll.
}
\nxatext
{
After having compiled the command successfully, close the \productname\ and go back to the \productbmsstudio. Afterwards, the new command has to be loaded before it can be used. This can be done by restarting the \productbmsserver\ or by loading the command manually by selecting the entry "Load logic module" within the "Tools" menu of the \productbmsstudio\ (cf. section \ref{sec:execute_command}). Then, open the "XCommand event definitions" via the menu "Extensions". Add a new definition and enter a name for the command within the first column. The next column can be left empty since all variables shall only be used locally. Within the third column, select "ON\_INPUT". This indicates that the command shall be invoked whenever one of the inputs changes. Then, press the "..." button within the "XCommand" column. A dialog appears where the command can be selected and configured. Select the "Lock" command from the drop down list. Afterwards, specify the different inputs, outputs, and parameters. A possible configuration is shown in figure \ref{fig:lock_bms}.
}
{
Nachdem das Kommando erfolgreich kompiliert wurde, kann der \productname\ geschlossen und zum \productbmsstudio\ zurückgekehrt werden. Vor Verwendung muss das neue Kommando geladen werden. Dies erfolgt mittels Neustart des \productbmsserver s oder durch manuelles Laden des Kommandos mithilfe des Entrags "Load logic module" innerhalb des "Tools" Menüs des \productbmsstudio s (vgl. Kapitel \ref{sec:execute_command}). Anschließlich, muss die "XCommand event definitions" Tabelle über den Menüeintrag "Extensions" geöffnet und eine neue Definition hinzugefügt werden. In der ersten Spalte muss ein Name für das Kommando vergeben werden. Die nächste Spalte muss leer bleiben, da alle Variablen nur lokal verwendet werden. Innerhalb der dritte Spalte ist "ON\_INPUT" zu wählen. Diese Option legt fest, dass das Kommando bei jeder Änderung eines Inputs ausgeführt wird. Anschließend ist auf den "..." Button in der "XCommand" Spalte zu klicken. Nun öffnet sich ein Dialog, in dem das Kommando selektiert und konfiguriert werden kann. Das "Lock" Kommando ist aus dem Auswahlmenü zu selektieren. Anschließend müssen noch Definitionen für die Inputs, Outputs und Parameter vergeben werden. Eine mögliche Konfiguration ist in Abbildung \ref{fig:lock_bms} dargestellt.
}
\nxagraphic
{examples/fig/lock_bms.png}
{examples/fig/lock_bms.png}
{Defining the command within the \productbmsstudio}
{Deinieren des Kommandos im \productbmsstudio}
{lock_bms}
{200pt}
{0.5pt}
\nxatext
{
After having saved the "XCommand event definition", restart the \productbmsserver\ and test the command\footnote{Note that the item behind the lock object has to be initialized. If the lock object has not the item quality "GOOD", an error will be shown. A possible solution to this problem is described in following section.}.
}
{
Nachdem die "XCommand event definition" gespeichert wurde, muss der \productbmsserver\ zum Testen des Kommando neu gestartet werden\footnote{Zu Beachten ist dass das Item hinter dem Sperrobjekt initialisiert werden muss. Wenn das Sperrobjekt nicht die Item-Qualität "GOOD" hat, wird ein Fehler angezeigt. Eine Lösung für dieses Problem ist im folgenden Abschnitt beschrieben}.
}
\subsection{\nxatext{Improving the command by testing the quality of the lock object}{Verbesserung des Kommandos durch prüfen der Qualität des Sperrobjekts}}
\nxatext
{
If the command is executed and the item behind the lock object has the quality "UNCERTAIN" or "BAD", an error will occur. The reason is that the "ITEM VALUE" block within the condition does not provide a correct value and thus the "EQUALS" block gets a wrong input. To solve this, another condition has to be added to the command.
}
{
Wird das Kommando ausgeführt und das Item hinter dem Sperrobjekt hat die Qualität "UNCERTAIN" oder "BAD", entsteht ein Fehler. Die Ursache für dieses Ergebnis ist der "ITEM VALUE" Block in der Bedingung der nicht den korrekten Wert liefert und dadurch erhält der "EQUALS" Block einen falschen Input. Um dieses Problem zu lösen muss eine zusätzliche Bedingung zum Kommando hinzugefügt werden.
}
\nxagraphic
{examples/fig/lock_improvement.png}
{examples/fig/lock_improvement.png}
{Improving the command}
{Verbessern des Kommandos}
{lock_improvement}
{320pt}
{0.5pt}
\nxatext
{
Open the \productname\ and reopen the "Lock" command via the menu "File". Place a new "IF THEN ELSE" block on the workspace. Connect the "START" connector of the "CMD HEADER" block to the "PREV" connector of the new "IF THEN ELSE" block. Then connect the "THEN NEXT" connector of the new block to the "PREV" connector of the "Verify lock object" block and the "ELSE NEXT" connector of the new block to the "FINISH" connector of the "CMD END" block. The new command flow is shown in figure \ref{fig:lock_improvement}.
}
{
Nach öffnen des \productname\ kann das "Lock" Kommando über den Menüeintrag "File" erneut geöffnet werden. Ein neuer "IF THEN ELSE" Block soll auf der Arbeitsfläche platziert werden. Der "START" Konnektor des "CMD HEADER" Blocks ist mit dem "PREV" Konnektor des neuen "IF THEN ELSE" Blocks zu verbinden. Der "THEN NEXT" Konnektor des neuen Blocks ist dann mit dem "PREV" Konnektor des "Verify lock object" Blocks und der "ELSE NEXT" Konnektor des neuen Blocks mit dem "FINISH" Konnektor des "CMD END" Blocks zu verbinden. Der neue Kommandofluss ist in Abbildung \ref{fig:lock_improvement} dargestellt.
}
\nxatext
{
Then, open the "Verify quality" condition and place a "PARAMETER VALUE" and a "IS GOOD" block on the work sheet. Select the parameter "Lock object" within the new "PARAMETER VALUE" block. Connect the "VALUE" of the "PARAMETER VALUE" connector to the "Item ID" connector of the "IS GOOD" block and the "Output" connector of the "IS GOOD" block to the "RESULT" connector of the "END" block. In this way, the item quality of the "Lock object" is tested. If the quality is "GOOD", the result of the condition is also true -- otherwise it is false. The final condition is shown in figure \ref{fig:lock_test_quality}.
}
{
Nun ist die "Verify quality" Bedingung zu öffnen und ein "PARAMETER VALUE" und ein "IS GOOD" Block sind im Arbeitsbereich zu platzieren. Selektiere den Parameter "Lock object" im neuen "PARAMETER VALUE" Block. Verbinde den "VALUE" Parameter des "PARAMETER VALUE" Konnektors mit dem "Item ID" Konnektor des "IS GOOD" Block und dem "Output" Konnektor des "IS GOOD" Block mit dem "RESULT" Konnektor des "END" Blocks. Auf diesem Weg wird die Item-Qualität des "Lock object" getestet. Wenn die Qualität "GOOD" ist, ist das Resultat der Bedingung ebenfalls true -- andernfalls false. Die finale Bedinung ist in Abbildung \ref{fig:lock_test_quality} dargestellt.
}
\nxagraphic
{examples/fig/lock_test_quality.png}
{examples/fig/lock_test_quality.png}
{Test the quality of the lock object}
{Testen der Qualität des Lockobjekts}
{lock_test_quality}
{300pt}
{0.5pt}
\nxatext
{
After having finished the new condition, save the project, compile it, restart the \productbmsserver, and test the improvement. Now, the command tests the quality of the lock object and does not invoke any function if the quality is not "GOOD".
}
{
Nachdem die neue Bedingung fertiggestellt wurde, das Projekt gespeichert und kompiliert wurde, der \productbmsserver\ neu gestartet wurde, kann die Verbesserung abschließend getestet werden. Das Kommando testet nun die Qualität des Sperrobjekts und führt keine Funktionen aus, wenn die Qualität nicht "GOOD" ist.
}