synApps 5.7


Introduction


synApps is a collection of EPICS software intended to support most of the common requirements of an x-ray laboratory or synchrotron-radiation beamline. Because it is EPICS software, synApps is extensible by developers and end users, to support new devices and experimental techniques. This extensibility frees synApps to focus mostly on general-purpose capabilities and infrastructure, from which application-specific software can be built or assembled.

Thus, for example, synApps provides support for motors, scalers, and scans, but it does not tie those items together into an immediately executable scan (of specific motors, to acquire specific scaler channels, for a specific dwell time, etc.). The user does this at run time (or a knowledgeable user can provide a fully specified scan, and give the novice user a button to start it).

Similarly, synApps provides support for ADC's and PID loops, but somebody has to tell the PID software what feedback value to read, what conditioning function to run it through, what PID parameters to use, and what actuator to drive. By default, all of these choices can be made at top level, by the end user. Or, a knowledgeable user can provide a fully specified PID loop, and make it available to a novice user through a simplified or otherwise customized interface. The techniques and tools used to accomplish this are essentially the same as those a user would have applied at run time, so the packaged solution can be prototyped and tested at run time.

synApps is organized into modules, whose structure is based on the example directory tree produced by the EPICS application, makeBaseApp.pl, typically with two additional directories: a documentation directory, and a display-file directory. synApps modules typically contain source code, EPICS databases and database-definition files, autosave-request files, client scripts, display files, libraries and executables, and documentation.

Most synApps modules are intended primarily to export support to other modules. Some synApps modules produce bootable software, in addition to support software, but in most cases, this bootable software is primarily for testing, and for demonstrating how the support software can be used. The support exported by a module is of the following types, with example names and locations from the calc module:

database-definition file, in calc/dbd
calcSupport.dbd
...

link library, in calc/lib/<arch>
libcalc

header files, in calc/include
transformRecord.h
...

database files, and associated autosave-request files, in calc/calcApp/Db
userTransforms10.db
userTransforms10_settings.req
...

display files, in calc/calcApp/op/adl, and calc/calcApp/op/opi
userTransforms10.adl
userTransforms10.opi
...
One synApps module, the xxx module, is different: it doesn't export anything. It imports support from other modules, and produces bootable software to support an EPICS IOC. The xxx module is documentation in runnable form, and also a template from which a synApps application can be constructed. xxx is not comprehensive: it doesn't apply all of synApps; it's usually a little behind the rest of synApps; it focusses more on VME crates than on other kinds of IOCs; and it's a compromise between what is most widely used and what is most likely to build and run out of the box.
If you haven't run into the term 'IOC' yet, two things:
  1. IOC stands for Input/Output Controller. Initially, this was a VME crate with a processor running EPICS under the VxWorks operating system, but beginning with EPICS 3.14, an EPICS IOC can also be a set of tasks on a workstation running Linux, Windows, Cygwin, Solaris, RTEMS, Mac OS, and, no doubt, other operating systems.
  2. The EPICS Application Developer's Guide is an essential reference for anyone planning to develop or deploy EPICS software. While you won't need to read the guide to build or run synApps, you will need it to understand what you've done, to diagnose problems, and to extend synApps in any significant way.

Contents


Here's a list of the modules and directories in synApps:

Module/directorydescription
areaDetectorSupport for area (i.e., 2-D, or image) detectors, including CCDs, pixel array detectors, and online imaging plates. This module replaces the ccd and pilatus modules.
autosaveSupport for saving software parameters at run time, and restoring them during the next reboot. Autosave is also a way to initialize array PV's at boot time.
busyThe busy record, which allows developers more ways to indicate when an operation is complete. Previously, this record was provided by the sscan module, because the sscan record is one of its beneficiaries.
calcRun-time expression evaluation, derived from the calcout record in EPICS base, and extended to operate on strings, arrays, and to implement coupled expressions.
camacSupport for CAMAC hardware.
configureBuild files
dac128VSupport for an IndustryPack DAC module.
delaygenSupport for delay generators, including the SRS DG645, Colby Instruments PDL100A, and Gigabaudics PADL3.
documentationUm... documentation
dxpSupport for X-Ray Instrumentation Associates's DXP digital signal processor
ebrickSupport and sample application for low-cost PC-104 and uCDIMM based IOC.
ipSupport for various serial, and other message-based, devices.
ip330Support for an IndustryPack ADC module
ipUnidigSupport for an IndustryPack digital I/O module
loveSupport for Love controllers
mcaSupport for multichannel analyzers and multichannel scalers.
measCompSupport for USB I/O modules from Measurement Computing
modbusSupport for ModBus-protocol devices over TCP, serial RTU, and serial ASCII links
motorSupport for motors
opticsSupport for optical tables, monochromators, slits, etc.
quadEMSupport for an APS-developed 4-channel electrometer
softGlueSupport for user-programmed "wiring" of custom FPGA content loaded into an Acromag IP-EP201 module.
sscanSupport for scans (programmed control and data acquisition).
stdMiscellaneous EPICS support, including the epid (extended PID), scaler, sseq (string sequence), and timestamp records; and pvHistory support.
streamDirk Zimoch's streamDevice, in a module-flavored wrapper.
utilsMiscellaneous tools, including support for converting an application from one version of synApps to another; support for the MDA file format, written by the sscan module; and support for EPICS-application prototyping.
vacSupport for vacuum controllers
vmeSupport for VME hardware
xxxSample user-application directory

See support/configure/RELEASE for a complete set of compatible module versions. This release of synApps is compatible with EPICS release 3.14.12, Tornado 2.2, and the following EPICS modules, which are produced and maintained by other members of the EPICS collaboration. These modules are not part of synApps, but their maintainers have permitted us to distribute copies along with synApps:

Moduledescription
allenBradleyfor communicating with Allen Bradley PLC's (ANL)
ipacrequired for IndustryPack support (ANL)
asynrequired by many modules (ANL)
seqfor SNL programs in synApps (BESSY)
source: http://www-csr.bessy.de/control/SoftDist/sequencer
streamconfigurable device support for message-based devices (PSI)
source: http://epics.web.psi.ch/software/streamdevice.
vxStatsvxWorks statistics, modified by us (SNS)
This module has been replaced by devIocStats, and will be removed from the next version of synApps.
devIocStatsIOC statistics, replaces vxStats (SLAC)
source: http://www.slac.stanford.edu/grp/cd/soft/epics/site/devIocStats/

