|
|
|
I had some thoughts about the Tape Recording Subsystem after our meeting that I wanted to share with you. The following subjects are discussed below:
Tape Library - expands on the ideas you and Stan kicked about.
Control Server - presents a suggested implementation of a custom control server.
Tcl-based GUIs - reveals how to simplify GUI development.
The tape library would be a library of
open()-close()-read()-write()
functions that clients could
call to access a tape drive. Internally, a _TapeDrive
structure would be defined that contains information about an opened tape
"file":
typedef struct _TapeDrive { ... } _TapeDrive ;
The clients would only see a TapeDrive
handle:
typedef struct _TapeDrive *TapeDrive ;
A client would access a tape drive with calls such as the following:
TapeDrive tape ; /* Handle for opened drive. */ status = tpOpen ("drive[@host][/file]", options, &tape) ; status = tpRead (tape, numBytesToRead, buffer, &numBytesRead) ; status = tpWrite (tape, numBytesToWrite, buffer, &numBytesWritten) ; fd = tpFd (tape, controlOrData) ; status = tpClose (tape, options) ;
The "file" name passed to tpOpen()
specifies the desired
drive, the host to which the drive is attached, and the name of the file to
access. For example,
sony1@triplex/dataSet23 ampex@ampex
("triplex" and the second "ampex" specify the IP addresses of the respective controllers.) The host name and file name are optional; defaults can be supplied in various ways when needed.
The options passed to tpOpen()
and tpClose()
are
simply character strings containing UNIX command-line style options for the
open and close operations; e.g.,
tpOpen ("ampex", "-recordSize 1024 -numRecords 10000", &tape) ; tpClose (tape, "-rewind") ;
By using this mechanism for specifying options, new options can be added as needed without affecting existing client code. (We have a library package to parse the options.)
The tpFd()
function returns a file descriptor for an opened
tape's control or data channel (e.g., the control socket or the FDDI read
and write sockets). These might be needed by GUI clients such as TPCE.
Some other tape library calls may be necessary to allow asynchronous I/O of
commands and status.
Internally, the tape library could use either the rsh(1)
implementation or the control server implementation. The client would not
need to know which, except with regard to the file descriptor returned by
tpFd()
for the control channel.
If you decide to write a custom control server, don't - we already have one. My gentle program is a network server that provides a separate Tcl interpreter to each of its connected clients. (A more detailed description of gentle is appended to this memo.) Tcl (Tool Command Language) is an embedded command language that can be extended with application-specific commands; e.g., tape drive commands. Although gentle simultaneously supports multiple clients, restricting it to one client would provide us with the locking mechanism we need to ensure exclusive access to a tape drive.
A Tcl-based program like gentle has the following advantages:
Clients send Tcl commands to gentle as ASCII strings encoded in
Sun's External Data Representation (XDR). gentle interprets
the commands and sends responses back, also as XDR ASCII strings. (TPOCC,
incidentally, uses this same protocol to communicate between processes.)
Sending and receiving XDR ASCII strings is very simple, thanks to our
Xnet
library. The following example sends a tape command to
the control server and reads the response:
#include <stdio.h> -- Standard I/O definitions. #include "tcp_util.h" -- TCP/IP networking utilities. #include "xnet_util.h" -- XNET definitions. int main (int argc, char *argv[]) { char *message ; int moreInput ; TcpEndpoint connection ; XnetStream stream ; -- Connect to control server. tcpCall ("sony1@triplex", -1.0, -1.0, &connection) ; xnetCreate (connection, NULL, &stream) ; -- Send tape command. xnetWrite (stream, -1.0, "$tapeDrive rewind") ; -- Read status. xnetRead (stream, -1.0, &message, &moreInput) ; printf ("Completion status = %s\n", message) ; xnetDestroy (stream) ; -- Close connection. }
C and C++ versions of the Xnet
functions are available. The
file descriptor for the socket connection underlying an Xnet
stream can be retrieved for use by GUIs.
Adding application-specific commands to Tcl is very easy. First, you need to decide upon a set of commands. Some example tape commands might look as follows:
set tape [openDrive sony1] $tape Position endOfTape $tape Enable writing
The openDrive
command opens the first Sony drive and returns a
handle for it that is stored in variable, tape
. The
openDrive
command also registers the handle as a dynamic Tcl
command; when the handle appears as a command keyword (e.g., by
dereferencing the tape
variable with a $
sign),
the new Tcl command is executed. For example, the $tape
Position
and $tape Enable
commands are the same command
($tape
) with different arguments, Position
and
Enable
.
When the Tcl interpreter encounters an application-specific command, it
parses the command arguments and passes them in an argc/argv
array of character strings to the C function that implements the command.
We have an option-scanning package that makes it a breeze to process the
command arguments. (This is the same package that would be used by the
tape library for scanning the open and close options.)
The tape command could perform the desired operation either by running the
appropriate Triplex program or by making the actual ioctl(2)
calls. The command would then return status to the client who issued the
command.
Tcl procedures ("subroutine scripts") would allow the packaging of
arbitrary sequences of primitive tape operations. An object-oriented
extension to Tcl, [incr Tcl], provides even higher-level
abstractions. In fact, by running the Triplex programs using Tcl's
exec
command, the TRS tape commands could be implemented
entirely in Tcl - no application-specific C coding would be necessary.
Stan mentioned that he had mentioned Tcl and Tk to you. The attached description of the MEDS Operator Interface, moi, will give you some idea of what can be accomplished in a Tcl-based GUI. Tk is an X Windows toolkit like the Xt-based Motif, but Tk is much easier to use, looks as good if not better, and is cheaper than Motif - Tk is free and well-supported!
Tk is not the only Tcl-based GUI, however; there are several Tcl bindings to Motif itself available. I used one of these bindings, tclMotif, to convert moi to Motif. This turned out to be much easier than expected since most of my Tk-specific windowing commands were encapsulated in [incr Tcl] object classes. By simply re-implementing these classes using Motif commands, I was able to reuse most of the existing display page definitions (e.g., the menus, the subsystem status pages, etc.). The Motif pages look nearly identical to their Tk counterparts.
What are the advantages of a Tcl-based GUI?
5 minutes - to create a status region definition script from the subsystem's status header file. This Tcl script, which specifies the layout of the subsystem's global status region, is read by the gentle server running under VxWorks on the Master Controller card.
5 minutes - to create the status display page script. This Tcl script tells moi how to periodically retrieve and display the subsystem's status information.
1 minute - to add the new subsystem to moi's display page menu.
Tcl is obviously the greatest thing since sliced bread, so what are you waiting for?