User Tools

Site Tools


doc:lua:start

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
doc:lua:start [2011/06/05 10:10] admindoc:lua:start [2013/12/29 16:14] admin
Line 1: Line 1:
-====== Make your own Lua Scripts ====== +====== Make your own OOBD Scripts ====== 
- FIXME under construction+ 
 + 
 +The "reloadable intelligence" of OOBD is realized as Lua script. What this means and how this works, is described here.
  
  
Line 25: Line 27:
  
 In the moment the OOBD interface supports two kinds of interfaces for Lua: Some for creating the menus, and some to talk to the serial line (( this is certainly subject to change in the future, when OOBD becomes more generic and the data links become more abstract)) In the moment the OOBD interface supports two kinds of interfaces for Lua: Some for creating the menus, and some to talk to the serial line (( this is certainly subject to change in the future, when OOBD becomes more generic and the data links become more abstract))
 +
 +
 +**Important** To allow it during debugging to replace the hardcoded extended Lua functions against some own debugging code, normally the hardcoded functions are assigned to some Lua variables first, which then are used in the later script:
 +
 +  local serFlush =serFlushCall
 +  serflush()
 +  
 +  
 +So by naming convention the hardcoded extended functions ends with xxx"Call", while the name used later is without "Call"
 +
 +Please keep this in mind while reading this document or writing own code.
  
  
Line 81: Line 94:
 return return
 </code> </code>
 +
 +
 (BTW: Here you also see the start() function in action) (BTW: Here you also see the start() function in action)
  