Previous versions of synApps included and relied on the genSub, ccd, and pilatus modules. Beginning with EPICS 3.14.10, a replacement for the genSub record, called the aSub record, is included in base, and synApps has been modified to use it instead of the genSub record. The ccd and pilatus modules have been replaced by the areaDetector module.

For convenience, this distribution includes the modules listed above, in place and ready to build, with minor modifications to build files. A few of the modules have suffered more substantial modifications to fix problems, add display files, etc.

synApps includes software developed by the Beamline Controls & Data Acquisition, Software Services, and Accelerator Controls groups of the Advanced Photon Source (APS); by developers in APS Collaborative Access Teams – notably, Mark Rivers (CARS-CAT); and by developers in the EPICS collaboration outside of the APS – notably, those at the Diamond Light Source, the Berliner Elektronenspeicherring-Gesellschaft für Synchrotronstrahlung (BESSY), the Stanford Linear Accelerator Center (SLAC), the Swiss Light Source (SLS)/Paul Scherrer Institut (PSI), the National Synchrotron Light Source (NSLS), the Deutsches Elektronen Synchrotron (DESY), the Spallation Neutron Source (SNS), the Australian Light Source, and the Canadian Light Source.

Aside from EPICS databases, SNL (State Notation Language) programs, and the like, synApps contains the following code:


How to deploy synApps


Although synApps is distributed as a single 'support' directory, it's normally deployed as a two-part system: a 'support' directory, and one or more 'user' directories. The support directory can be installed on a read-only file system, along with EPICS base and other modules, and used from there by user directories, each of which typically begins as a copy (or a collection of copies) of the xxx module, and is customized/extended to suit a particular application and set of hardware.

I'm not being very precise about what is meant by a user directory, because there are a number of reasonable variations. At the simplest, a single copy of the xxx module, which supports a single IOC, is a user directory. If several IOC's cooperate to serve a single application (such as a synchrotron beamline), one might make several independent copies of xxx, or one might extend a single xxx copy to contain multiple xxxApp directories, and multiple iocBoot/iocxxx directories. At APS, the BCDA group maintains around 100 top-level user directories (for each version of synApps) each of which contains a number of copies of xxx, and most of which, in turn, contain multiple xxxApp and iocBoot/iocxxx directories.

Here's what a complete installation might look like (much detail omitted) with all the files you will have to edit before you can build or boot an IOC:

The support directory

synApps_X_X/support/
    Makefile
    allenBradley/
    areaDetector/
    asyn/
    busy/
    calc/
    camac/
    configure/
        CONFIG
        CONFIG_SITE                     <— EDIT to build
        RELEASE                         <— EDIT to build
        EPICS_BASE.<arch>               <— EDIT to build for <arch>
        Makefile
        RELEASE
        SUPPORT.<arch>                  <— EDIT to build for <arch>
        ...
    dac128V/
    delaygen/
    devIocStats/
    documentation/
    dxp/
    ip/
    ip330/
    ipUnidig/
    ipac/
        drvIpac/drvIpac.dbd             <— EDIT to build
    love/
    mca/
    measComp/
    modbus/
    motor/
        motorApp/
            Makefile                    <— EDIT to build
    optics/
    quadEM/
    seq/
    softGlue/
    sscan/
    std/
    stream/
    utils/
    vac/
    vme/
    xxx/

The user-directory tree

synApps_X_X/ioc/
    1bm/
        Makefile
        bin/
        configure/
            CONFIG_SITE                 <— EDIT to build
            RELEASE                     <— EDIT to build
        dbd/
        iocBoot/
            Makefile
            nfsCommands                 <— EDIT to run
            ioc1bma/
                Makefile                <— EDIT to build
                *.cmd
                *.req
                *.substitutions
                autosave/
                cdCommands or envPaths
            ioc1bmb/
            ioc1bmc/
            ioc1bmd/
                <much like ioc1bma>
        release.pl
        setup_epics_common              <— EDIT to run user interface
        start_epics_1bma                <— EDIT to run user interface
        start_epics_1bmb                <— EDIT to run user interface
        start_epics_1bmc                <— EDIT to run user interface
        start_epics_1bmd                <— EDIT to run user interface
        1bmaApp/
        1bmbApp/
        1bmcApp/
        1bmdApp/

    1id/
    2bm/
    2id/
    ...
        <much like 1bm>

As shown above, the following files can or must be edited to modify the way the synApps support directory is built. After modifying files in the support, or support/configure directories, you should run make release, and make rebuild, in the support directory.

support/configure/RELEASE
Edit the definitions of EPICS_BASE and SUPPORT with the correct paths to these directories on your system.
Comment out any modules you don't want to build.

support/configure/EPICS_BASE.<arch>
If you plan to build on more than one host architecture from a single synApps directory, and the hosts use different paths to refer to the same file (for example, Windows and Linux using a shared file system) then you can override the definition of EPICS_BASE in the RELEASE file by specifying host-specific paths to base in separate EPICS_BASE.<arch> files. If you don't have such plans, then you can delete these files, but if they exist, they must be correct.

support/configure/SUPPORT.<arch>
Similar to EPICS_BASE.<arch>, but for the synApps support directory

support/configure/CONFIG_SITE
Edit to set the following variables, which control what will be built: The supported values for these variables are YES and NO.
LINUX_USB_INSTALLED
This controls the build of the dxp module. If usb is not installed for developers, then parts of dxp/dxpApp/handelSrc will not be built, and the example application executable, dxpApp, will not be built, so dxp/iocBoot cannot be used.
LINUX_NET_INSTALLED
This controls the build of the mca module, specifically, support for the Canberra AIM hardware.
IOCS_APPL_TOP
Path to application top as seen by IOC. Set this when your IOC and host use different paths to access the application directory. This will be needed to boot from a Microsoft FTP server or with some NFS mounts. You must rebuild in the iocBoot directory for this to take effect.

support/ipac/<version>/drvIpac/drvIpac.dbd
uncomment registrar() commands for IndustryPack carriers you plan to use.

support/motor/<version>/motorApp/Makefile
comment or uncomment to select the motor support you want to build.

The following files must be edited before building a user directory:

ioc/<appname>/configure/RELEASE
edit the definition of SUPPORT with the correct path to the support directory
ioc/<appname>/iocBoot/<iocname>/Makefile
edit to specify the architecture that is to be built

The following files must be edited before running the user interface:

