Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Embedded Systems

Graphical Embedded Real-Time Systems


Dr. Dobb's Journal April 1997: Embedded Systems

Harry, a software developer at CERN, can be contacted at [email protected].


For the past few years, I've been developing data-acquisition systems for high-energy physics experiments, including the ALICE experiment at CERN, Switzerland (http://www.cern.ch/ALICE/welcome.html), and the KLOE experiment at the National Nuclear Research Laboratory in Frascati, Italy (http://www.lnf.infn.it/kloe/). In doing so, I employ VME-based distributed embedded microprocessors to read data from transparently interfaced instrumentation buses (such as CAMAC, FASTBUS, and GPIB). I then reformat the data and ship it to workstations via TCP/IP (Ethernet, FDDI, or Fibre Channel). On the workstations, I store the data for offline physics analysis on tape. Some data analysis needs to be performed online in real time for quality assurance during acquisition.

This kind of activity used to be hardware oriented, requiring me to work with assembly-language programs, microkernels, and EPROM burning. More recently, embedded VME processors running diskless, network-based UNIX implementations (AIX, HP-UX, OSF, and Lynx OS) are providing more-than-acceptable real-time performance. This shift dramatically changes the software-development process, since I now have all the tools I need -- including networking and X11 -- on single-board computers.

For one thing, the shift enabled me (or forced me) to provide users -- experimental physicists who no longer want to type cryptic commands on VT100 terminals -- with graphical user interfaces. For another, it allowed me to make greater use of graphical data visualization. Detectors consist of hundreds of thousands of electronics channels. They can be understood at a glance, but only when displayed according to their true physical arrangement in the experimental zone with observed signals color coded on the display.

To add graphical elements to our systems, we originally experimented with Motif. This produced nice results, but the development effort was enormous (even with commercial GUI builders). Macintosh and Windows seemed better, but not enough to warrant porting our UNIX-based software.

