Tutorial:Erstellen neuer Relaisgruppen - Skripte erstellen: Unterschied zwischen den Versionen

Aus StellSi-Hilfewiki
Zur Navigation springen Zur Suche springen
(Auslagerung nach Tutorial:Namen von Klassen)
 
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt)
Zeile 162: Zeile 162:


Für eine ausführlichere Anleitung sei auf die entsprechende Fachliteratur verwiesen.
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.
** Wenn ein Wert hereinkommt, während connectionState auf CONNECTION_STATE_(DIS)CONNECTING steht, ist das ein Hinweis darauf, dass diese Werte im Rahmen des Verbindungsauf-/abbaus zu Stande kommen. In allen anderen Fällen ist der empfangene Wert Folge des Regelbetriebs. In der Regel sind diese Werte nur für Spezialfälle interessant. Im Bestand ist das z.B. der Fall, dass Hebel umgestellt werden, wenn man ihnen eine Weiche verbindet, die anderst herum steht als der Hebel.
* enum SpeedBinding; Gibt an, an welchen Zeitraffer der Timer gebunden werden soll
** const int Speed_None; Zeitrafferunabhängige Zeitmessung. Sollte nur verwendet werden, wenn eine Interaktion mit Sounds unbedingt erforderlich ist.
** 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 und Weichen abhängig ist verwendet werden (z.B. Weichenwecker).
** const int Speed_Bewegung; Bindung an den Bewegungs-Zeitraffer. Sollte für alles, was Zzgabhä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.
* Weitere Konstanten der Außenanlage gemäß [[Tutorial:Ansteuerung von Außenanlagen-Komponenten#Weichen und Riegel]]


== Datentypen ==
== Datentypen ==
* '''bool''' Warheitswert, true oder false
Siehe [[Tutorial:Namen von Klassen]]
* '''int''' Ganzzahl, vorzeichenbehaftet, 32 Bit. Weitere Ganzzahltypen sind int8, int16, int64, uint8, uint16, uint, uint64
* '''float''' Gleitkommazahl vorzeichenbehaftet. Weitere Gleitkommazahl ist double.
* '''string''' Zeichenfolge.
** Operatoren:
*** [string] + [string]; Kombiniert zwei Zeichenfolgen.
** Methoden:
*** string arg(string arg); Ersetzt die Zeichenfolge %1 im String durch den angegebenen Text, und die Zeichenfolge %2 durch %1 usw.
*** string arg(int arg);
*** string arg(float arg);
*** string layOver(string destination, optional bool alignLeft = false, optional int cutOverflow = -1, optional bool out cutRequired = false); Legt den akutellen String über den angegebenen String. Ist der aktuelle String kleiner als der angegebene String wird er rechtsbündig (Standard) oder linksbündig (Optional) ausgerichtet. Ist er größer als der angegebene String wird er Links (-1, Standard), Rechts (+1, optional) oder nicht (0, optional) abgeschnitten. Ein optionaler bool-Wert gibt true zurück, wenn der String abgeschnitten werden musste oder müsste, sonst false.
*** List<string> split(string sperator); Teilt die Zeichenfolge an jedem Vorkommen von sperator auf und speichert die Teilbereiche in einer Liste. Wenn seperator ein leerer String ist, wird hinter jedem Zeichen gesplittet. Der Text kann über die Join-Methode vollständig wieder hergestellt werden. Die Liste hat garantiert mindestens einen Eintrag.
** Verwandte globale Methoden:
*** void parseIntFromString(string source, int out ergebnis, optional bool out success = false); Wandelt den angegebenen Text in eine Zahl um. War die Umwandlung nicht erfolgreich, wird 0 ausgegeben.
*** string joinList(List<string>, string seperator); Vereinigt die angegebene Liste in dem zwischen jedem Eintrag seperator eingefügt wird. Umkehrfunktion zu string.split
** Funktionsdefinitionen, die derzeit als undokumentierte Technologiedemo gelten
*** funcdef void DataBoolChangedMethod(bool newData);
*** funcdef void DataIntChangedMethod(int newData);
*** funcdef void DataStringChangedMethod(string newData);
** Erweiterte Eigenschaften:
*** bool hasDigitCharacter (readonly); Enthält ein Zeichen der Unicode-Klasse "DecimalDigit"
*** bool hasLetterCharacter (readonly); ..Buchstaben (egal ob klein, groß oder Überschrift)
*** bool hasLowerCharacter (readonly); ..Kleinbuchstabe
*** bool hasMarkCharacter (readonly);
*** bool hasNonCharacter (readonly); ..Unicode-Gruppe für interne Verwendung in Programmen
*** bool hasNullCharacter (readonly); ..Null-Zeichen
*** bool hasNumberCharacter (readonly);  Geht über "DecimalDigit" hinaus (mehr als 0-9)
*** bool hasPrintCharacter (readonly); ..Druckbares Zeichen
*** bool hasPunctCharacter (readonly);
*** bool hasSpaceCharacter (readonly); ..Leerzeichenoiden (nicht nur Leerzeichen, sondern auch z.B. "\t", "\n", "\v", "\f" und "\r")
*** bool hasSymbolCharacter (readonly);
*** bool hasTitleCharacter (readonly); ..Buchstabe für Titel
*** bool hasUpperCharacter (readonly); ..Großbuchstabe
*** Zu allen: siehe zugehörige Member in der QT-Dokumentation von QChar.
** Erweiterte Methoden:
*** string toCaseFolded(); ..für die meisten Zeichen das selbe wie toLower
*** string toLowerCase();
*** string toTitleCase();
*** string toUpperCase();
*** Zu allen: siehe zugehörige Member in der QT-Dokumentation von QChar bzw. QString.
*** string toSimplified(); Löscht alle Leerzeichenoiden am Start und Ende und ersetzt alle mehrfachen Leerzeichenoiden durch ein echtes Leerzeichen.
*** string toTrimmed(); Löscht alle Leerzeichenoiden am Start und Ende.
*** int compareLocalized(string); Vergleicht die Zeichenfolge (<0: Kleiner, =0: Gleich, >0: Größer) mit der angegebenen, ..unter Berücksichtigung der Systemabhängigen Spracheinstellung
*** int compareCaseSensitive(string); ..unter Berüchksichtigung der Groß/Kleinschreibung
*** int compareInsensitive(string); ..ohne Groß/Kleinschreibung zu berücksichtigen
* '''List<T>''' Stellt eine Liste dar.
** Allgemeine Hinweise:
*** Der Typ der Einträge ist beliebig, die Liste kann also als List<string>, List<int> oder jeden anderen Typs verwendet werden.
*** Die Liste verhält sich ähnlich wie QT-Listen: Wenn man Liste1 = Liste2; macht und dann Liste1 ändert, hat dies keine Auswirkungne auf Liste2.
*** Die Implentierung kann unter Umständen noch Fehler enthalten.
** Methoden:
*** int count(); Gibt die Anzahl der Einträge aus.
*** bool isEmpty(); Gibt an, ob die Liste leer ist.
*** void append(T neuerEintrag); Fügt an letzter Stelle einen neuen Eintrag ein.
*** void insert(int loc, T neuerEintrag); Fügt an angegebener Stelle einen neuen Eintrag ein. (Bei zu großen Zahlen wird an letzter Stelle eingefügt. => Muss noch Getestet werden.)
*** T removeAt(int loc); Entfernt den Eintrag aus der angegebenen Stelle und gibt ihn zurück. Bei zu großen Zahlen wird eine Ausnahme ausgelöst, vor Benutzung also count oder isEmpty prüfen!
*** T replace(int loc, T neuerEintrag); Ersetzt den Eintrag an der angegebenen Stelle und gibt den bisherigen Eintrag zurück. Bei zu großen Zahlen wird eine Ausnahme ausgelöst, vor Benutzung also count oder isEmpty prüfen!
*** T at(int loc); Gibt den Eintrag an der angegebenen Stelle zurück. Bei zu großen Zahlen wird eine Ausnahme ausgelöst, vor Benutzung also count oder isEmpty prüfen!
*** void clear(); Entfernt alle Einträge aus der Liste.
* '''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 sendSignalSynchron(string signalname, string wert); Geht an '''eine''' Schnitstelle und gibt den Wert zurück, den diese Schnittstelle zurückgibt.
*** int sendSignalSynchron(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 des Signals darf _ enthalten, Name der Schnittstellenvarriable nicht).
*** 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 Eingangssignale der freien Eingangslogiken.
*** Freie Ausgangslogiken funktionieren als Schnittstelle, die den Namen hat, den die freie Ausgangslogik in ihrem XML-Attribut hat. Schnittstellen, die als freie Ausgangslogik fungieren, ignorieren den ''signalname'';
*** 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, die derzeit als undokumentierte Technologiedemo gelten: (sie können sich ändern und wieder entfallen)
*** void registerSetWertCallback(string signalname, DataIntChangedMethod@ delegateMethod); Die alten Methoden bleiben jewails erhalten. Die Reihenfolge des Methodenaufrufes, wenn mehrere Methoden registriert sind, ist nicht definiert. Hinweis: Die alte on-Syntax bleibt erhalten und sollte (wenn sinnvoll) vorangig verwendet werden. Die on-Methoden gelten sowohl für Ereignisse als auch für SetWert.
*** void registerSetWertCallback(string signalname, DataStringChangedMethod@ delegateMethod);
*** void registerEreignisCallback(string signalname, DataIntChangedMethod@ delegateMethod);
*** void registerEreignisCallback(string signalname, DataStringChangedMethod@ delegateMethod);
*** void registerUnknownSetWertReceivedMethod(DataStringChangedMethod@ delegateMethod); Wird aufgerufen, wenn ein SetWert empfangen wurde, zu dessen Leitungsname keine Methode (egal ob setWert oder Ereignis oder string oder int) registriert ist. Nach dem Ausführen dieser Methode wird erneut nach passenden Methoden gesucht und diese ggf. ausgeführt. Wurden Methoden für diesen Leitungsnamen registriert, passen diese aber nicht zu den Eigenschaften (setWert/Ereignis int/string) wird diese Methode nicht aufgerufen.
*** void registerUnknownEreignisReceivedMethod(DataStringChangedMethod@ delegateMethod);
*** string getRecentStringWert(const string signal) und string get_recentStringWert(const string signal);
*** int getRecentIntWert(const string signal) und int get_recentIntWert(const string signal);
*** bool getRecentBlinkWert(const string signal) und bool get_get_recentBlinkWert(const string signal);
* '''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 on_%Name der Timervarriable%(int wert);
** Methoden, die derzeit als undokumentierte Technologiedemo gelten: (sie können sich ändern und wieder entfallen)
*** DataIntChangedMethod@ replaceNotifyerDelegate(DataIntChangedMethod@ newDelegate); Rückgabewert: Die bisherige Delegate. Kann auch null sein.
*** void initFromInitedTimer(Timer@ vorlage); Timer müssen, damit sie initialisiert sind, derzeit in der Hauptklasse stehen und eine on-Methode haben, auch wenn diese ggf. später ersetzt wird. Timer, die zwar in der Hauptklasse sind, aber keine Methode haben, lösen eine Kompilierwarnung aus. Alle anderen Timer (die sich in Hilfsklassen befinden) können mit dieser Methode hilfsweise initialisiert werden.
* '''VerschlussFahrstrasse''' ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#Klasse VerschlussFahrstrasse|Details]])
** Methoden:
*** int verschliesse(string typ_fahrstrasse, int levelsoll, int levelmin, optional out string fehlernachricht); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#verschliesse|Details]])
*** int pruefe(string typ_fahrstrasse, int level, optional out string fehlernachricht); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#pruefe|Details]])
*** void stelle(string typ_fahrstrasse, int levelsoll, int levelmin); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#stelle|Details]])
** Ruft auf: ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#Ereignisse|Details]])
*** void on_%Name der Verschlussfahrstrassenvarriable%_%Name der Schubstange%_verschlussstangechanged(int level);
*** void on_%Name der Verschlussfahrstrassenvarriable%_%Name der Schubstange%_%Nummer des Zielzustandes%_festlegungchanged(int level);
* '''VerschlussElement''' ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#Klasse VerschlussElement|Details]])
** Methoden:
*** void setLevelgrenzen(string typ_fahrstrasse, string stellung, int minlevel, int maxlevel, optional string msgMinlevel, optional string msgMaxlevel); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#setLevelgrenzen|Details]])
*** int verschliesse(string typ_fahrstrasse, int levelsoll, int levelmin, optional out string fehlernachricht); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#verschliesse|Details]])
*** int pruefe(string typ_fahrstrasse, int level, optional out string fehlernachricht); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#pruefe|Details]])
*** void stelle(string typ_fahrstrasse, int levelsoll, int levelmin); ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#stelle|Details]])
** Ruft auf: ([[Tutorial:Erstellen neuer Relaisgruppen - Verschlussregister#Ereignisse|Details]])
*** void on_%Name der Verschlusselementvarriable%_%Name der Schubstange%_verschlussstangechanged(int level);
*** void on_%Name der Verschlusselementvarriable%_%Name der Schubstange%_%Nummer des Zielzustandes%_festlegungchanged(int level);
* '''Ringleitungen'''
** Allgemeine Hinweise:
*: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.
*:Jede Ringleitung kann einen Wert abrufen und einen Wert setzten. Der Wert, der abgerufen wird, berechnet sich je nach Art der Ringleitung aus verschiedenen Techniken. Dabei werden alle Ringleitungen aller Relaisgruppen der selben Relaisanlage zur Hilfe genommen, die den selben Namen und den selben Typ haben. Eine Ringleitung kann auch ihren Wert löschen, so dass sie keinen Wert hat und bei der Berechnung ignoriert wird (Standard bei Programmstart).
*:Eine Gruppe kann über die Änderung des abzurufenden Wertes informiert werden, wenn sie sich aktiviert. Beim Programmstart sind Ringleitungen inaktiv / passiv.
*:Ringleitungs-Objekte sollten im Grundzustand inaktiv sein und sich nur kurzzeitig (z.B. nach Drücken der WT) aktivieren, da die Ringleitungsbearbeitung je nach Art der Ringleitung Rechenaufwand bedeuten kann!
** '''RingleitungParallel'''
*:Auf die Ringleitung kann durch jede Gruppe (auch Anschaltgruppe) zugegriffen werden, in der folgender Eintrag existiert: "RingleitungParallel ring_beispiel".
*:Der Wert der Ringleitung ist das Maximum der Werte aller Gruppen, die einen Wert gesetzt haben. Hat keine Gruppe einen Wert gesetzt, wird 0 angenommen.
** '''RingleitungSumme'''
*:Auf die Ringleitung kann durch jede Gruppe (auch Anschaltgruppe) zugegriffen werden, in der folgender Eintrag existiert: "RingleitungSumme ring_beispiel".
*:Der Wert der Ringleitung ist die Summe der Werte aller Gruppen, die einen Wert gesetzt haben.
** '''RingleitungSeriell'''
*:Auf die Ringleitung kann durch jede Gruppe (auch Anschaltgruppe) zugegriffen werden, in der folgender Eintrag existiert: "RingleitungSeriell ring_beispiel".
*:Die Serielle Ringleitung kann man sich wie eine Liste vorstellen. Alle Relaisgruppen und Anschaltgruppen, die diese RingleitungSeriell nutzen, haben in der Liste einen Eintrag. Am Anfang der Liste stehen alle Relaisgruppen, am Ende stehen alle Anschaltgruppen. Die Reinfolge zwischen den Relais/Anschaltgruppe kann nicht vorhergesagt werden.
*:Jede Gruppe kann mit value() den Wert herausfinden, den ihr Vorgänger in der Liste gesetzt hat. Hat er keinen Wert gesetzt (siehe clear()), dann kann man mit value() den Wert bekommen, den eben dieser Vorgänger seinerseteits durch den Aufruf von value() bekommen würde.
*:Gibt es keine Anschaltgruppen oder haben alle Anschaltgruppen keinen Wert gesetzt, bekommt die erste Gruppe den Wert 0. (offene Ringleitung)
*:Hat mindestens eine Anschaltgruppe einen Wert gesetzt, so bekommt die erste Gruppe den Wert, den die letzte Anschaltgruppe in der Liste gesetzt hat. (geschlossener Ring)
** Methoden:
*** void set(int wert); Setzt auf die Ringleitung einen Wert. Standardmäßig ist kein Wert gesetzt.
*** void clear(); Löscht einen gesetzten Wert. Für die Berechnung des Wertes siehe Allgemeine Hinweise.
*** int value(); Gibt den Wert zurück, den diese Ringleitung aktuell hat. Funktioniert auch wenn die Gruppe inaktiv ist (nicht benachrichtigt wird) oder die Gruppe keinen Wert gesetzt hat.
*** 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!
*** 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 on_%Name der Ringleitung%(int wert);
*** void on_%Name der Ringleitung%(int alterWert, int neuerWert);
**:Wird aufgerufen, wenn Wert der Ringleitung sich geändert hat, aber nur wenn Gruppe vorher mit activate() aktiviert wurde. Zum Zeitpunkt des Aufrufes gibt value() bereits den neuen Wert zurück. Die Ringleitungen werden Successive eine nach der anderen auf den Neuen Wert Umgestellt. Dabei wird die value()-Methode kurz vor dem Aufruf der Informationsmethode umgestellt. Nach dem Aufruf der Informationsmethode wird die nächste Ringleitung umgestellt. Ob Ringleitungen in anderen Klassen schon auf dem neuen oder noch auf dem alten Wert sind, kann nicht vorhergesagt werden.
** Methoden, die derzeit als undokumentierte Technologiedemo gelten: (sie können sich ändern und wieder entfallen)
*** DataIntChangedMethod@ replaceNotifyerDelegate(DataIntChangedMethod@ newDelegate); Rückgabewert: Die bisherige Delegate. Kann auch null sein.
* '''Filterleitungen'''
** Allgemeine Hinweise:
*:Eine Gruppe kann einen oder mehrere Bezeichner in der Filterleitung registrieren. Andere Gruppen können Bezeichner der Filterleitung aktivieren und deaktivieren. Die Gruppe wird informiert, ob einer ihrer Bezeichner aktiviert ist.
** Klassen:
*** FilterleitungInt: T:=int
*** FilterleitungString: T:=string
** Methoden:
*** void activate(T wert); Aktiviert alle Gruppen mit dem angegebenen Filter
*** void deactivate(T wert); Deaktiviert die angegebenen Filter
** Eigenschaften:
*** List<T> filters; Gibt an, auf welche Filter die Gruppe reagieren soll.
*** bool isActivated (readOnly); true, wenn mindestens ein Filter aktiviert wurde.
** Ruft auf:
*** void on_%Name der Filterleitung%(bool wert);
** Methoden, die derzeit als undokumentierte Technologiedemo gelten: (sie können sich ändern und wieder entfallen)
*** DataBoolChangedMethod@ replaceNotifyerDelegate(DataBoolChangedMethod@ newDelegate); Rückgabewert: Die bisherige Delegate. Kann auch null sein.
* Sonnstiges
** Aufgerufene Methoden:
*** void parameterUpdate(string typ,int wert); Wenn eine Option im Parametereditor verstellt wird.
*** void parameterUpdate(string typ,string wert);
*** void parameterUpdate(string typ,float wert);


[[Kategorie:Neue Bauform]]
[[Kategorie:Neue Bauform]]

Aktuelle Version vom 11. April 2018, 15:20 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 Anschaltgruppe eine Klasse dar. Die Schnittstellen werden über Variablen 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 Inhalt der Klasse befindet. Die Klasse endet mit einer weiteren geschweiften Klammer.

class Weiche
{
    //Inhalt der Klasse
}

Innerhalb einer Klasse werden allgemeine Variablen deklariert. Variablen 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 Variable, mit dem man sie später identifizieren kann, und gleich danach einem ; .

class Weiche
{
    Schnittstelle tischfeld;
    int anzahlIrgendetwas;
    bool tasteGedrueckt;
}

Neben den Variablen 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 Variablen 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 rechts stehende Zahlen oder Warheitswerte einer links stehenden Variable 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 Reihenfolgen der Rechnereien festgelegt. Alles was zwischen // und dem Zeilenende oder zwischen /* und */ folgt ist ein Kommentar und wird (im gesamten 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-)Variablen 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 Variablen verwendet 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 Variablen 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.

Datentypen

Siehe Tutorial:Namen von Klassen