ioc/setup_epics_common
set the value of Channel Access variables, such as EPICS_CA_MAX_ARRAY_BYTES.
ioc/start_epics_xxx
edit to specify the path to the application and display-file directories, and the name of the top-level display file.

The association between a user directory, and the support directory on which it depends, is made entirely by the file, configure/RELEASE, in the user directory. Typically, this file simply includes the configure/RELEASE file from the support directory, but it may differ: it may specify EPICS modules not included in synApps, for example. Or, if the support directory contains more than one built version of a module (the original and a bug fix, for example) the user directory can choose which version it will use.

Note, however, that the modules in synApps are interdependent. Many of the modules depend on the asyn module, for example, and there are many other dependencies, both direct and implied. (If module a depends on module b, and module b depends on module c, then a also depends on c, and it must specify the same version of c that b specifies.) The complete set of modules selected by a user directory must be self consistent, and the EPICS build will ensure this, unless you tell it not to, by defining
CHECK_RELEASE=NO
or
CHECK_RELEASE=WARN
in ioc/configure/CONFIG_SITE.

For completeness, the format of a RELEASE-file path definition is "<name>=<path>", where <name> is an arbitrary string, and <path> is an absolute directory name (starts with '/' on a unix host, or with a drive name such as 'C:' on Windows). Although <name> is arbitrary, you should be consistent. Generally, the EPICS build doesn't care what paths are named, because it's just going to collect them all into a list, and use the list to search for libraries, .dbd files, etc. But, in the module consistency check mentioned above, the name does matter, because EPICS can't check that all modules in a build are using the same version of, say, the asyn module, unless they all use the same <name> for it. Also, in the xxx module, <name> is used extensively to find display files (that is, to set the EPICS_DISPLAY_PATH environment variable), and to specify databases, autosave request files, etc., when an ioc is booting.

The synApps build imposes an additional constraing on module names. Because synApps uses EPICS build rules to descend from support into the modules, module names may not include the character '.'. (The EPICS build rules expect '.' to be followed by a host or target architecture.)


How to build synApps


  1. System configuration
  2. Before building synApps, you should ensure that your system has the tools, libraries, header files, etc. required to build the modules you want to build. Here's a list of dependencies we've documented so far.

    Please help: new users are particularly well placed to help us complete this list. Long-time developers typically have lots of things correctly configured that they don't even remember configuring.

  3. Building and configuring the support directory
  4. If you have a built copy of EPICS base 3.14.12.1 or later, then building the synApps support directory should be very simple:

    1. Edit support/configure/RELEASE, and support/configure/CONFIG_SITE, as noted above.
      If you are using Perl 5.6 or earlier, see comments in support/configure/makeReleaseConsistent.pl for needed script modifications.
    2. Edit support/configure/EPICS_BASE.<arch>, support/configure/SUPPORT.<arch>, as noted above, for the architectures you want to build.
    3. Edit ipac/<version>/drvIpac/drvIpac.dbd, and motor/<version>/motorApp/Makefile, as noted above.
    4. Set the environment variable EPICS_HOST_ARCH to the architecture (and compiler, if there is a choice) on which you are building. synApps is tested with the architectures linux-x86_64, cygwin-x86, and win32-x86.
    5. In support, run 'make release'. (See note below.)
    6. In support, run 'make'. (You should be able to use 'make -j' to build synApps more quickly.)

    You should use the same GNU Make executable that was used to build EPICS base. You may need $(EPICS_BASE)/bin/<arch> in your path, and you may need $(EPICS_BASE)/lib/<arch> in LD_LIBRARY_PATH.

    When executed in the support directory, 'make release' will go to all of the modules support/Makefile is configured to build, and edit the configure/RELEASE files in those modules so that they all build from the same versions of EPICS base and other known modules.

    Typically, the build will not succeed the first time, because you will not have all of the required system support. If you find that you cannot build some synApps module, you can disable its build by commentng it out of support/configure/RELEASE.

  5. Building and configuring a user directory
  6. Once synApps' support directory has built without errors, the xxx module will have been configured (xxx/configure/RELEASE will have correct, absolute paths to base and support) and built, so you can use it as an example – or, better, a template – for constructing user directories to support your IOCs. To make a template of xxx, clean and uninstall it, and tar a copy of the directory. To use the template, untar it, cd to its top-level directory and run support/utils/changePrefix to change the PV-name prefix from xxx to whatever you want. (Note you must have support/utils in your command path, or you could copy support/utils/changePrefix and support/utils/doSed to a directory that is in your command path. Note that changePrefix is synApps-version specific.)

    Here's what I do:

    	# Do once when synApps is built:
    	cd $(SYNAPPS)/support/xxx
    	setenv EPICS_HOST_ARCH <host architecture>
    	gnumake clean uninstall
    	(repeat as needed for any other architectures)
    	tar cvf ../xxx.tar *
    
    	# Do whenever a new user directory ('1bm', in this example) is needed:
    	cd $(SYNAPPS)/ioc
    	mkdir 1bm
    	cd 1bm
    	tar xf $(SYNAPPS)/support/xxx.tar
    	changePrefix xxx 1bma
    	mv iocBoot/iocvxWorks iocBoot/ioc1bma
    	edit iocBoot/ioc1bma/Makefile to specify the IOC processor type
    	gnumake
    

    To put a second application, 1bmb, into 1bm, I run the following commands:

    	cd $(SYNAPPS)/ioc
    	mkdir temp
    	cd temp
    	tar xf $(SYNAPPS)/support/xxx.tar
    	changePrefix xxx 1bmb
    	mv iocBoot/iocvxWorks iocBoot/ioc1bmb
    	edit iocBoot/ioc1bmb/Makefile to specify the ioc processor type
    	cd $(SYNAPPS)/ioc
    	mv temp/1bmbApp/start_epics_1bmb 1bm
    	mv temp/1bmbApp 1bm
    	mv temp/iocBoot/ioc1bmb 1bm/iocBoot
    	rm -rf temp
    	cd 1bm
    	gnumake
    

    Edit the files above to agree with your hardware, to load the databases you want, etc., set up the IOC processor's parameters to load from the software just configured, and boot the crate. If you don't know how to do this, read on.