We eventually turned to Tcl/Tk. Tcl, short for "tool command language," is an embeddable scripting language that provides generic programming facilities. The Tcl language has been extended with the Tk toolkit for rapid GUI development. For more detailed information on Tcl/Tk, see Tcl and the Tk Toolkit, by John K. Ousterhout (Addison-Wesley, 1994), and "The Tcl Programming Language," also by John Ousterhout (Dr. Dobb's Sourcebook, #221 Winter 1994).

Tcl/Tk is a complete general-purpose programming language for solving any non-time-critical problem. But due to its interpreted nature, Tcl is limited in performance in nongraphical algorithms. Consequently, Tcl/Tk is available as a standalone command interpreter (called "wish") and as a library. The library allows you to add functionality to the interpreter in any compiled language (typically C or C++) for coding performance-sensitive parts of your application. This, together with integration into the X server, lets you use Tcl/Tk in an embedded real-time environment.

If you don't need submillisecond real-time response, the standard interpreter is probably all you need. It will give you platform independence, with the wish interpreter running under all X11-UNIX platforms, VMS, Windows, and Mac OS. In fact, it took me only about two hours to install both Tcl/Tk and the XF GUI builder under the Lynx OS real-time operating system.

To port Tcl/Tk applications, you only have to copy the ASCII source file to your computer. Tcl/Tk programs can also run as applets in web browsers with the Tcl/Tk plug-in supplied by Sun (http://www.sunlabs.com/research/tcl/). Alternatively, wish can serve as a helper application to your browser.

Tcl/Tk and XF

XF (see Figure 1) is a GUI builder for Tcl/Tk programs. Available at http://panther.cimetrix.com/sven/xf.html, XF lets you interactively run the application while building it. Once you create a button, XF shows you the look and functionality of the graphical element, even if it was implemented in a compiled language. This is possible because XF is completely written in Tcl/Tk and can be interpreted either by the standard wish or your own enriched version of wish. You can create complex applications with little or no knowledge of the Tcl/Tk syntax.

Not only does XF generate reasonably readable code that can be easily edited by hand, it lets you import hand-coded programs. You can intermix XF-generated and hand-coded programs without losing hand-coded additions, and you can switch to XF on previously developed Tcl/Tk programs. XF does not maintain separate UI description files -- any Tcl/Tk program is its own XF-compatible GUI description.

Real-Time Run Control

Figure 2 is a functional diagram of the Data Acquisition Test Environment (DATE), our data-acquisition system (see http://aldwww.cern.ch/documents/manuals/Test-Beam-DAQ/). The VME processor runs three asynchronous tasks:

  • Acquiring data from the hardware.
  • Shipping data to the workstation for recording.
  • Running the user interface.

These tasks exchange data and communicate with each other by a shared-memory segment implemented with System V services.

The UI, generated by XF in Tcl/Tk, is about 1500 lines of code, created in less than a day. (Most of the time was spent choosing GIFs and fine-tuning control appearance.) Had the code been written by hand, 500 to 600 lines would have sufficed, as XF is generous with support code, creating all objects (even similar ones) in an enumerative rather than iterative way. In other words, if I'm creating 100 similar labels by hand, I would have to use Example 1(a). XF, however, accomplishes the same thing with Example 1(b); this is intrinsic to how XF works. Although a boon in many situations, it may prove to be a problem when the code is provided as executable content, or when program-transfer time and source-code length are an issue. Still, I never really looked at the generated code, except for adding two hand-coded Tcl routines that handle the state changes and change the appearance of the panel (see Figure 3).

The only C-coded enhancement to the wish interpreter was adding the ability to link to the System V shared memory and linking the relevant variables to their Tcl counterparts. Listing One hows how you can add native code functionality to the interpreter. The panel displays these variables and sets them according to the user input. In the future, communication with the shared memory will be isolated in a separate process written in C, communicating with the UI over pipes. In this case, the UI is interpreted by the standard wish interpreter at a minimal performance penalty. This approach also allows us to run the UI task on a remote workstation, since pipes can easily be extended over the network using TCP/IP.

Detector Visualization

Figure 4 illustrates an event display of a particle detector. The wire chamber with pad readout is sensitive to the Cerenkov photons emitted in a cone by a charged particle traversing a dense medium faster than the speed of light in the same medium. The effect is the electromagnetic equivalent of the bang produced by a bullet or a supersonic plane. The angle of the emission cone or radius of the projected circle, as well as the number of photons emitted along this circle, are a direct measure of the speed of the particle. This, together with an independent momentum measurement, allows us to identify both the particle species and its energy. (The true dimension of the pad chamber is about 1×1 meter; it is equipped with about 10,000 electronics channels.)

The frame and canvas layout was generated by XF. The only hand-coded Tcl routine draws the projected rings and the pads hit by photons (see Listing Two). In turn, the Tcl routine calls a C-coded routine, online_event, that gets the event (a snapshot of the detector state) from the shared-memory segments and deposits them in associative arrays, which are an intrinsic data type in Tcl. File_event (written in C) allows to you visualize data previously recorded on tape or disk and is used in interactive offline analysis. Which of the three routines -- File_event, Online_ event, or MC_event -- is used by next_ event depends on the value of the variable inpmode.

The value of inpmode is controlled by the Input pull-down menu (Figure 5), which presents three radio buttons. Listing Three, the source code for this menu, illustrates how the Tk API lets you avoid writing event handlers. All user input (mouse motions, clicks, and key presses) are routed to the correct widget by the interpreter. In most cases, you don't even have to supply an explicit callback -- you link the graphical appearance of a widget to the contents of a variable.

When clicking the button, the -variable inpmode option in the radio button definition arranges for the variable to be set to what appears in the -value option. At the same time, changing the value of inpmode will select or deselect the correct button. Activating the File button deselects the other radio buttons.

Setting and obtaining the text of labels, text fields, check boxes, and sliders is also straightforward -- you set a Tcl variable to change the appearance of one or more displays or read a variable to get the value of a set of controls. You never have to ask a widget for its state information, nor do you have to know which control has acted on or displays the variable. When linking C variables to their Tcl counterparts, the C statement nr_events++; updates displayed text and/or moves a slider.

Each hit returned by the XXX_event procedure consists of three numbers: the pad column, row, and pulse height of the signal. The column and row determine the location in the canvas of the square to be drawn, while the pulse height determines the color.

Whatever you draw -- lines, circles, text, and the like -- becomes an identified modifiable object that will redraw itself whenever necessary. Since graphical elements are widgets, they can be supplied with their own callbacks. Consequently, you don't have to monitor mouse positions when connecting programmatic behavior.

Whenever you move the mouse pointer over one of the colored pads, the binding

.cf.rich_canvas bind $id <Enter> "set charge $hit_charge($i)" 

causes the pulse height under the mouse to be displayed in the text field at the bottom of the panel. The color of the pad indicates the observed signal; the label gives the exact value. The binding routine changes a variable; its value had been previously linked to the label text in

label.frame28.chargeval ...
-textvariable charge 

Similarly, the pad row and column numbers at the bottom of the display are updated by a <Motion> binding to the canvas itself.

What makes the object-oriented approach on the drawn elements more powerful is that graphical objects can be addressed not only by their unique identifiers but also by the tags they carry. Tags are arbitrary strings that may be attached to graphical objects. Many objects may share the same tag, and one object may carry more than one tag. For instance, to turn on the display of reconstructed Cerenkov rings, all I have to do is type:

.canvas itemconfigure rings 
-foreground grey 

Executing:

.canvas itemconfigure rings 
-foreground white 

will make them disappear again. They stay on screen, even if invisible, and I can switch them back on without knowing how many and where they are.

Tk transparently takes care of the third dimension for you: Turning the rings white or gray will not overpaint the hit pads. When moving or deleting an object, objects previously "under" an object will become visible. For instance, to clear the canvas of all but the static part of the detector to prepare for the next event, all you have to do is use .canvas delete hits and .canvas delete rings. The static parts of the detector will automatically reappear under pads and rings that had previously hidden them.

Example 2 shows how to create a color PostScript file from canvases and use the services of the underlying OS. Also, you can run short background tasks with the after directive; Listing Four, for instance, automatically displays a new event. (Unlike Java, Tk is not multithreaded.)

Real-Time Aspects of Integration into X Windows

Judging from the performance of Tk on top of X11, Tk's widget approach to primitive graphical elements seems to be seamlessly integrated with X11 widgets and tags. This has an important and visible effect when you run your display on X terminals that are different from machines running X clients. When you create, delete, or change the graphical appearance of a graphics primitive, you just send the relevant X11 creation and modification commands for single objects or groups of objects over the network rather than the pixel map. This frees up network bandwidth by transferring data rather than graphics. (My guess is that this is why Tcl/Tk event displays run significantly smoother and are more responsive than Java applets when viewed on an X terminal.)

This is an enormous advantage for me, since I don't want to directly connect a graphics screen to the VME board. Having a local display (some VME CPUs do offer SVGA ports) would be counterproductive, as the real-time processor would have to run both the X client and the X server. Processor-intensive tasks (getting interrupts for mouse movements, redrawing cursors, and determining what's under a deleted or moved object) are off-loaded to the X terminal by Tk, leaving the client VME processor free to perform its real-time tasks. Moreover, since the processors are often located in hostile environments (in terms of noise, temperature, and sometimes radiation levels), we can avoid sitting a "monitor cable's length" from the embedded, single-board computers.

Conclusion

Although initially thinking of Tcl/Tk and XF as fast prototyping tools, I now use them in production systems for controlling UIs and building detector visualization applications where true 3-D is not required. (For high-end 3-D applications -- possibly Tcl generated -- VRML seems a promising alternative.)

I am making programs available as executable contents to web browsers, either via plug-ins or with wish as a helper application. I prefer the latter because I am comfortable distributing to users on multiple platforms a customized version of wish with application-specific routines coded in C.

With the distributed, real-time system I've described here, my colleagues are able to control experiments and monitor detectors remotely from anywhere in the world. They provide the computing power at their end, keeping interference with the real-time requirements of the experiment to a minimum. Just as importantly, special hardware is not required -- any PC or Macintosh with a Tcl/Tk-enhanced browser and a modem suffices.

DDJ

Listing One

#include <tcl.h>#include <tk.h>
Tcl_Interp *globint;


</p>
int start_run(ClientData clientData,Tcl_Interp *interp,int argc,char** argv)
{  /*    start other tasks */
  return TCL_OK;
}
int stop_run(ClientData clientData,Tcl_Interp *interp,int arg,char** argv)
{
  /* kill other processes and await termination */
  return TCL_OK;
}
int poll_run(ClientData clientData,Tcl_Interp *interp,int argc,char** argv)
{ /* check whether run has to be stopped and update display */
  return TCL_OK;
}
int daq_start(ClientData clientData,Tcl_Interp *interp,int argc, char** argv)
{
  /* link to global section; */
  return TCL_OK;
}
int main(int argc, char** argv)
{
  Tk_Main(argc, argv, Tcl_AppInit);
  return 0;
}
int Tcl_AppInit(interp)
    Tcl_Interp *interp;
{
    Tk_Window main;
    globint = interp;
    main = Tk_MainWindow(interp);
    if (Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR;
    if (Tk_Init(interp) == TCL_ERROR) return TCL_ERROR;


</p>
    Tcl_CreateCommand(interp,"daq_start",daq_start,(ClientData) NULL,
                      (Tcl_CmdDeleteProc*)NULL);
    Tcl_CreateCommand(interp, "start_run", start_run,(ClientData) NULL,
                      (Tcl_CmdDeleteProc*)NULL);
    Tcl_CreateCommand(interp, "stop_run", stop_run,(ClientData) NULL,
                      (Tcl_CmdDeleteProc*)NULL);
    Tcl_CreateCommand(interp, "poll_run", poll_run,(ClientData) NULL,
                      (Tcl_CmdDeleteProc*)NULL);
    tcl_RcFileName = "../src/startup.tcl";
    return TCL_OK;
}

Back to Article

Listing Two

# Procedure: next_eventproc next_event {} {
#
# declare global variable. In Tcl they are local by default


</p>
global nr_hits hit_x hit_y hit_charge
glonal radius range_col charge
global projection center_x center_y center_radius
global nr_rings inpmode
global nr_event
.CF.rich_canvas delete rings
.CF.rich_canvas delete hits
if {$projection} {
# check whether projections should be visible or not
        set ccol #e0e0e0
        set cwidth 30
} else {
set ccol White
        set cwidth 0
}
switch $inpmode {
        File File_event
        Online Online_event
        Boss   MC_event
      }
#
#  draw rings
incr nr_event
for { set i 0} { $i<$nr_rings } { incr i} {
      set x_pos [ expr $center_x($i)*5+4]
      set y_pos [ expr (120-$center_y($i))*5+4 ]
      set r     [ expr $center_radius($i)*5 ]
      .cf.rich_canvas create oval                  \
           [ expr $x_pos-$r ]  [ expr $y_pos-$r ]  \
           [ expr $x_pos+$r ]   [ expr $y_pos+$r ] \
          -outline $ccol  -width $cwidth -tag rings
}
#
#  draw hits
for { set i 0} { $i<$nr_hits } { incr i} {
   set x_pos [ expr $hit_x($i)*5 ]
   set y_pos [ expr (36-$hit_y($i))*5 ]
   if {$hit_charge($i)>0} {
#      apply logarithmic color coding
        set color \
        $range_col([ expr \
        round(floor(log($hit_charge($i))/log(2)))])
   } else {
        set color green
   }
   set id  [  .cf.rich_canvas create rectangle  \
     [ expr $x_pos-1+5 ]    [ expr $y_pos-1+5 ] \
     [ expr $x_pos+5+4 ]   [ expr $y_pos+5+4 ]  \
     -fill $color  -outline {} -tag hits]
#
#   make bindings for displaying the charge when the mouse enters a pad
   .cf.rich_canvas bind $id <Enter> \
            "set  charge $hit_charge($i) "
   .cf.rich_canvas bind $id <Leave> \
             "set  charge ****"
   }
}

Back to Article

Listing Three

menu .selectbar.inmodebt.m

</p>
selectbar.inpmodebt.m add radiobutton \
-label Online -value Online -variable inpmode


</p>
selectbar.inpmodebt.m add radiobutton \
-label File -value File -variable inpmode


</p>
selectbar.inpmodebt.m add separator


</p>
selectbar.inpmodebt.m add radiobutton
-label "Boss around" -value Boss -variable inpmode

Back to Article

Listing Four

# Procedure auto_displayproc auto_display {} {
        if { $automode } {
#         only as long as the user did not get tired of it
        next_event
        after 100 auto_display
#         reschedule next display in 100 ms
        }
}
# to start with we are in stopped mode
set automode 0
set autobt_text "Auto"
button .selectbar.autbutton \
        -textvariable autobt_text -command {
    if {$automode} {
#       we were in automode
              set automode 0
#                prevent rescheduling
              set autobt_text "Auto"
#                     change button text
     } else {
#     we were in stopped mode, lets start
        set automode 1
#        enable rescheduling
        set autobt_text "Stop"
#        change button label
        after 1000 auto_display
#        first time wait a bit as to allow redraw of screen
      }
}



Back to Article


Copyright © 1997, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.