Tutorial:Erstellen neuer Relaisgruppen - Skripte erstellen: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| Zeile 171: | Zeile 171: | ||
== Konstanten == | == Konstanten == | ||
* const int VERSCHLUSSLEVEL_MAX; Maximal mögliches Verschlusslevel (= keine Einschränkungen) | * const int VERSCHLUSSLEVEL_MAX; Maximal mögliches Verschlusslevel (= keine Einschränkungen) | ||
* const int CONNECTION_STATE_CONNECTING; Die Schnittstelle wird gerade mit der Relaisgruppe verbunden. | |||
* const int CONNECTION_STATE_DISCONNECTING; Die Schnittstelle wird gerade von der Relaisgruppe getrennt. | |||
* enum SpeedBinding; Gibt an, an welchen Zeitraffer der Timer gebunden werden soll | * enum SpeedBinding; Gibt an, an welchen Zeitraffer der Timer gebunden werden soll | ||
** const int Speed_None; Zeitrafferunabhängige Zeitmessung. Sollte nicht verwedet werden. | ** const int Speed_None; Zeitrafferunabhängige Zeitmessung. Sollte nicht verwedet werden. | ||
| Zeile 199: | Zeile 201: | ||
** Besonderheiten: | ** Besonderheiten: | ||
*** Schnittstelle freie; Übernimmt Ein- und Ausgangssignale der Freien Eingangslogiken. (Ausgangssignale noch nicht getestet.) | *** Schnittstelle freie; Übernimmt Ein- und Ausgangssignale der Freien Eingangslogiken. (Ausgangssignale noch nicht getestet.) | ||
*** Signal connectionState; Wird vor und nach dem Verbinden und Trennen von Schnittstellen gesendet, und gibt an, ob die Werte Verbindungswerte, Trennungswerte oder normale Werte sind (siehe auch Konstanten). | |||
* '''Timer''' | * '''Timer''' | ||
** Methoden: | ** Methoden: | ||
Version vom 1. März 2014, 20:16 Uhr
Der Programmablauf von StellSi wird über Scripte gesteuert. Das Scriptsystem von StellSi basiert dabei auf dem C(++)-Ähnlichen Angelscript (http://www.angelcode.com/angelscript/).
Hintergrund
Die Logik von StellSi-Stellwerken wird mithilfe von Scripten gesteuert. Das heißt hinter jedem Stellwerk steht ein kleines Programm das die Funktionen von StellSi steuert und das man auch bearbeiten kann.
Die Scripte selbst befinden sich in seperaten Dateien, den *.stws-Dateien. Sie liegen zusammen mit den Biblitotheken im Verzeichnis der Bauform. Sie können im Prinzip mit jedem beliebigen Texteditor geöffnet werden, unter Windows zum Beispiel mit Editor/Notepad. Es ist jedoch zu beachten, dass bei Dateien von Fremden Betriebssystem möglicherweise eine andere Normierung für den Zeilenumbruch verwendet wurde. (Details siehe Wikipedia.) Ist es offensichtlich, dass das Programm die Zeilenumbrüche nicht Richtig erkannt hat, hilft es meist einen anderen Editor zu verwenden (unter Windows zum Beispiel WordPad). Für den eigentlichen Code sind die Zeilenumbrüche jedoch nicht relevant.
Im Script stellt Relais- oder Anschlatgruppe eine Klasse dar. Die Schnittstellen werden über Varriablen eingefügt und rufen automatisch bestimmte Methoden auf.
Grundlagen
Die Scripte sind im Prinzip wie eine normale Programmiersprache aufgebaut. Daher soll im folgenden eine kurze Einleitung über die Scriptprogrammierung gegeben werden.
Grundlage der Programmierung sind einzelne Klassen: Eine Klasse beginnt mit dem Schlüsselwort class, es folgt der Name der Klasse, dann eine Geschweifte Klammer, innerhalb der sich der Ihnhalt der Klasse befindet. Die Klasse endet mit einer weiteren geschweiften Klammer.
class Weiche
{
//Inhalt der Klasse
}
Innerhalb einer Klasse werden allgemeine Varriablen deklariert. Varriablen speichern Daten oder stellen Verbindungen zu der Programmlogik von StellSi her. Sie beginnt mit dem Datentyp der Variable (z.B. int für eine Zahl) gefolgt von einem Namen der Varriable, mit dem man sie Später identifizieren kann, und gleich danach einem ; .
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
}
Neben den Varriablen gibt es innerhalb von Programmen noch Funktionen. Eine Funktion beginnt mit void (oder einem Datentyp) gefolgt von dem Namen der Funktion. Danach folgt eine runde geöffnete Klammer, in der angegeben wird, welche Daten der Funktion mitgegeben werden. Diese Daten werden Kommagetrennt in der Form Datentyp Name angegeben. Es folgt eine Geschweifte Klammer für den Methodenanfang, der Methodeninhalt und eine Geschweifte Klammer für das Methodenende.
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
void init()
{
//Methodeninhalt
}
void on_tischfeld_wht(int wert)
{
//Methodeninhalt
}
void beliebigeMethode(int wert, bool andererWert)
{
//Methodeninhalt
}
}
Innerhalb der Methoden kann man mit den Varriablen Rechnen und ihnen Werte zuweisen. + addiert zwei Zahlen, - subtrahiert sie, * multipliziert, / dividiert Sie. Mit == wird überprüft ob Zahlen oder Warheitswerte gleich sind, das Ergebnis ist ein Warheitswert. Mit = werden Zahlen oder Warheitswerte zugewiesen. Mit ! wird aus einem Warheitswert sein Gegenteil. Mit & oder && wird Zurückgegeben, ob der eine und der andere Warheitswert Wahr ist, mit | oder || wird zurückgegeben, ob der eine oder der andere Warheitswert Wahr ist. Mit <, <=, > und >= wird überprüft, welche Zahl größer ist. Mit Klammern werden, wie in der Mathematik, die Reinfolgen der Rechnereien festgelegt. Alles was zwischen // und dem Zeilenende oder zwischen /* und */ folgt ist ein Kommentar und wird (im gesammten Programm) ignoriert. Ein Befehl endet mit ; . Das Programm arbeitet die Befehle Schritt für Schritt ab.
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
void init()
{
anzahlIrgendetwas=0;
tasteGedrueckt=false;
}
void on_tischfeld_wht(int wert)
{
tasteGedrueckt=true;
anzahlIrgendetwas=wert;
}
int beliebigeMethode(int wert, bool andererWert)
{
tasteGedrueckt = ((wert == 1)||(wert > 15))&&(!andererWert);
//Rest der Methode.
}
}
In den Methoden können andere Methoden aufgerufen werden. Eigene Methoden werden aufgerufen, indem man Sie mit ihrem Namen nennt, in einer Klammer kommagetrennt die Parameter übergibt und den Befehl dann wieder mit ; abschließt. Die Kommunikation mit StellSi findet statt indem man den Namen einer (Schnitstellen-)Varriablen gefolgt von einem . und dann dem Namen einer StellSi-Methode wie eine lokale Methode aufruft. Einige Methoden benötigen dafür Zeichenfolgen. Eine Zeichenfolge ist ein Text zwischen zwei Anführungszeichen.
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
void init()
{
anzahlIrgendetwas=0;
tasteGedrueckt=false;
tischfeld.setWert("besetzt",1);
}
void on_tischfeld_wht(int wert)
{
tasteGedrueckt=true;
anzahlIrgendetwas=wert;
beliebigeMethode(27,false);
}
int beliebigeMethode(int wert, bool andererWert)
{
tasteGedrueckt = ((wert == 1)||(wert > 15))&&(!andererWert);
tischfeld.setWert("irgendwas",41);
//Rest der Methode.
}
}
Der Programmablauf kann mit Bedingungen bedingt Fortgesetzt werden. Bedingungen beginnen mit if gefolgt von einem in eine Klammer eingeschlossenen Wahrheitsausdruck. Folgt nur ein Befehl kann dieser Direkt danach folgen, wenn mehrere Befehle bedingt abgearbeitet werden sollen, müssen diese in geschweifte Klammern zusammengefasst werden. Nach dem else-Schlüsselwort können auf die gleiche Art und Weise Befehle folgen, die ausgeführt werden sollen, wenn der Warheitswert false ist.
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
void init()
{
anzahlIrgendetwas=0;
tasteGedrueckt=false;
tischfeld.setWert("besetzt",1);
}
void on_tischfeld_wht(int wert)
{
tasteGedrueckt=true;
anzahlIrgendetwas=wert;
if (wert > 26)
beliebigeMethode(27,false);
else
{
beliebigeMethode(wert,true);
tischfeld.setWert("nochetwas",1);
}
}
int beliebigeMethode(int wert, bool andererWert)
{
tasteGedrueckt = ((wert == 1)||(wert > 15))&&(!andererWert);
tischfeld.setWert("irgendwas",41);
//Rest der Methode.
}
}
Die Ausführung von (void-)Methoden kann mithilfe von return; abgebrochen werden. Methoden, die nicht void sind, haben einen Rückgabewert und können daher wie Varriablen verwednet werden, um etwas zu berechnen. Sie müssen ein return beinhalten, dem der Wert, der zurückgegeben werden soll folgt.
class Weiche
{
Schnittstelle tischfeld;
int anzahlIrgendetwas;
bool tasteGedrueckt;
void init()
{
anzahlIrgendetwas=0;
tasteGedrueckt=false;
tischfeld.setWert("besetzt",1);
}
void on_tischfeld_wht(int wert)
{
tasteGedrueckt=true;
anzahlIrgendetwas=wert;
if (wert > 26)
beliebigeMethode(27,false);
else
{
beliebigeMethode(wert,true); //Kommentar
tischfeld.setWert("nochetwas" /*Kommentar*/,beliebigeMethode(0,false));
return;
}
}
int beliebigeMethode(int wert, bool andererWert)
{
tasteGedrueckt = ((wert == 1)||(wert > 15))&&(!andererWert);
tischfeld.setWert("irgendwas",41);
return 32;
}
}
Bestimmte Methoden (im obigen Fall init und die on-Methode) werden automatisch von StellSi aufgerufen. Werden Varriablen innerhalb einer Methode deklariert, gelten Sie nur bis zum Ende des aktuellen Bereiches (schließende }, wenn zwischen der } noch ein paar { aufgemacht wurden zählen die zugehörigen } natürlich nicht dazu).
Hinweis: Gibt es zum Beispiel zwei Weichen, die beide auf der Klasse Weiche aufbauen, so sind diese Unhabhängig voneinander. Die beiden Weichen arbeiten mit verschiedenen Instanzen der Klasse.
Für eine ausführlichere Anleitung sei auf die entsprechende Fachliteratur verwiesen.
Hilfsfunktionen
- void print(int value); Gibt den Wert je nach config.xml auf die Standardausgabe und/oder eine Log-Datei aus.
- void print(string value); Gibt den Wert je nach config.xml auf die Standardausgabe und/oder eine Log-Datei aus.
- int min(int a, int b); Gibt den kleineren der Werte zurück.
- int max(int a, int b); Gibt den größeren der Werte zurück.
Konstanten
- const int VERSCHLUSSLEVEL_MAX; Maximal mögliches Verschlusslevel (= keine Einschränkungen)
- const int CONNECTION_STATE_CONNECTING; Die Schnittstelle wird gerade mit der Relaisgruppe verbunden.
- const int CONNECTION_STATE_DISCONNECTING; Die Schnittstelle wird gerade von der Relaisgruppe getrennt.
- enum SpeedBinding; Gibt an, an welchen Zeitraffer der Timer gebunden werden soll
- const int Speed_None; Zeitrafferunabhängige Zeitmessung. Sollte nicht verwedet werden.
- const int Speed_Stelltisch; Bindung an den Stelltisch-Zeitraffer. Sollte nur verwendet werden, wenn eine Interaktion mit Animationen unbedingt erforderlich ist.
- const int Speed_Relaisanlage; Bindung an den Relaisanlagen-Zeitraffer. Sollte für die meisten Fälle passend sein.
- const int Speed_Aussenanlage; Bindung an den Außenanlagen-Zeitraffer. Sollte für alles, was von der Umlaufdauer von Signalen undr Weichen abhängig ist verwendet werden (z.B. Weichenwecker).
- const int Speed_Bewegung; Bindung an den Bewegungs-Zeitraffer. Sollte für alles, was Zugabhängig ist verwendet werden (z.B. Zeitschalter für Ersatzsignal).
- const int Speed_Fahrplan; Bindung an den Fahrplan-Zeitraffer. Sollte im Regelfall nicht Sinnvoll nutzbar sein.
Datentypen
- bool Warheitswert, true oder false
- int Ganzzahl, vorzeichenbehaftet, 32 Bit. Weitere Ganzzahltypen sind int8, int16, int64, uint8, uint16, uint, uint64
- float Gleitkommazahl vorzeichenbehaftet. Weitere Gleitkommazahl ist double.
- string Zeichenfolge.
- Schnittstelle Passt zu dem StellSi-Typ Schnittstelle.
- Methoden:
- void sendSignal(string signalname, string wert); Einmaliges Ereignis (z.B. Zählwerk)
- void sendSignal(string signalname, int wert);
- void setWert(string signalname, string wert); Dauerhafteter Zustand (z.B. Lampe an/aus)
- void setWert(string signalname, int wert);
- int sendSignalSyncron(string signalname, string wert); Geht an eine Schnitstelle und gibt den Wert zurück, den diese Schnittstelle zurückgibt.
- int sendSignalSyncron(string signalname, int wert);
- Ruft auf:
- void on_%Name der Schnittstellenvarriable%_%Name des Signals%(string wert); Wird aufgerufen, wenn ein Signal oder ein Wert gesendet wurde (name der Schnittstellenvarriable darf kein _ enthalten).
- void on_%Name der Schnittstellenvarriable%_%Name des Signals%(int wert);
- int on_%Name der Schnittstellenvarriable%_%Name des Signals%(string wert);
- int on_%Name der Schnittstellenvarriable%_%Name des Signals%(int wert);
- Besonderheiten:
- Schnittstelle freie; Übernimmt Ein- und Ausgangssignale der Freien Eingangslogiken. (Ausgangssignale noch nicht getestet.)
- Signal connectionState; Wird vor und nach dem Verbinden und Trennen von Schnittstellen gesendet, und gibt an, ob die Werte Verbindungswerte, Trennungswerte oder normale Werte sind (siehe auch Konstanten).
- Methoden:
- Timer
- Methoden:
- void start(float dauer, int wert, optional bool autorepeat=false); (Neu-)Start eines Timers. Dauer ist in Sekunden anzugeben.
- void stop();
- Eigenschaften:
- float timeToNextShot (readonly); Gibt die Zeit in Sekunden bis zum nächsten Auslösen an. Ist der Timer nicht gestartet wird -1 zurückgegeben.
- SpeedBinding speedDependency; Gibt an, an welchen Zeitraffer der Timer gebunden werden soll. Standardwert: Speed_Relaisanlage.
- Ruft auf:
- void _%Name der Timervarriable%(int wert);
- Methoden:
- VerschlussFahrstrasse (Details)
- Methoden:
- Ruft auf: (Details)
- on_%Name der Verschlussfahrstrassenvarriable%_%Name der Schubstange%_verschlussstangechanged(int level);
- on_%Name der Verschlussfahrstrassenvarriable%_%Name der Schubstange%_%Nummer des Zielzustandes%_festlegungchanged(int level);
- VerschlussElement (Details)
- Methoden:
- void setLevelgrenzen(string typ_fahrstrasse, string stellung, int minlevel, int maxlevel, optional string msgMinlevel, optional string msgMaxlevel); (Details)
- int verschliesse(string typ_fahrstrasse, int levelsoll, int levelmin, optional out string fehlernachricht); (Details)
- int pruefe(string typ_fahrstrasse, int level, optional out string fehlernachricht); (Details)
- void stelle(string typ_fahrstrasse, int levelsoll, int levelmin); (Details)
- Ruft auf: (Details)
- on_%Name der Verschlusselementvarriable%_%Name der Schubstange%_verschlussstangechanged(int level);
- on_%Name der Verschlusselementvarriable%_%Name der Schubstange%_%Nummer des Zielzustandes%_festlegungchanged(int level);
- Methoden:
- Sonnstiges
- Aufgerufene Methoden:
- void parameterUpdate(string typ,int wert); Wenn eine Option im Parametereditor verstellt wird.
- Aufgerufene Methoden:
- RingleitungParallel
- Allgemeines:
- Der Name des angelegten Objekts ist gleichzeitig der Name der Ringleitung. Alle Namen sollen mit ring_ beginnen, eine Leitung für die wgt würde daher ring_wgt heißen.
- Auf die Ringleitung kann durch jede Gruppe (auch Anschaltgruppe) zugegriffen werden, in der folgender Eintrag existiert: "RingleitungParallel ring_wgt".
- Methoden:
- void set(int wert)
- Setzt auf die Ringleitung einen Wert. Standardmäßig ist kein Wert gesetzt.
- Der Gesamtwert einer parallelen Ringleitung wird dabei nach folgendem Prinzip ermittelt:
- Es wird das Maximum der Werte aller RingleitungParallel-Objekte genommen, die einen gesetzten Wert haben.
- Existiert keine RingleitungParallel mit gesetztem Wert, wird 0 genommen.
- void clear()
- Löscht einen gesetzten Wert. Für die Berechnung des Wertes siehe Abschnitt zu set().
- int value()
- Gibt den Wert zurück, den diese Ringleitung aktuell hat. Funktioniert auch bei inaktiver Gruppe.
- void activate()
- Sorgt dafür, dass ein Ringleitungs-Objekt künftig bei Änderungen des Wertes der Ringleitung benachrichtigt wird. Standardmäßig ist die Relaisgruppe inaktiv!
- Ringleitungs-Objekte sollten im Grundzustand inaktiv sein und sich nur kurzzeitig (z.B. nach Drücken der WT) aktivieren, da die Ringleitungsbearbeitung sehr rechenaufwendig ist!
- void deactivate()
- Sorgt dafür, dass ein Ringleitungs-Objekt künftig bei Änderungen des Wertes der Ringleitung nicht mehr benachrichtigt wird. Standardmäßig ist die Relaisgruppe inaktiv!
- Ruft auf:
- void _%Name der Ringleitung%(int wert);
- Wird aufgerufen, wenn Wert der Ringleitung sich geändert hat, aber nur wenn Gruppe vorher mit activate() aktiviert wurde.
- RingleitungSeriell
- Allgemeines:
- Der Name des angelegten Objekts ist gleichzeitig der Name der Ringleitung. Alle Namen sollen mit ring_ beginnen, eine Leitung für die wgt würde daher ring_wgt heißen.
- Auf die Ringleitung kann durch jede Gruppe (auch Anschaltgruppe) zugegriffen werden, in der folgender Eintrag existiert: "RingleitungSeriell ring_wgt".
- Achtung: Serielle Ringleitungen benötigen immer genau eine Anschaltgruppe, die ebenfalls auf diese Ringleitung zugreift. Dies ist notwendig, da mehr oder keine Anschaltgruppe zu undefinierten Ergebnissen führen können.
- Methoden:
- void set(int wert)
- Setzt auf die Ringleitung einen Wert. Standardmäßig ist Wert 0 gesetzt.
- Bei seriellen Ringleitungen wird der Wert jeder aktiven Gruppe der darauf folgenden aktiven Gruppe übergeben. Die Gruppen sind dabei ringförmig angeordnet. Dies wird von der Weichenlaufkette verwendet - ein Element ist hier die Anschaltgruppe, das durch die innere Programmierung für die Unterbrechung des Rings sorgt.
- int value()
- Gibt den Wert zurück, den diese Ringleitung aktuell hat. Funktioniert auch bei inaktiver Gruppe.
- void activate()
- Sorgt dafür, dass ein Ringleitungs-Objekt in die serielle Ringleitung eingeklinkt wird, d.h. die Ringleitung wird an dieser Stelle unterbrochen, und der mit set gesetzte Wert wird übernommen, genauso wird aber die Gruppe auch bei eingehenden Wertänderungen benachrichtigt. Standardmäßig ist die Relaisgruppe inaktiv!
- Ringleitungs-Objekte sollten im Grundzustand inaktiv sein und sich nur kurzzeitig (z.B. nach Drücken der WT) aktivieren, da die Ringleitungsbearbeitung sehr rechenaufwendig ist!
- void deactivate()
- Sorgt dafür, dass ein Ringleitungs-Objekt künftig bei Änderungen des Wertes der Ringleitung nicht mehr benachrichtigt wird. Standardmäßig ist die Relaisgruppe inaktiv!
- Ruft auf:
- void _%Name der Ringleitung%(int wert);
- Wird aufgerufen, wenn Wert der Ringleitung sich geändert hat, aber nur wenn Gruppe vorher mit activate() aktiviert wurde.