I have now officially converted all of the configurations in OpenDAX to Lua scripts. It is quite simple to do when all that the configuration needs is "token = value" pairs. The token simply becomes a global variable in Lua and the modules just runs the script and reads the globals that it expects. The opendax.conf and modbus.conf files are a tad more complex because they have some structured information that needed to be added. Previously I had used a configuration that looked something like this...
<module>
name test
startup 0
path /Users/phil/opendax/modules/test/daxtest
args -C
args opendax.conf
restart yes
openpipes no # Have dax connect to stdin, stdout and stderr
</module>
It occurred to me last night that I may have a problem in the way that OpenDAX handles modules. The design assumes that there will only be one instance of any given module running at a time. This seemed okay until I started working on the daxc modules. This is the command line client module. It is designed to be run from the shell either by a user directly or from a script. I will have the same problem when I start getting to web/cgi types of interfaces too. I think it can be easily solved in the module registration function. If a module of the given name is already registered and running then generate another name and run that one. I know that the module handling part of OpenDAX still needs a lot of work.
Okay I've spent some time thinking about some of this stuff. I've come up with an idea that I think will keep the flexibility that I want and keep the module interface simple. There are basically two types of message transactions. Some messages are just put on the queue an then forgotten. It is assumed that the receiver will eventually get the message if it is still alive. Some messages require a response. Such as a read tag message. We have to ask for the tag and then wait for the response. This is where the problem starts. While the module is building the message to send the request to read the tag the OpenDAX core puts an event message on the queue. Then the module sends the request and immediately calls the message receiving function (basically a wrapper for msgrcv()).
I have been working on having the OpenDAX core send event messages to modules when something in the database changes (or some other event happens) and I am starting to see some of the problems with using a message queue for communication between modules. I'm starting to realize that the message queue gives me some interface problems between the modules and the library. It works just fine as long as the message queue simply replicates a functional interface. For instance, reading a tag is a function call that is one message sent (the request) and another message received (the data). Once the message queue is used for any kind of asynchronous notification scheme the problem with the message queue becomes apparent.
I continue to learn a lot working on this program. I am sure that there are some really experienced programmers out there that have looked at my code and thought that a real rookie is writing it. I guess I am a rookie. I have written a lot of C code in my day, but it was mostly small programs and embedded stuff. This is the largest single software project that I have ever worked on. I am starting to realize that I have some scalability problems.
I have a functioning command line module now. It's called daxc. It has only very basic functionality now. It supports 3 commands...
tag list x x x
tag set
tag get
It still needs quite a bit of testing, but at first glance it seems to work okay. There is still some debugging output too. I need to think of a way to write some good regression tests for it.
It is my intention to implement the features of OpenDAX in daxc as they are added to the system and to make this as robust as possible. The main use for daxc will be for debugging so it needs to be feature rich and right. Another use for daxc would be shell scripts.
I think the daxlua module is in pretty good shape, finally. This is a module that interprets a Lua script and has interfaces into the OpenDAX tagbase. Fundamentally it is a logic module.
I underestimated how difficult it was going to be to interface Lua with DAX. None of the difficulties were with Lua it was all in trying to make sure that the data types were handled correctly. There was also a little tagname handling trickiness that I knew was coming that I was finally forced to deal with. This basically involved handling the subscripts for the tags.
This is the first OpenDAX logic module. It's not all that spectacular, but it was easy to program. I have more plans for the module but the rest of the system will have to mature a little more.
Whilst I was looking for an embedded scripting library for the HMI I found a little language that is taking the computer gaming industry by storm. Well, I don't know about that but the language is called Lua. It's tiny, simple and easy to embed. I was starting to get a little worried about all the baggage that TCL or Python was going to bring with them. I don't really need a socket interface for an HMI scripting engine. Lua is extremely simple to embed. I had a 10 line C program calling a Lua script in less than an hour, and most of that hour was trying to figure out why the 4.0 documentation I was reading wouldn't work in 5.0.
I wrote the function that validates tagnames last night. Here is the skinny on what is allowed.