This is a tag page.

Synchronize Tcl and binary package versions

John Peck
Published

Update on 2024-Apr-13 -- Removed Gitlab references

Github makes it easier for me to provide binary package releases along with my source code.

Update on 2024-Mar-23 -- Moving to Github

Development has moved to Github.

feather<em>over</em>box

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:

package ifneeded tcladu 1.1.0 [list load [file join $dir tcladu.so]]\n[list source [file join $dir tcladu.tcl]]

...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.

Image by Freepik

Links

A Tcl interface to the ADU100 via SWIG

John Peck
Published

Tcladu is a Tcl package providing an interface to the ADU100 from Ontrak Control Systems.

Scope shot
Figure 1: ADU100 image from Ontrak's manual.

Updates

2024-Mar-23

Development has moved to Github.

2024-Apr-4

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.


johnpeck@darkstar:~/Downloads $ tar xzvf tcladu-1.0.0-linux-x64.tar.gz
tcladu/
tcladu/pkgIndex.tcl
tcladu/tcladu.so
johnpeck@darkstar:~/Downloads $ cd ~
johnpeck@darkstar:~ $ tclsh
% lappend auto_path ~/Downloads
/usr/share/tcltk/tcl8.6 /usr/share/tcltk ... ~/Downloads
% puts [package require tcladu]
1.0.0
% puts [tcladu::discovered_devices]
2
% puts [tcladu::serial_number 0]
B02597
% puts [tcladu::write_device 0 "SK0" 200]
0
% puts [tcladu::write_device 0 "RPK0" 200]
0
% puts [tcladu::read_device 0 8 200]
0 1
% puts [tcladu::write_device 0 "RK0" 200]
0
% puts [tcladu::write_device 0 "RPK0" 200]
0
% puts [tcladu::read_device 0 8 200]
0 0

What did we just do?

Unpacked the TGZ

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.

Links