de:doc:lua:start
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
de:doc:lua:start [2013/11/24 20:20] – wsauer | de:doc:lua:start [2014/03/29 01:00] (current) – removed admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Erstelle Deine eigenen OOBD Skripte ====== | ||
- | Die " | ||
- | |||
- | |||
- | ===== Was ist Lua? ===== | ||
- | |||
- | Einfach gesagt ist [[http:// | ||
- | |||
- | Das ermöglicht es ein Programm zu erstellen und das Verhalten so zu bestimmen wie es gebraucht wird. Dieses Konzept wurde in der OOBD " | ||
- | |||
- | Glücklicherweise wurde Lua ziemlich populär in den letzten Jahren und so ist es heute für alle wichtigen Plattformen verfügbar wie z.B. Desktop PC's, Smartphones und normale Mobiltelefone. | ||
- | |||
- | Es gibt eine Menge an Dokumentation über Lua im Internet, so das wir das Rad nicht noch mal neu erfinden wollen. Wir werden uns darauf konzentrieren, | ||
- | |||
- | |||
- | ===== Die Lua - OOBD Schnittstelle ===== | ||
- | |||
- | Wenn Lua innerhalb eines anderen Programms ohne weitere Hilfestellung gestartet wird, reagiert es wie eine Black Box: Es gibt keine Verbindung vom inneren zum äußeren Programm, keinerlei Eingabemöglichkeiten und keine Rückmeldungen an das aufrufende Programm. Das ist offensichtlich nicht besonders sinnvoll. Deshalb müssen, wenn Lua in ein Programm eingebaut wird, einige Schnittstellen erstellt werden, die Lua mit dem Host kommunizieren lassen. | ||
- | |||
- | Aus der Sicht von Lua arbeiten diese Schnittstellen als normale Lua Funktionsaufrufe. Aber wenn eine solche Funktion aufgerufen wird, verzweigt die Ausführung des Programms in das äußere Programm, macht dort irgendwas und kehrt letztlich von dieser Funktion zurück zu Lua. | ||
- | |||
- | Im Moment unterstützt OOBD zwei Arten von Schnittstellen für Lua: Einige die Menue' | ||
- | |||
- | **Wichtig** Um während der Fehlersuche die festeingebauten erweiterten Lua Funktionen gegen selbsterstellten Kode austauschen zu können, werden normalerweise die festeingebauten Lua Funktionen zuerst einigen Lua Variablen zugewiesen. Diese werden dann später in dem Skript benutzt. | ||
- | |||
- | local serFlush =serFlushCall | ||
- | serflush() | ||
- | | ||
- | Mit dieser Benamungskonvention enden die festeingebauten erweiterten Funktionen mit xxx" | ||
- | |||
- | Bitte behalte das im Gedächtnis, | ||
- | |||
- | Aber bevor wir einen Blick in den Programmablauf werfen, müssen wir verstehen wie der Lua Compiler (Luac) arbeitet und was das für die Programminitialisierung bedeutet: | ||
- | |||
- | ==== Kompilierung und Aufstartkode ==== | ||
- | |||
- | Um Speicherplatz zu sparen und die Aufstartzeit zu reduzieren, wird der Lua Interpretierer innerhalb OOBD nicht mit dem Quellcode ,der dann erst einmal kompiliert werden muss bevor er ausgeführt werden kann, versorgt. Stattdessen wird der fertig kompilierte Lua Programmkode eingebunden. | ||
- | |||
- | Der Kompilierungsprozess funktioniert folgendermassen: | ||
- | |||
- | Der Kommandozeileneintrag sieht dann folgendermaßen aus: | ||
- | |||
- | luac -o Ausgabedateiname.lbc Quellkodename1.lua Quellkodename2.lua ... | ||
- | | ||
- | | ||
- | In dem OOBD Quellkode Sammelverzeichnis sind einige Beispiele abgelegt, die zeigen wie es gemacht wird. | ||
- | |||
- | Wenn Du nun Deinen eigenen Übersetzungsprozess beginnen möchtest, gibt es zwei Dinge die Du wissen musst, da luac ein wenig anders arbeitet als ein gewöhnlicher Kompilierer. | ||
- | |||
- | - luac beurteilt **nicht** einige require() oder doFile() statements, sodaß diese Dateien nicht in der Ausgabedatei wiedergefunden werden können. Alle benötigten Dateien müssen stattdessen als Eingabedateien eingebunden werden, um in der Ausgabedatei enthalten zu sein. | ||
- | - Auch die Reihenfolge der Eingabedateien ist wichtig: Luac bindet diese Dateien zusammen, in der Reihenfolge in der sie angefügt werden. In dieser Reihenfolge werden sie später auch ausgeführt. Hierbei musst Du darauf achten, das Variablen und Funktionen deklariert werden müssen **bevor** sie das erste Mal benutzt werden. Wenn das nicht passiert, bekommst Du eine Schutzverletzung. | ||
- | |||
- | Wegen des zweiten genannten Punktes, sollte die Lua Funktion die die kompletten Lua Strukturen initialisiert, | ||
- | |||
- | === Das Start("","" | ||
- | |||
- | Um der OOBD Anwendung die Möglichkeit zu geben, neu initialisiert zu werden (wie z.B nach einem Verbindungsabbruch), | ||
- | wird der Name einer solchen Initialisierungsfunktion mit **Start("","" | ||
- | | ||
- | ==== Die Menu Kommando' | ||
- | OOBD benutzt nur drei Funktionen um die Menue Strukturen zu realisieren. Deshalb lass uns zuerst einen Blick in einen Beispielkode werfen: | ||
- | |||
- | <code lua> | ||
- | function Start(oldvalue, | ||
- | identifyOOBDInterface() | ||
- | setSendID(" | ||
- | openPage(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | addElement(" | ||
- | pageDone() | ||
- | return oldvalue | ||
- | end | ||
- | |||
- | |||
- | ----------------- Setzen der Startbedingungen -------------- | ||
- | |||
- | Start("","" | ||
- | return | ||
- | </ | ||
- | |||
- | |||
- | (Nebenbei gesagt: Hier siehst Du die start() Funktion in der Ausführung) | ||
- | |||
- | Also was finden wir hier? Zuerst haben wir den Aufruf der Funktion | ||
- | === openPage(" | ||
- | |||
- | Diese Funktion teilt OOBD mit, das ein neues Menue erstellt werden soll. Der //Title// wird benutzt, welch Überraschung, | ||
- | |||
- | Dann wird das Menü aufgebaut mit | ||
- | |||
- | === addElement(Description, | ||
- | |||
- | Dieser Funktionsaufruf fügt ein einzelnes Element zu der Liste hinzu. Diese Funktion hat die folgenden Parameter | ||
- | |||
- | * Description(String): | ||
- | * function: Jedes Menü ist einer Lua Funktion zugewiesen, wobei eine Funktion auf die diversen Menüeinträge aufgeteilt wird. Der Name dieser Funktion wird hier festgelegt ( Bitte achte auf die korrekte Groß- und Kleinschreibweise der Buchstaben ) | ||
- | * initialValue(String): | ||
- | * Flagset(Integer): | ||
- | * id(String): Diese id wird benutzt, um einen individuellen Marker an einen Menüeintrag zu binden. Dies ist weit verbreitet, wenn eine einzige Lua Funktion viele Menüoptionen unterstützen sollte. Es wird im Detail beschrieben in den [[# | ||
- | |||
- | === pageDone() === | ||
- | |||
- | Die pageDone() Funktion ist einfach, denn es teilt OOBD mit, daß das Menü nun komplett definiert und bereit zur Anzeige ist. | ||
- | |||
- | Das entgültige Ergebnis sieht dann ähnlich wie dieses aus. (Du wirst feststellen, | ||
- | |||
- | {{: | ||
- | |||
- | |||
- | ==== Das Menü Funktionsaufruf ==== | ||
- | |||
- | Wie oben gezeigt, haben wir nun die Menü Einträge aufgesetzt - aber nun wollen wir das etwas passiert, wenn der Benutzer einen Menue Eintrag auswählt, nicht wahr? | ||
- | |||
- | |||
- | Lasst uns also annehmen, das ein Benutzer einen Eintrag auswählt. Was passiert jetzt? | ||
- | - OOBD schaut nach, welche Lua Funktion mit diesem Menüeintrag verbunden ist | ||
- | - dann wird diese Lua Funktion mit diesen beiden Parametern aufgerufen: | ||
- | * der aktuell dargestellte Wert dieses Eintrags | ||
- | * und die id, welche wir dem Menüeintrag gaben, während der Initialisierung | ||
- | - dann macht die aufgerufene Lua Funktion etwas z.B. eine Berechnung oder sie startet die Erstellung eines weiteren Untermenüs | ||
- | - wenn die Funktion abgearbeitet ist, gibt sie eine Zeichenfolge zurück | ||
- | - Diese Zeichenfolge wird dann als neuer Wert dieses Menüeintrags dargestellt | ||
- | |||
- | Das ist erstmal alles, und es erfüllt den Zweck :-) | ||
- | |||
- | |||
- | ==== Die Kommunikation Kommandos ==== | ||
- | |||
- | OOBD benutzt gegenwärtig eine serielle Kommunikation, | ||
- | |||
- | === serFlush() === | ||
- | |||
- | Diese Funktion leert den Eingabespeicher (Von allem das, was möglicherweise in der Zwischenzeit empfangen wurde und nicht mehr benötigt wird) | ||
- | |||
- | === serWrite(String) === | ||
- | |||
- | Diese Funktion sendet einen //String// zum Ausgabespeicher (Das ist normalerweise der serielle Port) | ||
- | |||
- | === serSleep(milliseconds) === | ||
- | |||
- | Wartet // | ||
- | |||
- | === serReadLn(msTimeout) === | ||
- | |||
- | Liest von der Eingabe bis ein Zeilenvorschub (dez. 10 hex 0x0A) auftaucht und gibt Diese als Zeichenfolge zurück. | ||
- | |||
- | === serWait(OptionString, | ||
- | |||
- | Falls Du auf mehrere Zeichenfolgen wartest, von denen einige auftreten könnten, füllst Du den // | ||
- | |||
- | |||
- | ==== Sonstige Kommandos ==== | ||
- | |||
- | === serDisplayWrite(String) === | ||
- | |||
- | |||
- | Schreibt eine //String// Zeichenfolge zu dem was schon in der Ausgabe steht. | ||
- | |||
- | === dbLookup(db-File , searchstring) === | ||
- | |||
- | Sucht in der //db-file// Datenbank nach allen Einträgen mit dem Index // | ||
- | |||
- | dbLookup() gibt eine Lua Tabelle zurück | ||
- | | ||
- | myTable = dbLookup(" | ||
- | |||
- | // | ||
- | * if // | ||
- | * if // | ||
- | * if // | ||
- | |||
- | Wenn etwas gefunden wurde, enthält //myTable// zwei Bereiche, //header// Kopfzeile und //data// Daten. | ||
- | |||
- | Der " | ||
- | |||
- | col= myTable.header[" | ||
- | print (col) | ||
- | 2 | ||
- | |||
- | // | ||
- | |||
- | Der //data// Daten Bereich enthält dann die gefundenen Daten, aufgebaut in einem zweidimensionalen Feld, sortiert nach Zeilen und Spalten. | ||
- | result=myTable.data[row][column] | ||
- | |||
- | **Achtung**: | ||
- | |||
- | column=3 | ||
- | row=2 | ||
- | result=myTable.data[tostring(row)][tostring(column)]) | ||
- | | ||
- | |||
- | Nach all den theoretischen Informationen ein kleines Stück Beispielkode: | ||
- | |||
- | <code lua> | ||
- | myTable= dbLookupCall(" | ||
- | |||
- | print (" | ||
- | for k,v in pairs (myTable.header) do | ||
- | print (k," | ||
- | end | ||
- | |||
- | nrOfColumns = myTable.header.size | ||
- | nrOfRows = myTable.len | ||
- | |||
- | print ("Rows x Columns:" | ||
- | |||
- | |||
- | for row = 1 , nrOfRows , 1 do | ||
- | for column = 1 , nrOfColumns, | ||
- | | ||
- | print (cy, cx, myTable.data[tostring(row)][tostring(column)]) | ||
- | end | ||
- | end | ||
- | </ | ||
- | |||
- | ===== Ein paar Programmiertricks ===== | ||
- | |||
- | Wenn Du Kenntnisse aus den althergebrachten Programmiersprachen mitbringst, wirst Du wahrscheinlich einfache und statische Variablentypen verwenden, wie Zahlen und Zeichenfolgen. Aber Lua offeriert hier mehr Komfort, besonders mit der Hilfestellung von geschachtelten (assoziativen) Feldern. Mit diesen können einige Dinge sehr viel einfacher realisiert werden. | ||
- | |||
- | Wir wollen uns ein häufiges Szenario vorstellen: Du möchtest eine Anzahl von Menüeinträgen verwenden, welche alle das Gleiche tun, Einen Wert von einem Fahrzeug erhalten, nur mit verschiedenen Parametern. | ||
- | |||
- | In der Vergangenheit musstest Du eine Funktion für jeden einzelnen Wert und einen lange Liste von Menüeinträgen schreiben. Aber in Lua kannst Du alle Parameter, deren Bedeutungen und auch eine Funktionsreferenz, | ||
- | |||
- | < | ||
- | local Menu2Data = { | ||
- | id0x0815 = { byte = 1 , size = 1 , mult = 0.392156862745 , offset = 0, unit = " | ||
- | id0x4711 = { byte = 1 , size = 1 , mult = 0.392156862745 , offset = 0, unit = " | ||
- | -- ... here are all the other parameter settings | ||
- | |||
- | } | ||
- | </ | ||
- | |||
- | Dann, während Deiner Menü Initialisierung, | ||
- | |||
- | <code lua> | ||
- | openPage(" | ||
- | for key,value in pairs(Menu2Data) do | ||
- | res=_G[value.call](" | ||
- | addElement(value.title, | ||
- | end | ||
- | pageDone() | ||
- | |||
- | </ | ||
- | |||
- | Und wieder einmal kann man sagen: Das war's. | ||
- | |||
- | Wenn dann später eine Funktion aufgerufen wird, durch seinen Menü Eintrag, bekommt es einen Hash Key aus dem Menu2Data Feld als dessen id Parameter. Damit kann die Funktion, dann Ihre eigenen Parametersätze aus dem Menu2Data Feld auslesen um die korrekten Werte auszurechnen. | ||
- | |||
- | Bitte beachte den Gebrauch des _G array Feldes in dem obigen Beispiel: Lua speichert alle Funktionen in sein globales _G array Feld, wo sie dann referenziert über Ihren Namen, als normale Funktion benutzt werden können. So macht der '' | ||
- | |||
- | - es findet eine Funktion mit Hilfe seines Namens | ||
- | - dann ruft es diese Funktion auf, wie auch der Nutzer es tun würde | ||
- | - es speichert den aktuellen Rückgabewert ( welcher die aktuellen Messdaten repräsentiert ) in res | ||
- | - res wird dann wie der initial dargestellte Wert, als das Menü konfiguriert wurde, benutzt | ||
- | |||
- | Durch diese Vorgehensweise ist es möglich, ohne großen Aufwand ein Menü mit den reellen Daten während der Initialisierung zu füllen. So sind die aktuellen Daten von Anfang an direkt sichtbar. |
de/doc/lua/start.1385320851.txt.gz · Last modified: 2013/11/24 20:20 by wsauer