The first thing I realized when I started to use
tcladu was the need for
convenience functions. For example, combinations of write_device
and read_device should be combined into a query command for
convenience. And it would be nice for those kind of commands to be in
the same tcladu package. So I started to write some Tcl, and I
realized I didn't really know how to manage the package version with
this high-level addition.
The tcladu.so binary already provides the tcladu namespace and
package version. I set this version in a makefile that also drives
testing, so I'd really like the makefile/binary package version to be
the source of truth. So I need to extract that package version in the
convenience code. It turns out that there's a
package command
for this. These links are to Tcl 9.0 documentation, but my usage doesn't
care.
Adding these lines
load ./tcladu.so
set version [package present tcladu]
package provide tcladu $version
...to the tcladu.tcl source file synchronizes the Tcl and binary
source versions. I can then package this up with
pkg_mkIndex -verbose . tcladu.so tcladu.tcl
...using the pkg_mkIndex command. This produces the pkgIndex.tcl script distributed with the package source files:
...where you can see the combination of sourcing and loading done to make the package available. These convenience functions are coming in tcladu version 1.1.0.
Removed references to Tcladu at Sourceforge and Gitlab.
Demonstration
Let's say you've downloaded a release binary from
Github, and you have a few (two)
ADU100s connected. You also need permissions to access the device,
but let's say you have those.
The package is just two files: pkgIndex.tcl, used by Tcl's
package procedure, and
tcladu.so, a binary produced from some c code.
Appended the package to Tcl's auto_path
The auto_path list tells Tcl where to look for packages.
Required the package
This both loads procedures into the tcladu namespace and initializes libusb.
Populated the connected device database
The discovered_devices command will populate a device database with
things like device handles and serial numbers. This must be called
before writing to or reading from devices.
Queried the device database for device 0
The serial_number command doesn't do anything with connected
hardware -- it just returns a serial number populated by
discovered_devices.
Sent the command to set/close the ADU100's relay
The write_device command takes a device index instead of some kind
of handle to identify the targeted device. It then takes an ASCII
command that you can find in the ADU100
manual to manipulate the
hardware relay. The last argument is a timeout for libusb (in
milliseconds), which will become more interesting when we get into
reading from the hardware.
Sent the command to read the relay status
Reading the relay status starts with telling the ADU100 to read the
status. It will prepare the result to be read by the next libusb
read. The return value for the RPK0 command is just a success code
-- not the relay status.
Read from the ADU100
The read_device command takes a device index, followed by the number
of bytes we want to read. This payload size is a placeholder for now,
although it has to be 8 bytes or larger. I want to keep it to handle
larger payloads on other Ontrak devices this might support in the
future.
The final argument is the familiar ms timeout. Libusb will throw a
timeout error if the read takes longer than this value. But this
error isn't fatal, and your code can catch this and simply try again.
This gives your application a chance to stay active while you wait for
a long hardware read.
The result is a Tcl list
containing the success code and return value. In this case, a 1
shows us that the relay is set/closed.
Sent the command to reset/open the ADU100's relay
This is the opposite of the set command.
Sent the command to check the relay status again
We'll now expect the hardware to report 0 for the relay status.
Read from the ADU100
The returned list is now 0 0, telling us that the command succeeded
and that the relay is reset/open.