Literally: this branch is currently not-production ready due to C++ refactoring. Please use the v1-fixes branch! Thank you.
EPICS device- and record-support for the Lua language.
- Programming device support in Lua instead of C
- Supported records: ai, ao, bi, bo, mbbi, mbbo, stringin, stringout, waveform
- Programming subroutine records in Lua instead of C
- New record: luasub
- Replacing difficult-to-mantain database record sets
- Improving flexibility of seq/calc records
- Replacing sequencer code: removing compilation phase, and no IOC-restart required for code update
- It is not another interface layer to an EPICS IOC
- It does not change the behaviour of an EPICS IOC
Add the following command in your IOC startup script file:
lisConfigure (<script directory>, <log level>, <stack size>, <treat char waveform as string>)
Arguments:
- Script directory
- Absolute directory path where the .lua files are located
- Log-level; possible values are:
- 0 = None
- 1 = Standard
- 2 = Verbose
- Stack size for Lua states
- Default if 0
- If 1, char waveform types will be treated as strings in the Lua code
- Not yet implemented!
Example:
lisConfigure ("$(TOP)/luascripts", 2, 0, 0)
Remember sure to specify the device type:
field(DTYP,"lua")
Specify the .lua file in the INP/OUT field:
field(OUT,"@strout_date.lua")
Passing parameters to the Lua support: There are 2 dedicated parameters for the Lua support:
- @id=<state id>
- Allows you to specify the state ID of where the .lua file will be loaded and the code executed (default is the filename)
- @table=<methods table>
- Allows you to specify a global table, where the support methods are to be found as fields
Passing parameters to the .lua script file:
- Everything else is passed to the global arg table
Examples:
field(OUT,"@strout_date.lua @id=mystate")
field(OUT,"@strout_date.lua @table=myrec arg1 arg2")
Lua IOC Support forwards device-support callbacks to the record's Lua state, expecting to find the following methods in the .lua file:
init_record(<rec.table>)
special_linconv(<rec.table>)
add_record(<rec.table>)
del_record(<rec.table>)
get_ioint_info(<rec.table>)
The processing callback is however different for each record type:
read_ai(<rec.table>)
write_ao(<rec.table>)
read_bi(<rec.table>)
write_bo(<rec.table>)
read_mbbi(<rec.table>)
write_mbbo(<rec.table>)
read_stringin(<rec.table>)
write_stringout(<rec.table>)
read_longin(<rec.table>)
write_longout(<rec.table>)
read_wf(<rec.table>)
The return of the above Lua methods is of course passed to the device-support.
The library also implements extended-device support (as noticed by the add_record and del_record callbacks), therefore remember that you're able to modify the INP and OUT fields in a running IOC.
In the luasub record no methods are hardwired, you specify the method names in the ICOD (record initialization) and in the PCOD (record processing) fields. Inline Lua code, instead of a method name, is also valid, as long as the ACTP field is FUNORCHK (default) or CHUNK.
Output fields are forwarded to their respective links according to the DRVO field:
- NEVER: output values are never forwarded to output links
- ON_CHANGE: output values are forwarded if changed from the Lua code
- ALWAYS: output values are always forwarded to output links
- ON_VALID: output values are forwarded if respective VLD? field is explicitly set to VALID from the Lua code
If the @table parameter is specified in the INP/OUT then the library expects the above methods as fields in the given table. Example:
myrec.init_record(<rec.table>)
<record name> <rec.table>.record_name()
<curr/prev PACT> <rec.table>.pact(¿<new PACT>?)
<curr/prev NORD> <rec.table>.nord(¿<new NORD>?)
<field value> <rec.table>.retrieve_field(<field name>)
<rec.table>.update_field(<field name>,<field value>)
<rec.table>.scan_once()
<rec.table>.process()
<rec.table>.scan_lock()
<rec.table>.scan_unlock()
<rec.table>.<field name> = <new value>
<curr.value> = <rec.table>.<field name>
Logging API, using errlogSevPrintf:
luaiocsup.ioclog(<level>,<message>)
luaiocsup.ioclog_minor(<message>)
luaiocsup.ioclog_major(<message>)
luaiocsup.ioclog_fatal(<message>)
luaiocsup.ioclog_info(<message>)
Lua records suport I/O Intr scanning. The IOSCANPVT data structure is however internal and not transferable outside of the Lua IOC Support library.
<new vs reused id> luaiocsup.scanio_init(<io_strid>)
<id found> luaiocsup.scanio_request(<io_strid>,...)
You can post soft-events:
<boolean> luaiocsup.post_event(<event number>)
Retrieving non-Lua records:
<rec.table> luaiocsup.find_record(<rec.name>)
You can check if the IOC is indeed running and register callbacks for when the IOC exits:
<boolean> luaiocsup.ioc_running()
luaiocsup.at_exit(<lua function>)
The Lua IOC Support library as been successfully tested with threads outside of the EPICS IOC world, more specifically with the llthreads2 library. If these worker-threads want to however trigger a record-processing via an I/O (or soft) event they must have access to the LIS API, therefore the worker-thread as to call the following method in order to bind the required methods:
<boolean> luaiocsup.bind_luaiocsup()