How to make synApps work


  1. Setting up the IOC (vxWorks)
  2. Ensure that $(EPICS_BASE)/bin/<arch>/caRepeater gets run when your workstation boots. If you have no way of doing this, you can run it manually or put the command in your .login file.

    Setup your host system to work with the EPICS processor. See the VxWorks Programmer's Guide if you have a copy. Here's what we do (on a Sun workstation):

    See support/xxx/iocBoot/ioc*/bootParms for other processor types. If your VME processor has mount access to an 'APSshare' NFS file server, you can specify the 'file name', above, as "/APSshare/vw/T222/mv2700-asd1".

  3. Display files
  4. synApps includes hundreds of display files intended for use with the EPICS display manager, MEDM, and translations of those files that work with CSS-BOY and caQtDM. Other EPICS display managers exist, and I once did a mass automated translation of MEDM display files to the EDM display manager's file format, using software developed by others. This translation was only partially satisfactory, but we don't have the resources to do the job better or more generically. In this documentation, I'll limit attention to MEDM display files.

  5. Fitting synApps to a particular set of hardware
  6. This happens in the user directory. Generally, you must tell "EPICS" what hardware is in your crate, and what addresses, interrupt vectors, etc. you have set your hardware to use. (See support/xxx/documentation/vme_address.html for a list of suggested values.) You also must specify which motors any slit, table, monochromator, etc., control software is to use. If you use serial or GPIB, you must match port names to hardware devices, set serial-port parameters, and specify GPIB addresses. For any IndustryPack modules, you must specify the IP carrier and slot into which you've loaded those modules.

    Overview

    In a complete job of fitting synApps to an IOC's hardware, all of the following files will be touched:

    xxx/iocBoot/ioc*/st.cmd
    This is the ioc's startup script, and it loads the other .cmd files

    xxx/iocBoot/ioc*/*.cmd
    xxx/iocBoot/ioc*/*.substitutions
    Other command files that may or may not be invoked by st.cmd

    xxx/iocBoot/ioc*/auto_positions.req
    xxx/iocBoot/ioc*/auto_settings.req
    specifies PV's to be saved periodically during operation, and restored automatically when the ioc is rebooted.

    xxx/iocBoot/ioc*/saveData.req
    identifies PV's used by the saveData software, sscan records to be monitored for data, and PV's whose values are to be included in all scan-data files.

    xxx/iocBoot/ioc*/bootParms
    a copy of the boot parameters (in case the IOC processor crashes in a way that erases nonvolatile memory)

    In more detail

  7. Running synApps
    1. Boot parameters

      See xxx/iocBoot/ioc*/bootParms for sample boot parameters.

    2. Display manager

      • MEDM

        See the MEDM Operator's Manual for detailed information on the special needs of this X11/Motif program. I'll assume those needs have been met.

        MEDM uses a search path list to find .adl files, and we'd like for that path list to refer to the synApps module versions actually in use. To generate the search path list from an application's configure/RELEASE file, edit the file xxx/start_epics_xxx so it sets the environment variables EPICS_APP and EPICS_APP_ADL_DIR. Here's an example:

        setenv EPICS_APP /home/oxygen/MOONEY/epics/synApps/support/xxx
        setenvEPICS_APP_ADL_DIR ${EPICS_APP}/xxxApp/op/adl
        
        If you plan to run MEDM on a workstation that isn't on the same subnet as the IOC's, you'll need to uncomment and edit the definition of the environment variable EPICS_CA_ADDR_LIST. In principle, you should be able to name only the broadcast address for the subnet that contains the IOC's, but if this doesn't work, you can put in the IP addresses of all the IOC's you want to connect with, separated by spaces, as follows:
        setenv EPICS_CA_ADDR_LIST "164.54.53.126 164.54.53.127"

        If you want to use arrays larger than 16000 bytes (e.g., MCA spectra of more than 4000 channels, or scans of more than 2000 data points), you must set the environment variable EPICS_CA_MAX_ARRAY_BYTES, in both the IOC and workstation, to the size of the largest array you plan to send over the network, plus the size of the extra data channel access might be asked to include with the array. On a Unix system, for example, you might say

        setenv EPICS_CA_MAX_ARRAY_BYTES 64008
        in the IOC's st.cmd file, you'd say
        putenv "EPICS_CA_MAX_ARRAY_BYTES=64008"
        This will permit scans of up to 8000 points (8000 doubles * 8 bytes per double + 8 bytes for channel-access overhead), and mca spectra of up to 16000 channels.

        To bring up the top-level MEDM display for synApps software, cd to xxx and type "start_epics_xxx" (e.g., start_epics_1bma). This script locates the directories that might have MEDM-display files and includes them in the environment variable EPICS_DISPLAY_PATH, cd's to xxxApp/op/adl, and runs MEDM with the default top-level display file.

      • caQtDM

        caQtDM display files (*.ui) in synApps were translated from MEDM-display files (*.adl) with the adl2ui translator in caQtDM-2-8 (available from http://epics.web.psi.ch/software/caqtdm/).

        caQtDM implements a search path list very much as in MEDM, so we can use the same technique to autogenerate that path from an application's configure/RELEASE file. Edit the file xxx/start_caQtDM so it sets the environment variables EPICS_APP and EPICS_APP_UI_DIR. Here's an example:

        setenv EPICS_APP /home/oxygen/MOONEY/epics/synApps/support/xxx
        setenv EPICS_APP_UI_DIR ${EPICS_APP}/xxxApp/op/ui
        

        Other environment variables used by caQtDM are the same as for MEDM.

      • CSS-BOY

        CSS-BOY display files (*.opi) in synApps were translated from MEDM-display files (*.adl) using the ADL-to-BOY translator included with CSS-BOY.

        CSS-BOY can use a search path list for display files, as MEDM does, but the path is defined differently. One way to set it is to select the menu "Edit/Preferences", then select "CSS Applications/Display/BOY" and type the path into the "OPI Search Path" box. See CSS-BOY documentation for other options.

    3. autosave/restore

      You must give the crate write permission to xxx/iocBoot/ioc*/autosave so it can write the files auto_positions.sav and auto_settings.sav there. It's also helpful to set the autosave directory's 'group' bit so that files the crate writes will be owned by the owner of the directory instead of by . Normally, I do this:

      chmod a+w,g+s autosave

      To modify the list of PV's that are saved and restored, edit the files xxx/iocBoot/ioc*/auto_settings.req and xxx/iocBoot/ioc*/auto_positions.req

      The autosave software is started by the lines "create_monitor_set(..." in xxx/iocBoot/ioc*/st.cmd. The restore happens during iocInit as a result of function calls inserted into initHooks.o, which is included in the library provided by the autosave module, and linked into the executable loaded by xxx/iocBoot/ioc*/st.cmd.

    4. saveData

      saveData is a CA client that monitors sscan records and saves scan data to disk. On vxWorks, this is an NFS-mounted disk; on other operating systems, it's whatever file system the system provides for the standard C library. The saveData software is configured with the file xxx/iocBoot/ioc*/saveData.req, which needs no special attention unless you want to modify the list of EPICS PV's whose values are to be saved with every data file. To do this, look for the string "[extraPV]" in the file, and edit the list of PV's immediately following that string. If an entry in this list contains only the PV name, saveData will describe the PV, in the data file, using the .DESC field of the record that contains that PV. If a string follows the PV name, saveData will use the string instead.


How to extend synApps


Like all EPICS software, synApps can be extended in many ways, and at many levels, by EPICS developers and users. (That's how the package came to exist in the first place. It started as a single App directory, and folks just added stuff.) But synApps pushes the idea a little bit further toward end users who are not developers. One of the driving notions behind the development of synApps was to put as much of EPICS' flexibility and power as seems both wise and practical into the hands of end users – typically, scientists running experiments – whose backgrounds in software development and implementation vary over a wide range.

Here is a list of techniques by which synApps has already been extended by users and developers, arranged very roughly according to the amounts of effort, skill, and EPICS knowledge required.

All of the extension strategies described above produce (or, at least can produce) results which are fully integrated into the control system. This means that they can be used in further extensions by the same techniques. Thus, for example, motors ganged together by a transform record can be scanned, driven by a PID loop, or controlled by another userCalc.


The synApps utils directory


The synApps support/utils directory contains a variety of executables that may be useful in administering and/or using synApps. Some of these tools are probably peculiar to the way synApps is used at APS.

changePrefix, doSed
These are for the application developer's convenience in changing EPICS prefixes in a user directory. You must be in the top level of the user directory to run changePrefix, and you should do a "gnumake clean uninstall" before running it.

Example of use:

    cd $(SYNAPPS)/ioc/1bm
    changePrefix xxx 1bma
copyAdl
Look through synApps for .adl files, and copy them all to a specified directory

Example of use:

    copyAdl $SYNAPPS/support adl_files
convertIocFiles.py
This file, and its associates, are intended to help convert an IOC directory from one version of EPICS to another, by collecting data from an existing IOC directory, and attempting to correctly edit files in a new IOC directory. See support/utils/HowToUse_convertIocFiles.txt for more information on this program.

mdautils-src.tar.gz
This tar file contains utility programs for using data files written by the sscan module's "saveData" program. These programs were written by Dohn Arms, and contributed to synApps.

mdaExplorer
This wxPython program displays the content of MDA files, and directories of MDA files. (An MDA file is the scan-data file produced by the synApps sscan module's saveData software during a scan.)

mdaPythonUtils
A collection of python programs that read, write, modify, and translate MDA files.

snapDb
A wxPython rapid development tool for EPICS databases and MEDM display files. This program supports the use of EPICS' run-time programmability to prototype EPICS databases, using records loaded into an IOC. It's particularly useful with synApps "userCalcs", a collection of various record types intended for end users to program at run time.

Appendix: Device support in or distributed with synApps (including support from EPICS base)

recordbus-typecodenameDTYP name
aai CONSTANT devAaiSoft Soft Channel
aai INST_IO devaaiStream stream
aao CONSTANT devAaoSoft Soft Channel
aao INST_IO devaaoStream stream
acalcout CONSTANT devaCalcoutSoft Soft Channel
ai AB_IO devAiAb1771Ife0to5V AB-1771IFE-0to5Volt
ai AB_IO devAiAb1771Ife AB-1771IFE
ai AB_IO devAiAb1771IfeMa AB-1771IFE-4to20MA
ai AB_IO devAiAb1771IfeSe AB-1771IFE-SE
ai AB_IO devAiAb1771Il AB-1771IL-Analog In
ai AB_IO devAiAb1771IrCopper AB-1771RTD-Copper
ai AB_IO devAiAb1771IrPlatinum AB-1771RTD-Platinum
ai AB_IO devAiAb1771Ixe AB-1771IXE-Millivolt In
ai AB_IO devAiAbSlcDcm AB-SLC500DCM
ai AB_IO devAiAbSlcDcmSigned AB-SLC500DCM-Signed
ai BBGPIB_IO devAiAX301 PZT Bug
ai CONSTANT devAiSoftRaw Raw Soft Channel
ai CONSTANT devAiSoft Soft Channel
ai CONSTANT devAiTodSeconds Sec Past Epoch
ai CONSTANT devAiTodSeconds Sec Past Epoch
ai GPIB_IO devAidg535 dg535
ai GPIB_IO devAiGP307Gpib Vg307 GPIB Instrument
ai GPIB_IO devAiHeidAWE1024 Heidenhein Encoder
ai GPIB_IO devAiKeithleyDMM199 KeithleyDMM199
ai GPIB_IO devAiTestGpib GPIB Test
ai GPIB_IO devGpib GPIB init/report
ai INST_IO asynAiFloat64 asynFloat64
ai INST_IO asynAiFloat64Average asynFloat64Average
ai INST_IO asynAiInt32 asynInt32
ai INST_IO asynAiInt32Average asynInt32Average
ai INST_IO devAiAb1791 Allen Bradley 1791
ai INST_IO devAiAbDcm Ab Dcm
ai INST_IO devAiCan CANbus
ai INST_IO devAiClusts IOC stats clusts
ai INST_IO devAiClusts VX stats clusts
ai INST_IO devAiGeneralTime General Time
ai INST_IO devAiHeidND261 asyn ai HeidND261
ai INST_IO devAiHuberDMC Huber DMC 9200
ai INST_IO devAiMKS HPS SensaVac 937
ai INST_IO devAiMPC asyn MPC
ai INST_IO devAiStats IOC stats
ai INST_IO devAiStats VX stats
ai INST_IO devaiStream stream
ai INST_IO devAiStrParm asyn ai stringParm
ai INST_IO devAiTelevac asyn Televac
ai INST_IO devAiTelevac asyn Televac
ai INST_IO devAiTPG261 asyn TPG261
ai INST_IO devAiTPG261 asyn TPG261
ai INST_IO devInterfaceAI1 InterfaceAI1
ai INST_IO devTimestampAI Soft Timestamp
ai VME_IO devAiA32Vme Generic A32 VME
ai VME_IO devAiAvmeMRD devAvmeMRD
ai VME_IO devAiBunchClkGen APS Bunch Clock
ai VME_IO devAiVaroc ESRF Varoc SSI Encoder Iface
ai VME_IO devIK320Ai Heidenhain IK320
ai VME_IO devIK320GroupAi Heidenhain IK320 Group
ao AB_IO devAoAb1771Ofe AB-1771OFE
ao AB_IO devAoAbSlcDcm AB-SLC500DCM
ao BBGPIB_IO devAoAX301 PZT Bug
ao CONSTANT devAoSoftCallback Async Soft Channel
ao CONSTANT devAoSoftRaw Raw Soft Channel
ao CONSTANT devAoSoft Soft Channel
ao GPIB_IO devAodg535 dg535
ao GPIB_IO devAoHeidAWE1024 Heidenhein Encoder
ao GPIB_IO devAoKeithleyDMM199 KeithleyDMM199
ao GPIB_IO devAoTestGpib GPIB Test
ao INST_IO asynAoFloat64 asynFloat64
ao INST_IO asynAoInt32 asynInt32
ao INST_IO devAoAb1791 Allen Bradley 1791
ao INST_IO devAoAbDcm Ab Dcm
ao INST_IO devAoCan CANbus
ao INST_IO devAoEurotherm asyn ao Eurotherm
ao INST_IO devAoMPC asyn MPC
ao INST_IO devAoStats IOC stats
ao INST_IO devAoStats VX stats
ao INST_IO devaoStream stream
ao INST_IO devAoStrParm asyn ao stringParm
ao INST_IO devAoTPG261 asyn TPG261
ao INST_IO devAoTPG261 asyn TPG261
ao INST_IO devInterfaceAO1 InterfaceAO1
ao VME_IO devAoA32Vme Generic A32 VME
ao VME_IO devAoAvme9210 AVME-9210
ao VME_IO devAoBunchClkGen APS Bunch Clock
ao VME_IO devAoVMI4116 VMIVME-4116
asyn INST_IO asynRecordDevice asynRecordDevice
bi AB_IO devBiAb16 AB-16 bit BI
bi AB_IO devBiAb32 AB-32 bit BI
bi AB_IO devBiAb AB-Binary Input
bi CONSTANT devBiSoftRaw Raw Soft Channel
bi CONSTANT devBiSoft Soft Channel
bi GPIB_IO devBidg535 dg535
bi GPIB_IO devBiGP307Gpib Vg307 GPIB Instrument
bi GPIB_IO devBiHeidAWE1024 Heidenhein Encoder
bi GPIB_IO devBiKeithleyDMM199 KeithleyDMM199
bi GPIB_IO devBiTestGpib GPIB Test
bi INST_IO asynBiInt32 asynInt32
bi INST_IO asynBiUInt32Digital asynUInt32Digital
bi INST_IO devBiAbDcm Ab Dcm
bi INST_IO devBiCan CANbus
bi INST_IO devBiMPC asyn MPC
bi INST_IO devbiStream stream
bi INST_IO devBiStrParm asyn bi stringParm
bi INST_IO devBiTelevac asyn Televac
bi INST_IO devBiTelevac asyn Televac
bi INST_IO devBiTip810 Tip810
bi INST_IO devBiTPG261 asyn TPG261
bi INST_IO devBiTPG261 asyn TPG261
bi VME_IO devBiA32Vme Generic A32 VME
bi VME_IO devBiAvme9440 AVME9440 I
bi VME_IO devBiAvmeMRD devAvmeMRD
bi VME_IO devBiBunchClkGen APS Bunch Clock
bi VME_IO devBiHP10895LaserAxis HP interferometer
bo AB_IO devBoAb16 AB-16 bit BO
bo AB_IO devBoAb32 AB-32 bit BO
bo AB_IO devBoAb AB-Binary Output
bo BBGPIB_IO devBoAX301 PZT Bug
bo CONSTANT devBoSoftCallback Async Soft Channel
bo CONSTANT devBoSoftRaw Raw Soft Channel
bo CONSTANT devBoSoft Soft Channel
bo GPIB_IO devBodg535 dg535
bo GPIB_IO devBoGP307Gpib Vg307 GPIB Instrument
bo GPIB_IO devBoHeidAWE1024 Heidenhein Encoder
bo GPIB_IO devBoKeithleyDMM199 KeithleyDMM199
bo GPIB_IO devBoTestGpib GPIB Test
bo INST_IO asynBoInt32 asynInt32
bo INST_IO asynBoUInt32Digital asynUInt32Digital
bo INST_IO devBoAbDcm Ab Dcm
bo INST_IO devBoCan CANbus
bo INST_IO devBoGeneralTime General Time
bo INST_IO devBoMPC asyn MPC
bo INST_IO devboStream stream
bo INST_IO devBoStrParm asyn bo stringParm
bo INST_IO devBoTPG261 asyn TPG261
bo INST_IO devBoTPG261 asyn TPG261
bo INST_IO softGlueShow softGlueShow
bo VME_IO devBoA32Vme Generic A32 VME
bo VME_IO devBoAvme9440 AVME9440 O
bo VME_IO devBoAvmeMRD devAvmeMRD
bo VME_IO devBoBunchClkGen APS Bunch Clock
bo VME_IO devBoHP10895LaserAxis HP interferometer
busy CONSTANT devBusySoftRaw Raw Soft Channel
busy CONSTANT devBusySoft Soft Channel
busy INST_IO asynBusyInt32 asynInt32
calcout CONSTANT devCalcoutSoftCallback Async Soft Channel
calcout CONSTANT devCalcoutSoft Soft Channel
calcout INST_IO devcalcoutStream stream
digitel INST_IO devDigitelPump asyn DigitelPump
digitel INST_IO devDigitelPump asyn DigitelPump
epid CONSTANT devEpidSoftCB Async Soft Channel
epid CONSTANT devEpidSoft Soft Channel
epid INST_IO devEpidFast Fast Epid
event CONSTANT devEventSoft Soft Channel
longin AB_IO devLiAbSlcDcm AB-SLC500DCM
longin CONSTANT devLiSoft Soft Channel
longin GPIB_IO devLidg535 dg535
longin GPIB_IO devLiHeidAWE1024 Heidenhein Encoder
longin GPIB_IO devLiKeithleyDMM199 KeithleyDMM199
longin GPIB_IO devLiTestGpib GPIB Test
longin INST_IO asynLiInt32 asynInt32
longin INST_IO asynLiUInt32Digital asynUInt32Digital
longin INST_IO devLiAbDcm Ab Dcm
longin INST_IO devLiGeneralTime General Time
longin INST_IO devLiHuberDMC Huber DMC 9200
longin INST_IO devLiStrParm asyn li stringParm
longin INST_IO devlonginStream stream
longin VME_IO devLiA32Vme Generic A32 VME
longin VME_IO devLiAvmeMRD devAvmeMRD
longin VME_IO devLiHP10895LaserAxis HP interferometer
longout AB_IO devLoAbSlcDcm AB-SLC500DCM
longout BBGPIB_IO devLoAX301 PZT Bug
longout CONSTANT devLoSoftCallback Async Soft Channel
longout CONSTANT devLoSoft Soft Channel
longout GPIB_IO devLodg535 dg535
longout GPIB_IO devLoHeidAWE1024 Heidenhein Encoder
longout GPIB_IO devLoKeithleyDMM199 KeithleyDMM199
longout GPIB_IO devLoTestGpib GPIB Test
longout INST_IO asynLoInt32 asynInt32
longout INST_IO asynLoUInt32Digital asynUInt32Digital
longout INST_IO devLoAbDcm Ab Dcm
longout INST_IO devlongoutStream stream
longout INST_IO devLoStrParm asyn lo stringParm
longout INST_IO softGlueSigNum softGlueSigNum
longout VME_IO devLoA32Vme Generic A32 VME
longout VME_IO devLoHP10895LaserAxis HP interferometer
mbbi AB_IO devMbbiAb16 AB-16 bit BI
mbbi AB_IO devMbbiAb32 AB-32 bit BI
mbbi AB_IO devMbbiAb AB-Binary Input
mbbi AB_IO devMbbiAbAdapterStat AB-Adapter Status
mbbi AB_IO devMbbiAbCardStat AB-Card Status
mbbi CONSTANT devMbbiSoftRaw Raw Soft Channel
mbbi CONSTANT devMbbiSoft Soft Channel
mbbiDirect AB_IO devMbbiDirectAb16 AB-16 bit BI
mbbiDirect AB_IO devMbbiDirectAb32 AB-32 bit BI
mbbiDirect AB_IO devMbbiDirectAb AB-Binary Input
mbbiDirect CONSTANT devMbbiDirectSoftRaw Raw Soft Channel
mbbiDirect CONSTANT devMbbiDirectSoft Soft Channel
mbbiDirect INST_IO asynMbbiDirectUInt32Digital asynUInt32Digital
mbbiDirect INST_IO devMbbiDirectCan CANbus
mbbiDirect INST_IO devmbbiDirectStream stream
mbbi GPIB_IO devMbbidg535 dg535
mbbi GPIB_IO devMbbiHeidAWE1024 Heidenhein Encoder
mbbi GPIB_IO devMbbiKeithleyDMM199 KeithleyDMM199
mbbi GPIB_IO devMbbiTestGpib GPIB Test
mbbi INST_IO asynMbbiInt32 asynInt32
mbbi INST_IO asynMbbiUInt32Digital asynUInt32Digital
mbbi INST_IO devMbbiAbDcm Ab Dcm
mbbi INST_IO devMbbiCan CANbus
mbbi INST_IO devmbbiStream stream
mbbi INST_IO devMbbiTPG261 asyn TPG261
mbbi INST_IO devMbbiTPG261 asyn TPG261
mbbi VME_IO devMbbiA32Vme Generic A32 VME
mbbi VME_IO devMbbiAvme9440 AVME9440 I
mbbi VME_IO devMbbiAvmeMRD devAvmeMRD
mbbi VME_IO devMbbiHP10895LaserAxis HP interferometer
mbbo AB_IO devMbboAb16 AB-16 bit BO
mbbo AB_IO devMbboAb32 AB-32 bit BO
mbbo AB_IO devMbboAb AB-Binary Output
mbbo CONSTANT devMbboSoftCallback Async Soft Channel
mbbo CONSTANT devMbboSoftRaw Raw Soft Channel
mbbo CONSTANT devMbboSoft Soft Channel
mbboDirect AB_IO devMbboDirectAb16 AB-16 bit BO
mbboDirect AB_IO devMbboDirectAb32 AB-32 bit BO
mbboDirect AB_IO devMbboDirectAb AB-Binary Output
mbboDirect CONSTANT devMbboDirectSoftCallback Async Soft Channel
mbboDirect CONSTANT devMbboDirectSoftRaw Raw Soft Channel
mbboDirect CONSTANT devMbboDirectSoft Soft Channel
mbboDirect INST_IO asynMbboDirectUInt32Digital asynUInt32Digital
mbboDirect INST_IO devMbboDirectCan CANbus
mbboDirect INST_IO devmbboDirectStream stream
mbbo GPIB_IO devMbbodg535 dg535
mbbo GPIB_IO devMbboHeidAWE1024 Heidenhein Encoder
mbbo GPIB_IO devMbboKeithleyDMM199 KeithleyDMM199
mbbo GPIB_IO devMbboTestGpib GPIB Test
mbbo INST_IO asynMbboInt32 asynInt32
mbbo INST_IO asynMbboUInt32Digital asynUInt32Digital
mbbo INST_IO devMbboAbDcm Ab Dcm
mbbo INST_IO devMbboCan CANbus
mbbo INST_IO devMbboMPC asyn MPC
mbbo INST_IO devmbboStream stream
mbbo INST_IO devMbboTPG261 asyn TPG261
mbbo INST_IO devMbboTPG261 asyn TPG261
mbbo VME_IO devIK320Dir Heidenhain IK320 Sign
mbbo VME_IO devIK320Funct Heidenhain IK320 Command
mbbo VME_IO devIK320ModeX3 Heidenhain IK320 X3 Mode
mbbo VME_IO devMbboA32Vme Generic A32 VME
mbbo VME_IO devMbboAvme9440 AVME9440 O
mbbo VME_IO devMbboHP10895LaserAxis HP interferometer
mca CONSTANT devMCA_soft Soft Channel
mca INST_IO devMcaAsyn asynMCA
motor CONSTANT devMotorSoft Soft Channel
motor INST_IO devMotorAsyn asynMotor
motor VME_IO devE500 E500
motor VME_IO devEMC18011 EMC18011
motor VME_IO devESP300 ESP300
motor VME_IO devIM483PL IM483PL
motor VME_IO devIM483SM IM483SM
motor VME_IO devMAXv OMS MAXv
motor VME_IO devMCB4B ACS MCB-4B
motor VME_IO devMCDC2805 MCDC2805
motor VME_IO devMDrive MDrive
motor VME_IO devMDT695 MDT695
motor VME_IO devMicos Micos MoCo
motor VME_IO devMM3000 MM3000
motor VME_IO devMM4000 MM4000
motor VME_IO devMotorSim Motor Simulation
motor VME_IO devMVP2001 MVP2001
motor VME_IO devOms58 OMS VME58
motor VME_IO devOMS OMS VME8/44
motor VME_IO devOmsPC68 OMS PC68/78
motor VME_IO devPC6K PC6K
motor VME_IO devPIasyn PI Motor GCS2
motor VME_IO devPIC630 PI C630
motor VME_IO devPIC662 PIC662
motor VME_IO devPIC663 PIC663
motor VME_IO devPIC844 PIC844
motor VME_IO devPIC848 PIC848
motor VME_IO devPIC862 PIC862
motor VME_IO devPIE516 PIE516
motor VME_IO devPIE710 PIE710
motor VME_IO devPIE816 PIE816
motor VME_IO devPIJEDS PIJEDS
motor VME_IO devPM304 Mclennan PM304
motor VME_IO devPM500 PM500
motor VME_IO devPmac PMAC
motor VME_IO devPMNC87xx PMNC87xx
motor VME_IO devSC800 SC-800
motor VME_IO devSmartMotor SmartMotor
motor VME_IO devSoloist Soloist
motor VME_IO devSPiiPlus SPiiPlus
scalcout CONSTANT devsCalcoutSoft Soft Channel
scalcout INST_IO devscalcoutStream stream
scaler INST_IO devScalerAsyn Asyn Scaler
scaler VME_IO devScalerCamac CAMAC scaler
scaler VME_IO devScaler Joerger VSC8/16
scaler VME_IO devScaler_VS Joerger VS
steppermotor AB_IO devSmAB1746Hstp1 Allen Bradley 1746-HTSP1
stringin CONSTANT devSiSoft Soft Channel
stringin CONSTANT devSiTodString Time of Day
stringin CONSTANT devSiTodString Time of Day
stringin GPIB_IO devSidg535 dg535
stringin GPIB_IO devSiGP307Gpib Vg307 GPIB Instrument
stringin GPIB_IO devSiHeidAWE1024 Heidenhein Encoder
stringin GPIB_IO devSiKeithleyDMM199 KeithleyDMM199
stringin GPIB_IO devSiTestGpib GPIB Test
stringin INST_IO asynSiOctetCmdResponse asynOctetCmdResponse
stringin INST_IO asynSiOctetRead asynOctetRead
stringin INST_IO asynSiOctetWriteRead asynOctetWriteRead
stringin INST_IO devSiGeneralTime General Time
stringin INST_IO devSiHuberDMC Huber DMC 9200
stringin INST_IO devSiMPC asyn MPC
stringin INST_IO devSiStrParm asyn si stringParm
stringin INST_IO devSiTPG261 asyn TPG261
stringin INST_IO devSiTPG261 asyn TPG261
stringin INST_IO devSiWiener CANbus
stringin INST_IO devStringinEnvVar IOC env var
stringin INST_IO devStringinEpics IOC epics var
stringin INST_IO devStringinStats IOC stats
stringin INST_IO devStringinStats VX stats
stringin INST_IO devstringinStream stream
stringin INST_IO devTestBlockInp testBlock
stringin INST_IO devTimestampSI Soft Timestamp
stringout CONSTANT devSoSoftCallback Async Soft Channel
stringout CONSTANT devSoSoft Soft Channel
stringout GPIB_IO devSodg535 dg535
stringout GPIB_IO devSoHeidAWE1024 Heidenhein Encoder
stringout GPIB_IO devSoKeithleyDMM199 KeithleyDMM199
stringout GPIB_IO devSoTestGpib GPIB Test
stringout INST_IO asynSoftGlue softGlue
stringout INST_IO asynSoOctetWrite asynOctetWrite
stringout INST_IO devSoEurotherm asyn so Eurotherm
stringout INST_IO devSoMPC asyn MPC
stringout INST_IO devSoStdio stdio
stringout INST_IO devSoStrParm asyn so stringParm
stringout INST_IO devstringoutStream stream
stringout VME_IO devIK320Parm Heidenhain IK320 Parameter
subArray CONSTANT devSASoft Soft Channel
swait CONSTANT devSWaitIoEvent Soft Channel
vs INST_IO devVacSen asyn VacSen
vs INST_IO devVacSen asyn VacSen
waveform CONSTANT devWfSoft Soft Channel
waveform INST_IO asynFloat32ArrayWfIn asynFloat32ArrayIn
waveform INST_IO asynFloat32ArrayWfOut asynFloat32ArrayOut
waveform INST_IO asynFloat64ArrayWfIn asynFloat64ArrayIn
waveform INST_IO asynFloat64ArrayWfOut asynFloat64ArrayOut
waveform INST_IO asynFloat64TimeSeries asynFloat64TimeSeries
waveform INST_IO asynInt16ArrayWfIn asynInt16ArrayIn
waveform INST_IO asynInt16ArrayWfOut asynInt16ArrayOut
waveform INST_IO asynInt32ArrayWfIn asynInt32ArrayIn
waveform INST_IO asynInt32ArrayWfOut asynInt32ArrayOut
waveform INST_IO asynInt32TimeSeries asynInt32TimeSeries
waveform INST_IO asynInt8ArrayWfIn asynInt8ArrayIn
waveform INST_IO asynInt8ArrayWfOut asynInt8ArrayOut
waveform INST_IO asynWfOctetCmdResponse asynOctetCmdResponse
waveform INST_IO asynWfOctetRead asynOctetRead
waveform INST_IO asynWfOctetWrite asynOctetWrite
waveform INST_IO asynWfOctetWriteRead asynOctetWriteRead
waveform INST_IO devwaveformStream stream
waveform VME_IO devWfBunchClkGen APS Bunch Clock

Suggestions and Comments to:
Tim Mooney : (mooney@aps.anl.gov)
Software Services Group
Advanced Photon Source, Argonne National Laboratory