
It is possible to extend the displays beyond what is provided with the
standard distribution, although we aren't sure how many people have
attempted this, so be forewarned that you're treading in uncharted waters.   

There is little documentation available other than the source code, and 
we don't have any resources to devote to that at this time.  Those 
cautions aside, we did design the system with the intention that others 
could add display modules, and one of our graduate students put together 
a high-level outline of what needs to be done - that is included below.  
Using that as a guide, you should be able to look through an existing 
Functional Unit, and modify it to suit your needs.  You may also need 
to add entries in the Pablo AppDefaults file if you want default values 
for your display - again, refer to the source code of an existing FU 
and see how it relates back to the AppDefaults directory entries.  

<< The original user was interested in updating displays to show how	 >>
<< objects in their program were being created and destroyed on the fly. >>
<< The response to that question is included here as well --  it         >>
<< may help you understand a bit more about how functional units operate >>
<< and how the structure of the data packets can impact what a FU can do >>

A functional unit only sees a stream of data.  If that data contains
packets that say when a object is created/destroyed, then it should be
possible to update your displays based on that information.  The way
the data is encapsulated, combined with how you write your FU will 
determine how easy this will be.  When the FU is configured, you
select which packets to look at.  As the FU runs, it will "fire" any
time one of these packets is seen.  The existing FUs have no way of
knowing which of possibly several packet types caused the FU to execute --
it's possible to do this, but not easy (or documented)  at this time.

Probably the most straight-forward way would be to write a 
custom FU that "understands" your data and can update displays from that.
The tricky part is, you need ALL the data for the FU in a single packet type.

For example,  say your trace contains a packet that says "switch to Object A"
or "switch to Object B", and then some packets containing information on
times ins the "current Object".  If the packets show up as:

packet type   packet data		comments
switch		A			<switch to A>
time		10			<10 in A>
time		10			<10 more in A>
time		30			<30 more in A>
switch		B			<switch to B>
time		10			<10 in B>
time		20			<20 more in B>

Now, you can't write a FU that says "fire on type SWITCH or type TIME
and if it's SWITCH update my labels & zero accumulated time but if it's
TIME, add value to accumulating time and update display" because the
FU can't tell which packet type is causing it to fire.

But, if you structure your data as:
packet type   packet data		comments
info		A	10		<10 in A>
info		A	10		<10 more in A>
info		A	30		<30 more in A>
info		B	10		<10 in B>
info		B	20		<20 more in B>

Then your FU can take 2 inputs - if the first field, (object) differs
from the previous value, then change label & zero time - else, just update
time.  The FU fires on each "info" packet and always has enough information
to do what you want.

The FU isn't as general as the ones we usually write, but should be along
the lines of what you want.   Hopefully this gives you some hints on where 
to begin.  You should also be familiar with the SDDF documents if you aren't 
already - the terms used are explained there.


----------------------- guideline document -------------------------

1. Writing a New Functional Unit

   1.0 Definition of Terms
       widget:  In Pablo, C source code implementing X widgets.
       wrapper: C++ source that implements an interface layer to widgets 
                on top of the usual "arglist" layer
       FU:  In Pablo, a module accessible from the module palette that
            may be wired into an analysis graph.
       display FU:  An FU that interfaces to a data display window.
	            Display FU's are generally constructed using one or
	            more types of widgets; display FU's interface with
	            wrappers for each widget of interest.
       
   1.1 Scope
	This discussion assumes all the widget behavior required of
 	a new display FU is already in place.

   1.2 Source Files
	Source code for FU's resides in two files:
                Visual/Src/System/FunctionalUnits/<FUName>.C
	        Visual/Src/System/Includes/<FUName>.h
	where <FUName> is a meaningful identifier of your choosing.

	To write clean FU code sometimes requires the addition or
        modification of methods in the wrappers to which one interfaces.
	Wrapper files may be found in the directory
                Visual/Src/Widgets/Wrappers
        with filenames similar to the names of their corresponding 
	widgets (e.g., "BargraphFormWrapper.C" for the Bargraph widget).
	Both .C and .h wrapper files are in this one directory.

   1.3 FU Methods
	In writing a new FU, the following methods should be
        implemented.  The easiest approach here is to select an existing
	FU and use it as a development template.

	     * constructor and destructor
	     * configureOperation() and/or configure():  These methods 
		 are executed when the user is in the process of 
		 "Configure Graph" or "Configure Module" operations in 
		 the main interface.  configureOperation() is executed
		 before the pipe/record/field to port bindings, and
		 configure() is executed after those bindings.  Both
		 of these methods are optional.
	     * copy(): This method makes a copy of the FU and is executed
		 when you first select a module of this type.
	     * init(): This method is executed when the FU is selected
	         from the Add A Module palette.  Here we instantiate
	         classes for any wrappers to be used.
	     * loadConfigFromFile():  This method allows saved
	         configurations to be read from disk using a
		 fopen/fscanf-style implementation.	
	     * ready():  This simple method is used by the Pablo
                 infrastructure to determine if the configuration state
	         is such that running the graph is legal.
	     * run():  This method is executed each time data appears
	         at the input port of this FU.  It is the responsibility
	         of this code to extract data values from their internal
	         storage representation and perform all desired filtering and
	         processing on them.  Typically, some final version of
	         the processed data will be passed to wrapper methods
	         here for eventual display.
	     * saveConfigToFile():  Writes configuration to disk using a
	         fopen/fprintf-style implementation.  The format of
	         saves must be compatible with what loadConfigFromFile()
		 is coded to read.

	Other methods than these may be added, as is done in many of
	the existing FU's.  One useful possibility is:

	     * fuCallback():  Implements a callback at the FU-level.  One
	         typically wants a callback at this level in order to
	         display data values exactly as they were received by
	         the FU.

   1.4 Hooking into Pablo Interface
	Given a complete implementation for a new FU, three source
	code modifications must be made to allow Pablo to recognize
	it and incorporate it into the Add A Module palette.

	First, the file 
	     Visual/Src/System/Includes/FunctionalUnitList.fudef 
	must be modified.  This file contains lists of functional unit
	entries, each entry of the form

	    <FUName> string

	where <FUName> is the name described in Section 1.2 (i.e., the
	name of the source files, without extension).  'string' is an
	arbitrary identifier.  By convention, we choose <FUName> to end
	in the suffix "FU" and 'string' to be the same as <FUName> but
	with the "FU" suffix removed.

	The 'string' identifier is used by the second source code file
	that needs to be modified,
	     Src/System/Includes/FUClassification.def

	This file contains for each FU a one-line entry of the form
	     FU_CLASS( "string", FU_Display,
	               FUIcon_height, FUIcon_width, FUIcon_bits )
		       
	where FU_CLASS is a macro, "string" is the 'string' identifier
	discussed above, and the other entries are defined constants
	that need not be changed.  If one is not creating a display FU,
	the entry 'FU_Display' should be changed to one of the other
	valid entries, depending on the categorization of the FU (e.g.,
	FU_Math, FU_Unclassified).

	Finally, the third file to be modified is
	    Src/System/Build/FunctionalUnits/ObjFiles

	This file contains a single list of .o files that tell the
	Makefiles what may need to be built.  Just add the entry
	for <FUname>.o.


   At this point, rebuilding Pablo will incorporate the new FU into the system.
