|
|
|
(The original PDF version of this memo
includes the original screen snapshots.)
Since you asked about Tcl, I thought I'd let you know what I've done with it. I've got two Tcl-based applications, one running on the Master Controller card under VxWorks and the other running on a workstation under UNIX:
Master Controller Workstation .--------. .-----. | gentle |<----------->| moi | `--------' `-----' |
moi (MEDS Operator Interface) is the user interface program you see running on my workstation sometimes, displaying event messages, status blocks, etc., received from the LZP system. moi is programmed in Tk, a superset of Tcl that includes support for X Windows and GUI objects.
gentle (GENeric TcL sErver) is a
network server program that provides each network client with its own Tcl
interpreter. gentle's Tcl has been extended with networking commands,
memory access commands, and various MEDS commands (e.g., getAlias
,
logEvent
, mapRam
, waitInit
, and a whole
slew of the TPCE-LZP commands).
moi and gentle communicate using ASCII strings (sent as XDR strings in XDR network records). For example, the event logging loop can be tested by:
logEvent code message
" command to gentle.
eventmsg()
function to log the
message.
To display a particular status variable on the screen, moi:
peek variable
" command to gentle.
The above is a simplification of the exchange. The actual command sent to
gentle is "region Get variable
", where
region specifies the MEDS status block (e.g., "APSTATUS
")
and variable is the name of the field within the block. moi and
gentle both make use of an object-oriented extension of Tcl:
[incr Tcl] (the Tcl equivalent of C++). [incr Tcl] provides
support for C++-like classes. In the command above, region is a memory
region object that responds to a Get
message by returning the
value of the requested variable. region also responds to a
Set
message; for example:
$xpstatus Set numRejectedFrames 100000000
raises the XP's rejected frame count to 100,000,000.
Tool Command Language (Tcl) is a simple, extensible, command language whose interpreter can be embedded in any application. "#"s indicate comment lines. The basic command syntax is:
command argument(s)
Arguments are frequently specified using UNIX-style "-" options; e.g.,
Activate catalog -version N
Curly braces and double quotes are used to enclose strings. Square brackets enclose nested commands. The following command:
set xpstatus [Region #auto XPSTATUS -mapFunction mapSTS]
evaluates the Region
command (which creates a region object and
maps to the XP status block) and stores the resulting value (a region handle)
in variable xpstatus
.
The value of a variable is referenced by prefixing a dollar sign to the variable name. In the following command:
$xpstatus Get gsHealthMsg
$xpstatus
is replaced by the region handle returned above, so the
actual command that will be executed is:
regionHandle Get gsHealthMsg
(This results in a "Get gsHealthMsg
" command being sent to the
region object.)
Tcl makes Perl look like a cross between COBOL and APL.
As mentioned before, gentle is a network server that provides each
client with its own Tcl interpreter. When gentle receives a command
from a client, it passes the command to that client's interpreter for
execution. A "client write message
" command allows the
interpreter to send responses back to the client. gentle can also be
run in tty mode (i.e., you type commands in at the command line) and
on a UNIX workstation. For example, I can initiate a data session from the
command line on my Sun:
% gentle -tty set mcr [mcrOpen 3000@vxlzp1] -- Connect to MC. $mcr Activate DS8V2 -- Activate catalog DS8V2. set sds [mcrOpen 3000@128.183.92.97] -- Connect to Data Generator. $sds Activate DS8V2 -- Activate data generation. exit %
gentle adds a number of commands to the base Tcl command set. In the listing below, optional command options are not shown. For example, the
peek location
command supports the following options:
peek ?-address format? ?-format format? ?-signed? ?-type type? ?-unsigned? ?-write? location
(Since square brackets have meaning in Tcl, Tcl documentation usually encloses
optional arguments in question marks;
e.g., "?-type type?
".)
As another example, the full network call
command supports these
options:
call server?@host? ?-nowait? ?-connect command? ?-error command? ?-input command?
(A signal handler is used to trap bus errors and access violations.)
The Region
class:
class Region { member mapFunction -- Default is "mapRAM". constructor() destructor() method Fill() -- Defines fill space. method Define() -- Defines typed field. method Get() -- Gets value of field. method GetInfo() -- Indexed access to arbitrary info. method IndexedAddress() -- Computes address into array field. method Set() -- Stores value in field. method SetInfo() -- Indexed access to arbitrary info. }
provides a concise means of mapping to and defining the layout of a
MEDS memory region. For example, the following definition of the XP
status region is found in "/folks/hilinski/lzp/etc/defineXP.tcl
":
# Map to XP status block. set xpstatus [Region #auto XPSTATUS -mapFunction mapSTS] # MEDS status header. DefineStatusHeader $xpstatus # XP information. $xpstatus Define inProgress {byte -unsigned} $xpstatus Define dataDirection char $xpstatus Fill byte 6 $xpstatus Define sessionID -- Default data type is ULONGWORD. # Frame counts. $xpstatus Define numInputFrames $xpstatus Define numRejectedFrames $xpstatus Define ...
A specific field in the status block can be retrieved:
client write [$xpstatus Get numInputFrames] client write [$xpstatus Get gsHealthMsg]
or modified:
$xpstatus Set numInputFrames 1234 $xpstatus Set gsHealthMsg "Never been faster!"
The Info
methods are used to store arbitrary information. For
example, to access particular entries in the XP's Virtual Channel Status table,
you need to know the size of an individual entry. "defineXP.tcl
"
computes and saves this information as follows:
$xpvcs SetInfo sizeOfVCS [expr [$xpvcs GetInfo nextOffset] - $baseOffset]]
This information can be retrieved and passed to the Get
and
Set
methods in order to access particular entries in the table.
moi is a generic, Tcl/Tk-based, graphical user interface. Tk is a
Motif-like, X Windows toolkit that contains an embedded Tcl interpreter; this
allows user interfaces to be programmed entirely in Tcl - no C coding required.
moi adds a couple of Tcl extensions: the gentle networking
commands (e.g., call
, listen
, etc.) and the
gentle timer
command.
moi initially reads a Tcl script file that defines the user interface.
My file, "/folks/alexm/source/moi/lzp
", connects moi to
the gentle server and to the MEDS event server, and then creates the
main window of my LZP interface; this window contains:
The menu bar has pull-down entries for:
[incr Tcl] was used to great advantage in my "lzp" application. I defined the following classes:
Box -- For grouping items on a page. Button CheckButton Dialog EntryDialog Field Object1D BarGraph Dial Stripchart Page DisplayPage -- Periodically updates. MemoryPage -- For memory dumps. ScrolledList Separator Timer Variable -- Local variables. RemoteVariable -- Remote variables (on the LZP).
Variable objects are used to get/set local/remote variables. In
the case of a RemoteVariable
, a
"region Get variable" command is sent to the gentle
server on the LZP system; the gentle server peek
s the
value and sends its back to moi.
The display objects (Field
, BarGraph
,
Dial
, and Stripchart
) each contain a
Variable
object, either local or remote. When you
invoke the Update
method of a display object, it
Get
s the value of its variable and updates its display.
The most commonly used display object, Field
, consists
of a label and a display/entry field:
.----------. Session ID: | 12345678 | `----------' |
When a Field
is Update
d, it retrieves the value
of its variable and places it in the display/entry field. If you type in
a new value in the display/entry field, the new value is stored in the
variable (e.g., over on the LZP rack). A Field
's label can
also function as a button. I use this capability in the Packet Break
List page: clicking on the "Next Break" label advances the page to
the next break entry.
Box
objects are used to group display objects. For example, a
two-column display is created by placing two boxes side by side. Invoking
Update
on a box results in Update
being applied to
each display object in the box.
Page
objects provide a higher-level grouping of display objects.
The bare-bones Page
class is used for interactive pages; e.g., the
LZP and SDS command panels. The DisplayPage
class contains a
timer that periodically invokes Update
on the display objects
(or boxes) in the page. Display pages are automatically given three buttons
at the bottom of the window:
Memory pages display memory dumps from the LZP rack in a scrolling window.
The ScrolledList class provides a generic scrolling list capability. Scrolled lists are used:
Individual items in a list can be selected; this capability is used in (1) to recall previous commands and in (2) to select a catalog to activate or a data set to distribute.
The Page
class is defined in [incr Tcl] as:
class Page { member displayWindow member infoArray member objectsArray member title constructor() destructor() method AddObj() method DeleteObj() method GetInfo() method GetObj() method Iterate() method Print() method SetInfo() }
objectsArray is a list of the display objects on the page; infoArray is used to store and lookup arbitrary information.
The DisplayPage
class adds several new methods to the base
Page
class:
class DisplayPage { inherit Page member updateInterval member isFrozen constructor() -- Creates Print, Freeze, Close buttons. destructor() method Freeze() -- Suspends/resumes updating. method Update() -- Updates each object in window. }
The Update
method Iterate
s through the
objectsArray, invoking the Update
method of each
display object in the array. The Update
method in an
individual object retrieves its variable's value (e.g., from the
gentle server on the LZP rack) and updates its display.
Creating a display page is a simple matter. The following example
is taken from the script file that creates the XP status page (see
"/folks/alexm/local/lib/tcl/lzp/xpstatus.tcl
"):
set page [DisplayPage #auto -title "XP Status"] set window [$page Window]
Field
s, ScrolledList
s,
Stripchart
s) to the page:
CenteredText [$window] "-- XP Status --" $page AddObj inProgress [Field #auto $window "Packet Output:" [...]] $page AddObj sessionID [Field #auto $window "Session ID:" [...]] ... and so on ...
"[...]" specifies what variable is bound to the Field
and is
omitted for the sake of clarity. When the page is created, a periodic timer
is started; whenever the timer fires (e.g., every 5 seconds), the page updates.
moi currently supports the following display pages:
Because everything is coded in Tcl and [incr Tcl], you can add a new subsystem status page in 15 minutes or less:
defineXP.tcl
") that maps to and defines the layout of
the status block.
pageXP.tcl
").
lzp
").
Modifying an existing page is just as easy and quick. Although I currently don't do this, such changes could be made while moi is still running.
The MEDS command panels are used to send commands to the LZP and Spacecraft Data Simulator (SDS) racks. (Or to any rack, if desired.) Across the bottom of a command panel are two buttons:
Down the left side of the command panel is a column of Fields for:
In the center of the command panel is a scrolling list of the available
catalogs; clicking on a catalog moves its name to the catalog name
Field
. On the right side of the command panel is a column
of buttons:
The Distribute button brings up the data distribution panel (useless
for the SDS). This panel is similar to the command panel: the available
data sets are displayed in a scrolling list and the Field
entries on the left side are used for entering the information needed for
FTP transfers. As with the command panel, clicking on a data set moves its
name into the data set name Field
.