Line 92: Line 107:
 === addElement(Description, function, initialValue, Flagset, id) === === addElement(Description, function, initialValue, Flagset, id) ===
  
 +This call adds a single element to the list. For now these function has the following parameters
 +
 +  * Description(String): This is what appears as description on this menu item
 +  * function: Each menu is assigned to a Lua function, where one function can be shared between several menu items. The name of this function is given here (please take care about correct upper/lower characters)
 +  * initialValue(String): This is what is shown as initial value when the menu is displayed the first time.
 +  * Flagset(Integer): This is an integer value, where each bit represents a flag. The meanings of these flags are explained in the [[:dev:clientdesignguide|Client design guide]] (look for System Flags)
 +  * id(String): The id is used to add an individual marker to a menu item. This is widely used when one single Lua function should support many menu items. This is descripted in detail in the [[#the_menu_function_call|Menu Function Calls]] below.
 +
 +=== "advanced" addElement(Description, function, initialValue, Flagset, id, type) === 
 +
 +
 +
 +
 +
 +=== pageDone() ===
 +
 +The pageDone() function is easy, it just tells OOBD that the menu is defined now and ready to be shown.
 +
 +The final result looks than similar like this (you'll noticed that the script has slightly changed after the screenshot has been made)
 +
 +{{:pics:oobdme-window.png|}}
 +
 +
 +==== The Menu Function Call ====
 +
 +As shown above, we've now set up the menu items - but now we want something happen when the user selects a menu item, won't we?
 +
 +
 +So let's assume the user selects an item. What happens now?
 +  - OOBD looks, which Lua function is assigned to that menu item
 +  - than that Lua function is called, with two parameters:
 +    * the actual displayed value of that item
 +    * and the id with we gave to that menu item during initialization
 +  - than the called Lua function does something, e.g. a calculation or it starts to generate another submenu
 +  - when the function is finished, it returns a string value
 +  - that string value is then displayed as new value of the menu item
 +
 +That's already all, that does the job :-)
 +
 +
 +==== The Communication  Commands ====
 +
 +OOBD uses (actual) serial communication to talk to the diagnostic device. To allow Lua to send and receive data from the serial port, a few extended Lua functions exists:
 +
 +=== serFlush() ===
 +
 +It just clears the input buffer (from anything which was maybe received in the meantime and which is not needed anymore)
 +
 +
 +=== serWrite(String) ===
 +
 +Sends //String// to the output (which is normally the serial port)
 +
 +
 +=== serSleep(milliseconds) ===
 +
 +waits //milliseconds//
 +
 +=== serReadLn(msTimeout) ===
 +
 +reads from input until a LF (dez. 10 hex 0x0A) appears and returns that input as String
 +
 +=== serWait(OptionString, msTimeout) ===
 +
 +In case you want to wait for some input strings, of which several could appear, you fill the //Optionstring// with string1|string2|..|stringN. If then one of this string appears at the input, the index of the found string is returned (first string=1). If the string does not appear within //msTimeout//, the function returns 0.
 +
 +
 +====  Miscellaneous  Commands ====
 +
 +=== serDisplayWrite(String) ===
 +
 +
 +Writes //String// to the build in output console.
 +
 +=== dbLookup(db-File , searchstring) ===
 +
 +Searches in the //db-file// for all entries with index //searchstring//. The //db-file// needs to be in the same directory as the Lua- script itself. The //db-file// itself is made by [[doc:oodbcreate|oodbCreate]].
 +
 +dbLookup() returns a Lua table
 +  
 +  myTable = dbLookup("dtc.oodb", "0815")
 +
 +//myTable.len// tells the success status:
 +  * if //myTable.len// < 0 then an error has occured
 +  * if //myTable.len// = 0 then //searchstring// has not been found
 +  * if //myTable.len// > 0 then //myTable.len// tells the number of entries found
 +
 +When something has been found, than //myTable// contains two sections, //header// and //data//.
 +
 +The header section is needed in case you don't know in which column your wanted result is stored; you can identify the column by its column header name instead:
 +
 +   col= myTable.header["DTC-Text"]
 +   print (col)
 +   2
 +   
 + //myTable.header.size// tells the number of colums in total **without** the first index column, which is always surpressed.
 +
 +
 +The //data// section then contains the found data itself, arranged as a two dimensional array, sorted by rows and columns. 
 +
 +    result=myTable.data[row][column]
 +  
 +**ATTENTION**: Although the row and column indexes are expressed as numbers (1,2,3,4..), they are internally represented as string values ("1","2","3","4"...), so to read the result correctly, numeric row and column counters need to be converted to strings first to address the array correctly
 +
 +    column=3
 +    row=2
 +    result=myTable.data[tostring(row)][tostring(column)])
 +    
 +    
 + Here after all a piece of sample code
 +
 +<code lua>
 +myTable= dbLookupCall("dtc.oodb","005")
 +
 +print ("header")
 +for k,v in pairs (myTable.header) do
 +    print (k,"=",v)
 +end
 +
 +nrOfColumns = myTable.header.size
 +nrOfRows = myTable.len
 +
 +print ("Rows x Columns:" ,nrOfRows, nrOfColumns)
 +
 +
 +for row = 1 , nrOfRows , 1 do
 +  for column = 1 , nrOfColumns, 1 do 
 +  
 +   print (cy, cx, myTable.data[tostring(row)][tostring(column)])
 +  end
 +end
 +</code>
 +
 +===== Some Programming Tricks =====
 +
 +Coming from old fashioned programming languages, you might be used to simple and static variable types like numbers and Strings. But Lua offers much more comfort here, especially with the support of nested (associative) Arrays. With that some things can be realized quite easy.
 +
 +Let's assume a common scenario: You want to use a number of menu items, which basically do all the same (getting a value from a vehice) just with different parameters. 
 +
 +In former days you had to write one function for each single value and a long list of menu items, but in Lua, you can store all parameters, their meanings and even the function reference to get them in a single array like
 +
 +<code>
 +local Menu2Data = {
 +id0x0815 = { byte = 1 , size =  1 , mult = 0.392156862745 , offset = 0, unit = " %", title="Part Number", call = "readAscPid"} ,
 +id0x4711 = { byte = 1 , size =  1 , mult = 0.392156862745 , offset = 0, unit = " %", title="Software Level", call = "readAscPid"} ,
 +-- ... here are all the other parameter settings
 +
 +}
 +</code>
 +
 +then, during your menu initialisation, you can let Lua run though the array and building the menu out of it
 +
 +<code lua>
 + openPage("MyMenu")
 + for key,value in pairs(Menu2Data) do
 + res=_G[value.call]("-",key) --nice trick to call a function just by name :-)
 + addElement(value.title, value.call,res,0x1, key)
 + end
 + pageDone()
 +
 +</code>
 +
 +And again: That's it
 +
 +When than later on a function is called by its menu item, it gets the hash key of the Menu2Data array as its "id" parameter, so the function can then read out its personal parameter set out of the Menu2Data Array to calculate the correct values.
 +
 +Please also note the use of the _G array in the sample above: Lua stores also all functions into its global _G array, where they can be refenced by their name and used as a normal function. So the ''res=_G[value.call]("-",key)'' call does the following:
 +  - it finds a function by its name
 +  - then it calls these function as if the user would do it
 +  - it saves the actual return value (which represents e.g. the actual measuring data) in res
 +  - res is then be used as initial displayed value when setting up the menu
  
 +By that it's possible without big efforts to fill a menu  with real data already during initialization, so the actual data is visible straight from the beginning.