diff --git a/documentation/pilatusDoc.html b/documentation/pilatusDoc.html index e94ca31..8c66356 100755 --- a/documentation/pilatusDoc.html +++ b/documentation/pilatusDoc.html @@ -1,941 +1,945 @@ - - - areaDetector Pilatus driver - - -
-

- areaDetector Pilatus driver

-

- September 21, 2008

-

- Mark Rivers

-

- University of Chicago

-
-

- Table of Contents

- -

- Introduction

-

- This is a driver for the Pilatus pixel array detectors - Dectris. It inherits from ADDriver and implements many of the parameters in - ADStdDriverParams.h. It also implements a number of parameters that are specific - to the Pilatus detectors.

-

- The interface to the detector is via a TCP/IP socket interface to the camserver - server that Dectris provides. The camserver program must be started before the areaDetector - software is started, typically by running the camonly script provided by - Dectris. -

-

- The camserver program saves the data to disk as TIFF files. The areaDetector software - reads these disk files in order to read the data, because camserver does not provide - another mechanism to access the data. -

-

- Implementation of standard driver parameters

-

- The following table describes how the Pilatus driver implements some of the standard - driver parameters. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Parameter Definitions in pilatusDetector.cpp and EPICS Record Definitions in pilatus.template
- Enum name - EPICS record name - Description
- ADTriggerMode - $(P$(R)TriggerMode - The driver redefines the choices for the ADTriggerMode parameter (record $(P)$(R)TriggerMode) - from ADStdDriverParams.h. The choices for the Pilatus are: -
    -
  • Internal (external signal not used)
  • -
  • External Enable (count while external trigger line is high, readout on high to - low transition)
  • -
  • External Trigger (begin acquisition sequence on high to low transition of external - trigger line)
  • -
  • Multiple External Trigger (high to low transition on external signal triggers - a single acquisition for the programmed exposure time)
  • -
  • Alignment (collect images as fast as exposure time and readout permit, images - written to a temporary file)
  • -
- The first 4 modes correspond directly to the camserver commands Exposure, - ExtEnable, ExtTrigger, and ExtMTrigger respectively. - Alignment mode uses the Exposure command as well, but continuously - takes images into the same temporary file (alignment.tif). -
- ADExposureTime - $(P$(R)ExposureTime - In External Enable mode this value is not used by camserver. However, it should - be set larger than the maximum time exposure time from the external source, so that - pilatusROI.st can estimate how long to wait for the data files to be created before - timing out.
- ADNumImages - $(P$(R)NumImages - Controls the number of images to acquire. It applies in all trigger modes except - Alignment.
- ADExposurePeriod - $(P$(R)ExposurePeriod - Controls the exposure period in seconds. It applies only in Internal or External - Trigger modes when NumImages > 1.
- ADNumExposures - $(P$(R)NumExposures - Controls the number of exposures per image. It is only used in External Enable mode.
- ADAquire - $(P$(R)Acquire - Controls the acquisition. Setting this to 1 starts image acquisition. The driver - sets the record to 0 when acquisition is complete. This means an entire acquisition - series if NImages > 1. Setting this to 0 aborts an acquisition. If the driver - was currently acquiring imges then this record will cause the "Stop" and "K" (Kill) - commands to be sent to camserver.
- ADFilePath - $(P$(R)FilePath - Controls the path for saving images. It must be a valid path for camserver and - for the areaDetector driver, which is normally running in an EPICS IOC. If camserver - and the EPICS IOC are not running on the same machine then soft links will typically - be used to make the paths look identical.
- ADFileFormat - $(P)$(R)FileFormat - camserver uses the file extension to determine what format to save the files in. - The areaDetector Pilatus driver only supports TIFF files, so the extension should - be .tif. When saving multiple images (NImages>1) camserver has its own rules for - creating the names of the individual files. The rules are as follows. The name constructed - using the algorithm described for ADFileTemplate under - File Saving Parameters in ADStdDriverParams is used as a basename. The following - examples show the interpretation of the basename. -
-Basename            Files produced
-     
-test6.tif           test6_00000.tif,  test6_00001.tif, ...
-test6_.tif          test6_00000.tif,  test6_00001.tif, ...
-test6_000.tif       test6_000.tif,    test6_001.tif, ...
-test6_014.tif       test6_014.tif,    test6_015.tif, ...
-test6_0008.tif      test6_0008.tif,   test6_0009.tif, ...
-test6_2_0035.tif    test6_2_0035.tif, test6_2_0036.tif, ...
-      
- The numbers following the last '_' are taken as a format template, and as a start - value. The minimum format is 3; there is no maximum; the default is 5. The format - is also constrained by the requested number of images.
-

- It is useful to use NDPluginROI to define an ROI containing the entire Pilatus detector. - The MaxValue_RBV PV in this ROI can be monitored to make sure that the 20-bit limit - of 1,048,575 is not being approached in any pixel. -

-

- Pilatus specific parameters

-

- The Pilatus driver implements the following parameters in addition to those in ADStdDriverParams.h: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Parameter Definitions in pilatusDetector.cpp and EPICS Record Definitions in pilatus.template
- Enum name - asyn interface - Access - Description - drvUser string - EPICS record name - EPICS record type
- PilatusDelayTime - asynFloat64 - r/w - Delay in seconds between the external trigger and the start of image acquisition. - It only applies in External Trigger mode - DELAY_TIME - $(P)$(R)DelayTime - ao
- PilatusThreshold - asynFloat64 - r/w - Threshold energy in keV - THRESHOLD - $(P)$(R)ThresholdEnergy - ao
- N/A - N/A - r/w - Gain menu. Controls the value of Vrf, which determines the shaping time and gain - of the input amplifiers. The allowed values are: -
    -
  • 0 ("Fast/Low") Fastest shaping time (~125ns) and lowest gain.
  • -
  • 1 ("Medium/Medium") Medium shaping time (~200 ns) and medium gain.
  • -
  • 2 ("Slow/High") Slow shaping time (~400 ns) and high gain.
  • -
  • 3 ("Slow/Ultrahigh") Slowest peaking time (? ns) and highest gain.
  • -
-
- N/A - $(P)$(R)GainMenu - mbbo
- PilatusArmed - asynInt32 - r/o - Flag to indicate when the Pilatus is ready to accept external trigger signals (0=not - ready, 1=ready). This should be used by clients to indicate when it is OK to start - sending trigger pulses to the Pilatus. If pulses are send before Armed=1 then the - Pilatus may miss them, leading to DMA timeout errors from camserver - ARMED - $(P)$(R)Armed - bi
- PilatusTiffTimeout - asynFloat64 - r/w - Timeout in seconds when reading a TIFF file. It should be set to several seconds, - because there can be delays for various reasons. One reason is that there is sometimes - a delay between when an External Enable acquisition is started and when the first - external pulse occurs. Another is that it can take some time for camserver processes - to finish writing the files. - TIFF_TIMEOUT - $(P)$(R)ReadTiffTimeout - ao
- PilatusBadPixelFile - asynOctet - r/w - Name of a file to be used to replace bad pixels. If this record does not point to - a valid bad pixel file then no bad pixel mapping is performed. The bad pixel map - is used before making the NDArray callbacks. It does not modify the data in the - files that camserver writes. This is a simple ASCII file with the following format: -
-badX1,badY1 replacementX1,replacementY1 
-badX2,badY2 replacementX2,replacementY2
-...
-          
- The X and Y coordinates range from 0 to NXPixels-1 and NYPixels-1. Up to 100 bad - pixels can be defined. The bad pixel mapping simply replaces the bad pixels with - another pixel's value. It does not do any averaging. It is felt that this is sufficient - for the purpose for which this driver was written, namely fast on-line viewing of - ROIs and image data. More sophisticated algorithms can be used for offline analysis - of the image files themselves. The following is an example bad pixel file for a - GSECARS detector: -
          
-263,3   262,3
-264,3   266,3
-263,3   266,3
-300,85  299,85
-300,86  299,86
-471,129 472,129
-          
-
- BAD_PIXEL_FILE - $(P)$(R)BadPixelFile - waveform
- PilatusNumBadPixels - asynInt32 - r/o - The number of bad pixels defined in the bad pixel file. Useful for seeing if the - bad pixel file was read correctly. - NUM_BAD_PIXELS - $(P)$(R)NumBadPixels - longin
- PilatusFlatFieldFile - asynOctet - r/w - Name of a file to be used to correct for the flat field. If this record does not - point to a valid flat field file then no flat field correction is performed. The - flat field file is simply a TIFF file collected by the Pilatus that is used to correct - for spatial non-uniformity in the response of the detector. It should be collected - with a spatially uniform intensity on the detector at roughly the same energy as - the measurements being corrected. When the flat field file is read, the average - pixel value (averageFlatField) is computed using all pixels with intensities > PilatusMinFlatField. - All pixels with intensity < PilatusMinFlatField in the flat field are replaced with - averageFlatField. When images are collected before the NDArray callbacks are performed - the following per-pixel correction is applied: -
-ImageData[i] = (averageFlatField * ImageData[i])/flatField[i];
-          
-
- FLAT_FIELD_FILE - $(P)$(R)FlatFieldFile - waveform
- PilatusMinFlatField - asynInt32 - r/w - The mimimum valid intensity in the flat field. This value must be set > 0 to prevent - divide by 0 errors. If the flat field was collected with some pixels having very - low intensity then this value can be used to replace those pixels with the average - response. - MIN_FLAT_FIELD - $(P)$(R)MinFlatField - longout
- PilatusFlatFieldValid - asynInt32 - r/o - This record indicates if a valid flat field file has been read. 0=No, 1=Yes. - FLAT_FIELD_VALID - $(P)$(R)FlatFieldValid - bi
- N/A - N/A - N/A - asyn record to control debugging communication with camserver. Setting the CNCT - field in this record to Disconnect causes the drvAsynIPPort server - to disconnect from camserver. This can be used to allow another program, such as - TVX, to temporarily take control of camserver, without restarting the EPICS IOC. - Set CNCT to Connect to reconnect the IOC to camserver, or simply process - any record which communicates with camserver, because the driver will automatically - reconnect. - N/A - $(P)$(R)CamserverAsyn - asyn
-

- Configuration

-

- The Pilatus driver is created with the following command, either from C/C++ or from - the EPICS IOC shell. -

-
   
-pilatusDetectorConfig(const char *portName, const char *camserverPort, 
-                      int maxSizeX, int maxSizeY, int maxBuffers, size_t maxMemory);
-  
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Argument - Description
- portName - The name of the asyn port for this detector. -
- camserverPort - The name of the asyn TCP/IP port to communicate with camserver. This must have been - previously created with drvAsynIPPortConfig(), -
- maxSizeX - The number of pixels in the X direction on the detector. This is 487 for the Pilatus - 100K.
- maxSizeY - The number of pixels in the Y direction on the detector. This is 195 for the Pilatus - 100K.
- maxBuffers - Maximum number of buffers to be created for plugin callbacks. Passed to the constructor - for the ADDriver base class.
- maxMemory - Maximum number of bytes of memory to be allocated for plugin callbacks. Passed to - the constructor for the ADDriver base class.
-

- The following is an example st.cmd startup script: -

-
< envPaths
-errlogInit(20000)
-
-dbLoadDatabase("$(AREA_DETECTOR)/dbd/pilatusDetectorApp.dbd")
-pilatusDetectorApp_registerRecordDeviceDriver(pdbbase) 
-
-###
-# Create the asyn port to talk to the Pilatus on port 41234.
-drvAsynIPPortConfigure("camserver","gse-pilatus2:41234")
-# Set the input and output terminators.
-asynOctetSetInputEos("camserver", 0, "\030")
-asynOctetSetOutputEos("camserver", 0, "\n")
-
-pilatusDetectorConfig("Pil", "camserver", 487, 195, 50, 200000000)
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/ADBase.template",   "P=13PIL1:,R=cam1:,PORT=Pil,ADDR=0,TIMEOUT=1")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/pilatus.template","P=13PIL1:,R=cam1:,PORT=Pil,ADDR=0,TIMEOUT=1,CAMSERVER_PORT=camserver")
-
-# Create a standard arrays plugin
-drvNDStdArraysConfigure("PilImage", 5, 0, "Pil", 0, -1)
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDPluginBase.template","P=13PIL1:,R=image1:,PORT=PilImage,ADDR=0,TIMEOUT=1,NDARRAY_PORT=Pil,NDARRAY_ADDR=0")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDStdArrays.template", "P=13PIL1:,R=image1:,PORT=PilImage,ADDR=0,TIMEOUT=1,SIZE=32,FTVL=LONG,NELEMENTS=94965")
-
-# Create an ROI plugin with 8 ROIs
-drvNDROIConfigure("PilROI", 5, 0, "Pil", 0, 8, -1)
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDPluginBase.template","P=13PIL1:,R=ROI1:,  PORT=PilROI,ADDR=0,TIMEOUT=1,NDARRAY_PORT=Pil,NDARRAY_ADDR=0")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROI.template",       "P=13PIL1:,R=ROI1:,  PORT=PilROI,ADDR=0,TIMEOUT=1")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:0:,PORT=PilROI,ADDR=0,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:1:,PORT=PilROI,ADDR=1,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:2:,PORT=PilROI,ADDR=2,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:3:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:4:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:5:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:6:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
-dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:7:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
-
-# Create "fastSweep" drivers for the MCA record to do on-the-fly scanning of ROI data
-initFastSweep("PilSweepTotal", "PilROI", 8, 2048, "TOTAL_ARRAY", "CALLBACK_PERIOD")
-initFastSweep("PilSweepNet", "PilROI", 8, 2048, "NET_ARRAY", "CALLBACK_PERIOD")
-
-# Load MCA records for the fast sweep drivers
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:0:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 0)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:1:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 1)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:2:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 2)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:3:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 3)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:4:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 4)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:5:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 5)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:6:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 6)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:7:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 7)")
-
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:0:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 0)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:1:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 1)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:2:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 2)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:3:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 3)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:4:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 4)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:5:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 5)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:6:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 6)")
-dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:7:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 7)")
-
-
-#asynSetTraceMask("Pil",0,255)
-#asynSetTraceMask("PilROI",0,3)
-#asynSetTraceIOMask("PilROI",0,4)
-
-# Load scan records for scanning energy threshold
-dbLoadRecords("$(SSCAN)/sscanApp/Db/scan.db", "P=13PIL1:cam1:,MAXPTS1=2000,MAXPTS2=200,MAXPTS3=20,MAXPTS4=10,MAXPTSH=10")
-
-set_requestfile_path("./")
-set_savefile_path("./autosave")
-set_requestfile_path("$(AREA_DETECTOR)/ADApp/Db")
-set_requestfile_path("$(SSCAN)/sscanApp/Db")
-set_pass0_restoreFile("auto_settings.sav")
-set_pass1_restoreFile("auto_settings.sav")
-save_restoreSet_status_prefix("13PIL1:")
-dbLoadRecords("$(AUTOSAVE)/asApp/Db/save_restoreStatus.db", "P=13PIL1:")
-
-iocInit()
-
-# save things every thirty seconds
-create_monitor_set("auto_settings.req", 30,"P=13PIL1:,D=cam1:")
-
-
-

- MEDM screens

-

- The following show the MEDM screens that are used to control the Pilatus debtector. - Note that the general purpose screen ADBase.adl can be used, but it exposes many - controls that are not applicable to the Pilatus.

-

- pilatusDetector.adl is the main screen used to control the Pilatus - driver. All records except those for ROIs are accessed through this screen. -

-
-

- pilatusDetector.adl

- pilatusDetector.png
-

- NDROI8.adl is used to define the ROIs, and to display the statistics - for each ROI. In this example there are 3 valid ROIs defined. ROI 0 is the entire - detector, ROI 1 is a 100x50 rectangle starting at [300,60], and ROI 2 is a 50x30 - rectangle starting at [320,70].

-
-

- NDROI8.adl

- NDROI8.png
-

- mca.adl can be used to plot the net or total counts in an ROI when - NImages>1. In this example the plot is the net counts in ROI 1 as the diffractometer - chi was scanned +- 1 degree with 1000 points at .02 seconds/point. This was done - with the SPEC command -

-
lup chi -1 1 1000 .02
-
-

- using trajectory scanning on a Newport kappa diffractometer. This was a compound - motor scan with the Newport XPS putting out pulses every .02 seconds. These pulses - triggered the Pilatus in External Enable mode. The Pilatus driver read each TIFF - file as it was created and updated this plot every 0.2 seconds. The total time to - collect this scan with 1000 images was 20 seconds.

-
-

- mca.adl

- pilatusMCA.png
-

- scan_more.adl is used to define a scan. In this example the sscan record - is set up to scan the ThresholdEnergy PV and to collect the total counts in ROI2, - which was defined to include the entire detector.

-
-

- scan_more.adl

- pilatusROI_scan_more.png
-

- scanDetPlot.adl is used to plot the results of a scan after it is complete. - In this example the total counts in ROI 2 are plotted as a function of the ThresholdEnergy - as it was scanned from 3000 to 10000 eV in 250 eV steps. The source was Fe55, and - the cut-off is at 6 keV, as expected for the Mn Ka and Mn Kb x-rays that this source - produces.

-
-

- scanDetPlot.adl

- pilatus_scan_plot.png
-

- asynRecord.adl is used to control the debugging information printed - by the asyn TCP/IP driver (asynTraceIODriver) and the SNL program (asynTraceIODevice).

-
-

- asynRecord.adl

- pilatusAsynRecord.png
-

- asynOctet.adl can be used to send any command to camserver and display - the response. It can be loaded from the More menu in asynRecord.adl above.

-
-

- asynOctet.adl

- pilatusAsynOctet.png
-

- SPEC interface

-

- At the GSECARS beamlines (13-ID-C and 13-BM-C) at the APS we use SPEC to control - our Newport diffractometers. We have added and modified SPEC macros to use the pilatusDetector - areaDetector driver to treat the Pilatus detector as a SPEC counter. This works - in both traditional step-scanning mode, as well as in - trajectory scanning mode. Here are some snippets from the SPEC macros for - the Pilatus. We can supply the source files on request.

-
# need some more globals (kludge)
-global    PILATUS_ROI_PV    
-global    PILATUS_imgPATH_PV
-global    PILATUS_FNAME_PV
-global    PILATUS_FILENUMBER_PV
-global    PILATUS_FILEFORMAT_PV
-global    PILATUS_EXPSRTM_PV
-global    PILATUS_NFRAME_PV
-global    PILATUS_EXPPRD_PV
-global    PILATUS_NEXPFRM_PV
-global    PILATUS_ACQ_PV
-global    PILATUS_ACQMODE_PV
-
-###############################################################
-def _setup_img '{
-     local j, str
-		
-     # PILATUS_PREFIX should be detector aquisition pv (GSE-PILATUS1:)
-     if ( PILATUS_PREFIX == "") PILATUS_PREFIX = "GSE-PILATUS1:"
-     PILATUS_PREFIX = getval("Enter PILATUS pv prefix",PILATUS_PREFIX)
-
-     # rois pvs
-     PILATUS_ROI_PV    = PILATUS_PREFIX "ROI1NetCounts"
-     PILATUS_imgPATH_PV = PILATUS_PREFIX "FilePath"
-     PILATUS_FNAME_PV   = PILATUS_PREFIX "Filename"
-     PILATUS_FILENUMBER_PV   = PILATUS_PREFIX "FileNumber"
-     PILATUS_FILEFORMAT_PV = PILATUS_PREFIX "FileFormat"
-     PILATUS_EXPSRTM_PV = PILATUS_PREFIX "ExposureTime"
-     PILATUS_NFRAME_PV  = PILATUS_PREFIX "NImages"
-     PILATUS_EXPPRD_PV  = PILATUS_PREFIX "ExposurePeriod"
-     PILATUS_NEXPFRM_PV = PILATUS_PREFIX "NExposures"
-     PILATUS_ACQ_PV     = PILATUS_PREFIX "Acquire"
-     PILATUS_ACQMODE_PV = PILATUS_PREFIX "AcquireMode"
-...
-
-def epics_pilatus_count '{
-...
-     # write to data base fields
-     # Need to convert path from string to byte array
-     # Note: we use the "wait" parameter in epics_put here (new to spec5.7.02) so that
-     # it uses ca_put_callback, to know that all PVs have been processed
-     # before we start counting.  Use 1 second timeout, will actually be
-     # much faster than this unless something is wrong.
-     array _temp[256]
-     _temp = PILATUS_IMAGE_DIR
-     # Do not change path for now
-     #epics_put(PILATUS_imgPATH_PV,_temp, 1)
-     epics_put(PILATUS_FNAME_PV,img_fname, 1)
-     epics_put(PILATUS_FILENUMBER_PV,NPTS, 1)
-     epics_put(PILATUS_FILEFORMAT_PV,_fileformat, 1)
-     epics_put(sc_prtm_pv,cnt_time_val, 1)
-     epics_put(PILATUS_EXPSRTM_PV,cnt_time_val, 1)
-     epics_put(PILATUS_ACQMODE_PV,0, 1)  # Internal trigger 
-     epics_put(PILATUS_NFRAME_PV, 1, 1)
-     epics_put(PILATUS_NEXPFRM_PV, 1, 1)
-
-
-def user_getcounts '{
-    local pv_roi, j, pv
-
-...
-   # using image_count routine  
-    } else if ( EPICS_COUNT == 4 ) {
-        S[iroi] = 0
-        S[iroi] = epics_get(PILATUS_ROI_PV)
-
-

- Performance measurements

-

- The following measurements were done to demonstrate the performance that can be - obtained with the areaDetector Pilatus driver.

-
    -
  1. AcquireMode=Internal, NumImages=1000, AcquireTime=.005, AcquirePeriod=.01, NumExposures=1. - The time to collect this series should be exactly 10.0 seconds. The actual time - was measured using the EPICS camonitor program. It printed the time when acquisition - was started (Acquire changed to Acquire=1) and when acquisition was complete (Acquire - changed to Done=0). The time was 10.022 seconds. This includes the time for camserver - to save all 1000 images to disk (366 MB), and for pilatusROI to read each file, - correct the bad pixels and flat field, compute the ROIs, and post the ROIs to EPICS. - It also posted all of the images to EPICS. The total additional time was less than - 0.03 seconds for all 1000 images.
  2. -
  3. AcquireMode=Internal, NImages=1, ExposureTime=.01, NExposures=1. An EPICS sscan - record was used to collect 1000 points. There were no positioner PVs (to eliminate - motor overhead). The only detector trigger was the Pilatus Acquire PV. The only - detector PV was ROI1:0:Total_RBV. In this mode camserver is being told to individually - collect each file. If there were no overhead then time to collect this series should - be exactly 10.0 seconds. The actual time measured using the EPICS camonitor program - was 45.514 seconds. The overhead is thus 35.514 seconds, or 35 ms per point. In - this single-frame mode pilatusROI is thus able to collect >20 images/second. For - comparison, another measurement was done using the same EPICS sscan record, but - using a Joerger VSC16 scaler as the detector trigger and detector. The preset time - was also .01 seconds. The elapsed time for a 1000 point scan was 16.068 seconds, - so the overhead was 6.068 seconds, or 6 ms per point.
  4. -
  5. AcquireMode=Ext. Enable, NImages=1000, NExposures=1. SPEC was used to collect - 1000 points using - trajectory scanning mode with the Newport XPS motor controller. The following - SPEC command was used: -
          lup chi -2 2 1000 .015
    -      
    - This tells SPEC to do a relative scan of the chi axis from -2 degrees to +2 degrees - with 1000 points at .015 seconds/point. On our kappa diffractometer this entails - a coordinated motion of the phi, kappa and omega axes. The EPICS trajectory scanning - software downloads the non-linear trajectory that SPEC computes into the XPS controller, - which executes it. As the motors are moving the XPS outputs synchronization pulses - at the period of the collection time, .015 seconds in this case. These pulses are - stretched (see Hardware notes below) and used as the - external input to the Pilatus. The time to execute this scan should be 15.0 seconds. - The actual time was 16.3 seconds, measured using camonitor on the Acquire PV. Again, - this includes the time for camserver to save all 1000 images to disk (366 MB), and - for pilatusROI to read each file, correct the bad pixels and flat field, compute - the ROIs, and post the ROIs to EPICS. It also posted the images to EPICS at 1Hz - (15 images total). The total additional time was less than 1.3 seconds for all 1000 - images. As soon as the acquisition was complete SPEC plotted the net counts in the - first ROI (containing the Bragg peak) as follows: -
    -

    - 1000 point SPEC scan with 15 ms per point collected in 16.3 seconds

    - pilatusROI_spec.png
    -

    -

    - For comparison this identical scan was executed in traditional step-scanning mode, - where the motors stopped at each point in the scan. The Pilatus was run in Internal - mode with NImages=1. The total time for the scan was 870 seconds (more than 14 minutes), - compared to 16.3 seconds in trajectory mode. Most of this overhead is the settling - time for the motors, with only a small fraction due to the Pilatus single-exposure - mode. The trajectory scanning mode is thus more than 50 times faster to execute - the identical SPEC scan.
  6. -
-

-  

-

- Hardware notes

-

- Trigger pulses

-

- The Pilatus supports 3 types of external triggering. In External Trigger mode (the - camserver ExtTrigger command) the Pilatus uses the programmed values of ExposureTime, - ExposurePeriod, NImages and NExposures. It waits for a single external trigger, - then waits for Delay seconds and then collects the entire sequence. It is very similar - to Internal mode with NImages>1, except that it waits for a trigger to begin collecting - the sequence.

-

- In External Enable mode (the camserver ExtEnable command) the Pilatus uses the external - signal to control acquisition. Only NImages and NExposures are used, ExposureTime - and ExposurePeriod are not used. When the signal is high the detector counts, and - on the transition to low it begins its readout.

-

- In External MultiTrigger Mode (the camserver ExtMTrigger command) the Pilatus uses - the programmed ExposureTime, in addition to NImages and NExposures. Each external - trigger pulse causes the Pilatus to collect one image at the programmed exposure - time. This mode works well with a trigger source like the Newport motor controllers - or the SIS380x multichannel scaler, that put out a short trigger pulse for each - image. One only needs to take care that the time between external trigger pulses - is at least 4msec longer than the programmed exposure time, to allow time for the - detector to read out before the next trigger pulse arrives.

-

- When using the External Enable mode, we use an inexpensive analog pulse generator - to convert the trigger pulses from the MM4005 and XPS to a form suitable for External - Enable mode with the Pilatus. This is the solution we have developed that seems - to be reliable:

- -

- The Tenma TGP110 seems to be currently called a Tenma 72-6860, and lists for about - $350 new at Newark. -

-

- Detector Voltage

-

- When we were initially testing the Pilatus in the lab, we had many errors in External - Enable mode, where it did not seem to be seeing the external pulses. camserver would - get DMA timeouts, and need to be restarted. Dectris said these were happening because - the cables on our detector are longer than normal, and the voltage drop from the - power supply to the detector was leading to marginal voltage values. They suggested - shortening the cables or increasing the supply voltage slightly. When moving the - detector to the hutch these problems initially went away. However, they then recurred, - and we fixed the problem by increasing the power supply voltage from 4.4 to 4.7 - volts at the detector.

-

- Dectris has since informed me that they have increased the power supply voltage - on all new Pilatus systems, so this should no longer be an issue.

-

- Restrictions

-

- The following are some current restrictions of the pilatusROI SNL program:

- - - + + + areaDetector Pilatus driver + + +
+

+ areaDetector Pilatus driver

+

+ September 21, 2008

+

+ Mark Rivers

+

+ University of Chicago

+
+

+ Table of Contents

+ +

+ Introduction

+

+ This is a driver for the Pilatus pixel array detectors + Dectris. It inherits from ADDriver and implements many of the parameters in + ADStdDriverParams.h. It also implements a number of parameters that are specific + to the Pilatus detectors.

+

+ The interface to the detector is via a TCP/IP socket interface to the camserver + server that Dectris provides. The camserver program must be started before the areaDetector + software is started, typically by running the camonly script provided by + Dectris. +

+

+ The camserver program saves the data to disk as TIFF files. The areaDetector software + reads these disk files in order to read the data, because camserver does not provide + another mechanism to access the data. +

+

+ Implementation of standard driver parameters

+

+ The following table describes how the Pilatus driver implements some of the standard + driver parameters. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Parameter Definitions in pilatusDetector.cpp and EPICS Record Definitions in pilatus.template
+ Enum name + EPICS record name + Description
+ ADTriggerMode + $(P$(R)TriggerMode + The driver redefines the choices for the ADTriggerMode parameter (record $(P)$(R)TriggerMode) + from ADStdDriverParams.h. The choices for the Pilatus are: +
    +
  • Internal (external signal not used)
  • +
  • External Enable (count while external trigger line is high, readout on high to + low transition)
  • +
  • External Trigger (begin acquisition sequence on high to low transition of external + trigger line)
  • +
  • Multiple External Trigger (high to low transition on external signal triggers + a single acquisition for the programmed exposure time)
  • +
  • Alignment (collect images as fast as exposure time and readout permit, images + written to a temporary file)
  • +
+ The first 4 modes correspond directly to the camserver commands Exposure, + ExtEnable, ExtTrigger, and ExtMTrigger respectively. + Alignment mode uses the Exposure command as well, but continuously + takes images into the same temporary file (alignment.tif). +
+ ADExposureTime + $(P$(R)ExposureTime + In External Enable mode this value is not used by camserver. However, it should + be set larger than the maximum time exposure time from the external source, so that + pilatusROI.st can estimate how long to wait for the data files to be created before + timing out.
+ ADNumImages + $(P$(R)NumImages + Controls the number of images to acquire. It applies in all trigger modes except + Alignment.
+ ADExposurePeriod + $(P$(R)ExposurePeriod + Controls the exposure period in seconds. It applies only in Internal or External + Trigger modes when NumImages > 1.
+ ADNumExposures + $(P$(R)NumExposures + Controls the number of exposures per image. It is only used in External Enable mode.
+ ADAquire + $(P$(R)Acquire + Controls the acquisition. Setting this to 1 starts image acquisition. The driver + sets the record to 0 when acquisition is complete. This means an entire acquisition + series if NImages > 1. Setting this to 0 aborts an acquisition. If the driver + was currently acquiring imges then this record will cause the "Stop" and "K" (Kill) + commands to be sent to camserver.
+ ADFilePath + $(P$(R)FilePath + Controls the path for saving images. It must be a valid path for camserver and + for the areaDetector driver, which is normally running in an EPICS IOC. If camserver + and the EPICS IOC are not running on the same machine then soft links will typically + be used to make the paths look identical.
+ ADFileFormat + $(P)$(R)FileFormat + camserver uses the file extension to determine what format to save the files in. + The areaDetector Pilatus driver only supports TIFF files, so the extension should + be .tif. When saving multiple images (NImages>1) camserver has its own rules for + creating the names of the individual files. The rules are as follows. The name constructed + using the algorithm described for ADFileTemplate under + File Saving Parameters in ADStdDriverParams is used as a basename. The following + examples show the interpretation of the basename. +
+Basename            Files produced
+     
+test6.tif           test6_00000.tif,  test6_00001.tif, ...
+test6_.tif          test6_00000.tif,  test6_00001.tif, ...
+test6_000.tif       test6_000.tif,    test6_001.tif, ...
+test6_014.tif       test6_014.tif,    test6_015.tif, ...
+test6_0008.tif      test6_0008.tif,   test6_0009.tif, ...
+test6_2_0035.tif    test6_2_0035.tif, test6_2_0036.tif, ...
+      
+ The numbers following the last '_' are taken as a format template, and as a start + value. The minimum format is 3; there is no maximum; the default is 5. The format + is also constrained by the requested number of images.
+

+ It is useful to use NDPluginROI to define an ROI containing the entire Pilatus detector. + The MaxValue_RBV PV in this ROI can be monitored to make sure that the 20-bit limit + of 1,048,575 is not being approached in any pixel. +

+

+ Pilatus specific parameters

+

+ The Pilatus driver implements the following parameters in addition to those in ADStdDriverParams.h:. + Note that to reduce the width of this table the enum names have been split into + 2 lines, but these are just a single name, for example PilatusDelayTime. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Parameter Definitions in pilatusDetector.cpp and EPICS Record Definitions in pilatus.template
+ Enum name + asyn interface + Access + Description + drvUser string + EPICS record name + EPICS record type
+ Pilatus
DelayTime
+ asynFloat64 + r/w + Delay in seconds between the external trigger and the start of image acquisition. + It only applies in External Trigger mode + DELAY_TIME + $(P)$(R)DelayTime + ao
+ Pilatus
Threshold
+ asynFloat64 + r/w + Threshold energy in keV + THRESHOLD + $(P)$(R)ThresholdEnergy + ao
+ N/A + N/A + r/w + Gain menu. Controls the value of Vrf, which determines the shaping time and gain + of the input amplifiers. The allowed values are: +
    +
  • 0 ("Fast/Low") Fastest shaping time (~125ns) and lowest gain.
  • +
  • 1 ("Medium/Medium") Medium shaping time (~200 ns) and medium gain.
  • +
  • 2 ("Slow/High") Slow shaping time (~400 ns) and high gain.
  • +
  • 3 ("Slow/Ultrahigh") Slowest peaking time (? ns) and highest gain.
  • +
+
+ N/A + $(P)$(R)GainMenu + mbbo
+ Pilatus
Armed
+ asynInt32 + r/o + Flag to indicate when the Pilatus is ready to accept external trigger signals (0=not + ready, 1=ready). This should be used by clients to indicate when it is OK to start + sending trigger pulses to the Pilatus. If pulses are send before Armed=1 then the + Pilatus may miss them, leading to DMA timeout errors from camserver + ARMED + $(P)$(R)Armed + bi
+ Pilatus
TiffTimeout
+ asynFloat64 + r/w + Timeout in seconds when reading a TIFF file. It should be set to several seconds, + because there can be delays for various reasons. One reason is that there is sometimes + a delay between when an External Enable acquisition is started and when the first + external pulse occurs. Another is that it can take some time for camserver processes + to finish writing the files. + TIFF_TIMEOUT + $(P)$(R)ReadTiffTimeout + ao
+ Pilatus
BadPixelFile
+ asynOctet + r/w + Name of a file to be used to replace bad pixels. If this record does not point to + a valid bad pixel file then no bad pixel mapping is performed. The bad pixel map + is used before making the NDArray callbacks. It does not modify the data in the + files that camserver writes. This is a simple ASCII file with the following format: +
+badX1,badY1 replacementX1,replacementY1 
+badX2,badY2 replacementX2,replacementY2
+...
+          
+ The X and Y coordinates range from 0 to NXPixels-1 and NYPixels-1. Up to 100 bad + pixels can be defined. The bad pixel mapping simply replaces the bad pixels with + another pixel's value. It does not do any averaging. It is felt that this is sufficient + for the purpose for which this driver was written, namely fast on-line viewing of + ROIs and image data. More sophisticated algorithms can be used for offline analysis + of the image files themselves. The following is an example bad pixel file for a + GSECARS detector: +
          
+263,3   262,3
+264,3   266,3
+263,3   266,3
+300,85  299,85
+300,86  299,86
+471,129 472,129
+          
+
+ BAD_PIXEL_FILE + $(P)$(R)BadPixelFile + waveform
+ Pilatus
NumBadPixels
+ asynInt32 + r/o + The number of bad pixels defined in the bad pixel file. Useful for seeing if the + bad pixel file was read correctly. + NUM_BAD_PIXELS + $(P)$(R)NumBadPixels + longin
+ Pilatus
FlatFieldFile
+ asynOctet + r/w + Name of a file to be used to correct for the flat field. If this record does not + point to a valid flat field file then no flat field correction is performed. The + flat field file is simply a TIFF file collected by the Pilatus that is used to correct + for spatial non-uniformity in the response of the detector. It should be collected + with a spatially uniform intensity on the detector at roughly the same energy as + the measurements being corrected. When the flat field file is read, the average + pixel value (averageFlatField) is computed using all pixels with intensities > PilatusMinFlatField. + All pixels with intensity < PilatusMinFlatField in the flat field are replaced with + averageFlatField. When images are collected before the NDArray callbacks are performed + the following per-pixel correction is applied: +
+ImageData[i] = 
+    (averageFlatField * 
+    ImageData[i])/flatField[i];
+          
+
+ FLAT_FIELD_FILE + $(P)$(R)FlatFieldFile + waveform
+ Pilatus
MinFlatField
+ asynInt32 + r/w + The mimimum valid intensity in the flat field. This value must be set > 0 to prevent + divide by 0 errors. If the flat field was collected with some pixels having very + low intensity then this value can be used to replace those pixels with the average + response. + MIN_FLAT_FIELD + $(P)$(R)MinFlatField + longout
+ Pilatus
FlatFieldValid
+ asynInt32 + r/o + This record indicates if a valid flat field file has been read. 0=No, 1=Yes. + FLAT_FIELD_VALID + $(P)$(R)FlatFieldValid + bi
+ N/A + N/A + N/A + asyn record to control debugging communication with camserver. Setting the CNCT + field in this record to Disconnect causes the drvAsynIPPort server + to disconnect from camserver. This can be used to allow another program, such as + TVX, to temporarily take control of camserver, without restarting the EPICS IOC. + Set CNCT to Connect to reconnect the IOC to camserver, or simply process + any record which communicates with camserver, because the driver will automatically + reconnect. + N/A + $(P)$(R)CamserverAsyn + asyn
+

+ Configuration

+

+ The Pilatus driver is created with the following command, either from C/C++ or from + the EPICS IOC shell. +

+
   
+pilatusDetectorConfig(const char *portName, const char *camserverPort, 
+                      int maxSizeX, int maxSizeY, int maxBuffers, size_t maxMemory);
+  
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Argument + Description
+ portName + The name of the asyn port for this detector. +
+ camserverPort + The name of the asyn TCP/IP port to communicate with camserver. This must have been + previously created with drvAsynIPPortConfig(), +
+ maxSizeX + The number of pixels in the X direction on the detector. This is 487 for the Pilatus + 100K.
+ maxSizeY + The number of pixels in the Y direction on the detector. This is 195 for the Pilatus + 100K.
+ maxBuffers + Maximum number of buffers to be created for plugin callbacks. Passed to the constructor + for the ADDriver base class.
+ maxMemory + Maximum number of bytes of memory to be allocated for plugin callbacks. Passed to + the constructor for the ADDriver base class.
+

+ The following is an example st.cmd startup script: +

+
< envPaths
+errlogInit(20000)
+
+dbLoadDatabase("$(AREA_DETECTOR)/dbd/pilatusDetectorApp.dbd")
+pilatusDetectorApp_registerRecordDeviceDriver(pdbbase) 
+
+###
+# Create the asyn port to talk to the Pilatus on port 41234.
+drvAsynIPPortConfigure("camserver","gse-pilatus2:41234")
+# Set the input and output terminators.
+asynOctetSetInputEos("camserver", 0, "\030")
+asynOctetSetOutputEos("camserver", 0, "\n")
+
+pilatusDetectorConfig("Pil", "camserver", 487, 195, 50, 200000000)
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/ADBase.template",   "P=13PIL1:,R=cam1:,PORT=Pil,ADDR=0,TIMEOUT=1")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/pilatus.template","P=13PIL1:,R=cam1:,PORT=Pil,ADDR=0,TIMEOUT=1,CAMSERVER_PORT=camserver")
+
+# Create a standard arrays plugin
+drvNDStdArraysConfigure("PilImage", 5, 0, "Pil", 0, -1)
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDPluginBase.template","P=13PIL1:,R=image1:,PORT=PilImage,ADDR=0,TIMEOUT=1,NDARRAY_PORT=Pil,NDARRAY_ADDR=0")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDStdArrays.template", "P=13PIL1:,R=image1:,PORT=PilImage,ADDR=0,TIMEOUT=1,SIZE=32,FTVL=LONG,NELEMENTS=94965")
+
+# Create an ROI plugin with 8 ROIs
+drvNDROIConfigure("PilROI", 5, 0, "Pil", 0, 8, -1)
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDPluginBase.template","P=13PIL1:,R=ROI1:,  PORT=PilROI,ADDR=0,TIMEOUT=1,NDARRAY_PORT=Pil,NDARRAY_ADDR=0")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROI.template",       "P=13PIL1:,R=ROI1:,  PORT=PilROI,ADDR=0,TIMEOUT=1")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:0:,PORT=PilROI,ADDR=0,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:1:,PORT=PilROI,ADDR=1,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:2:,PORT=PilROI,ADDR=2,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:3:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:4:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:5:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:6:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
+dbLoadRecords("$(AREA_DETECTOR)/ADApp/Db/NDROIN.template",      "P=13PIL1:,R=ROI1:7:,PORT=PilROI,ADDR=3,TIMEOUT=1,HIST_SIZE=256")
+
+# Create "fastSweep" drivers for the MCA record to do on-the-fly scanning of ROI data
+initFastSweep("PilSweepTotal", "PilROI", 8, 2048, "TOTAL_ARRAY", "CALLBACK_PERIOD")
+initFastSweep("PilSweepNet", "PilROI", 8, 2048, "NET_ARRAY", "CALLBACK_PERIOD")
+
+# Load MCA records for the fast sweep drivers
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:0:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 0)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:1:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 1)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:2:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 2)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:3:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 3)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:4:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 4)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:5:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 5)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:6:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 6)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:7:TotalArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepTotal 7)")
+
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:0:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 0)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:1:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 1)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:2:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 2)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:3:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 3)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:4:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 4)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:5:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 5)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:6:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 6)")
+dbLoadRecords("$(MCA)/mcaApp/Db/mca.db", "P=13PIL1:,M=ROI1:7:NetArray,DTYP=asynMCA,NCHAN=2048,INP=@asyn(PilSweepNet 7)")
+
+
+#asynSetTraceMask("Pil",0,255)
+#asynSetTraceMask("PilROI",0,3)
+#asynSetTraceIOMask("PilROI",0,4)
+
+# Load scan records for scanning energy threshold
+dbLoadRecords("$(SSCAN)/sscanApp/Db/scan.db", "P=13PIL1:cam1:,MAXPTS1=2000,MAXPTS2=200,MAXPTS3=20,MAXPTS4=10,MAXPTSH=10")
+
+set_requestfile_path("./")
+set_savefile_path("./autosave")
+set_requestfile_path("$(AREA_DETECTOR)/ADApp/Db")
+set_requestfile_path("$(SSCAN)/sscanApp/Db")
+set_pass0_restoreFile("auto_settings.sav")
+set_pass1_restoreFile("auto_settings.sav")
+save_restoreSet_status_prefix("13PIL1:")
+dbLoadRecords("$(AUTOSAVE)/asApp/Db/save_restoreStatus.db", "P=13PIL1:")
+
+iocInit()
+
+# save things every thirty seconds
+create_monitor_set("auto_settings.req", 30,"P=13PIL1:,D=cam1:")
+
+
+

+ MEDM screens

+

+ The following show the MEDM screens that are used to control the Pilatus debtector. + Note that the general purpose screen ADBase.adl can be used, but it exposes many + controls that are not applicable to the Pilatus.

+

+ pilatusDetector.adl is the main screen used to control the Pilatus + driver. All records except those for ROIs are accessed through this screen. +

+
+

+ pilatusDetector.adl

+ pilatusDetector.png
+

+ NDROI8.adl is used to define the ROIs, and to display the statistics + for each ROI. In this example there are 3 valid ROIs defined. ROI 0 is the entire + detector, ROI 1 is a 100x50 rectangle starting at [300,60], and ROI 2 is a 50x30 + rectangle starting at [320,70].

+
+

+ NDROI8.adl

+ NDROI8.png
+

+ mca.adl can be used to plot the net or total counts in an ROI when + NImages>1. In this example the plot is the net counts in ROI 1 as the diffractometer + chi was scanned +- 1 degree with 1000 points at .02 seconds/point. This was done + with the SPEC command +

+
lup chi -1 1 1000 .02
+
+

+ using trajectory scanning on a Newport kappa diffractometer. This was a compound + motor scan with the Newport XPS putting out pulses every .02 seconds. These pulses + triggered the Pilatus in External Enable mode. The Pilatus driver read each TIFF + file as it was created and updated this plot every 0.2 seconds. The total time to + collect this scan with 1000 images was 20 seconds.

+
+

+ mca.adl

+ pilatusMCA.png
+

+ scan_more.adl is used to define a scan. In this example the sscan record + is set up to scan the ThresholdEnergy PV and to collect the total counts in ROI2, + which was defined to include the entire detector.

+
+

+ scan_more.adl

+ pilatusROI_scan_more.png
+

+ scanDetPlot.adl is used to plot the results of a scan after it is complete. + In this example the total counts in ROI 2 are plotted as a function of the ThresholdEnergy + as it was scanned from 3000 to 10000 eV in 250 eV steps. The source was Fe55, and + the cut-off is at 6 keV, as expected for the Mn Ka and Mn Kb x-rays that this source + produces.

+
+

+ scanDetPlot.adl

+ pilatus_scan_plot.png
+

+ asynRecord.adl is used to control the debugging information printed + by the asyn TCP/IP driver (asynTraceIODriver) and the SNL program (asynTraceIODevice).

+
+

+ asynRecord.adl

+ pilatusAsynRecord.png
+

+ asynOctet.adl can be used to send any command to camserver and display + the response. It can be loaded from the More menu in asynRecord.adl above.

+
+

+ asynOctet.adl

+ pilatusAsynOctet.png
+

+ SPEC interface

+

+ At the GSECARS beamlines (13-ID-C and 13-BM-C) at the APS we use SPEC to control + our Newport diffractometers. We have added and modified SPEC macros to use the pilatusDetector + areaDetector driver to treat the Pilatus detector as a SPEC counter. This works + in both traditional step-scanning mode, as well as in + trajectory scanning mode. Here are some snippets from the SPEC macros for + the Pilatus. We can supply the source files on request.

+
# need some more globals (kludge)
+global    PILATUS_ROI_PV    
+global    PILATUS_imgPATH_PV
+global    PILATUS_FNAME_PV
+global    PILATUS_FILENUMBER_PV
+global    PILATUS_FILEFORMAT_PV
+global    PILATUS_EXPSRTM_PV
+global    PILATUS_NFRAME_PV
+global    PILATUS_EXPPRD_PV
+global    PILATUS_NEXPFRM_PV
+global    PILATUS_ACQ_PV
+global    PILATUS_ACQMODE_PV
+
+###############################################################
+def _setup_img '{
+     local j, str
+		
+     # PILATUS_PREFIX should be detector aquisition pv (GSE-PILATUS1:)
+     if ( PILATUS_PREFIX == "") PILATUS_PREFIX = "GSE-PILATUS1:"
+     PILATUS_PREFIX = getval("Enter PILATUS pv prefix",PILATUS_PREFIX)
+
+     # rois pvs
+     PILATUS_ROI_PV    = PILATUS_PREFIX "ROI1NetCounts"
+     PILATUS_imgPATH_PV = PILATUS_PREFIX "FilePath"
+     PILATUS_FNAME_PV   = PILATUS_PREFIX "Filename"
+     PILATUS_FILENUMBER_PV   = PILATUS_PREFIX "FileNumber"
+     PILATUS_FILEFORMAT_PV = PILATUS_PREFIX "FileFormat"
+     PILATUS_EXPSRTM_PV = PILATUS_PREFIX "ExposureTime"
+     PILATUS_NFRAME_PV  = PILATUS_PREFIX "NImages"
+     PILATUS_EXPPRD_PV  = PILATUS_PREFIX "ExposurePeriod"
+     PILATUS_NEXPFRM_PV = PILATUS_PREFIX "NExposures"
+     PILATUS_ACQ_PV     = PILATUS_PREFIX "Acquire"
+     PILATUS_ACQMODE_PV = PILATUS_PREFIX "AcquireMode"
+...
+
+def epics_pilatus_count '{
+...
+     # write to data base fields
+     # Need to convert path from string to byte array
+     # Note: we use the "wait" parameter in epics_put here (new to spec5.7.02) so that
+     # it uses ca_put_callback, to know that all PVs have been processed
+     # before we start counting.  Use 1 second timeout, will actually be
+     # much faster than this unless something is wrong.
+     array _temp[256]
+     _temp = PILATUS_IMAGE_DIR
+     # Do not change path for now
+     #epics_put(PILATUS_imgPATH_PV,_temp, 1)
+     epics_put(PILATUS_FNAME_PV,img_fname, 1)
+     epics_put(PILATUS_FILENUMBER_PV,NPTS, 1)
+     epics_put(PILATUS_FILEFORMAT_PV,_fileformat, 1)
+     epics_put(sc_prtm_pv,cnt_time_val, 1)
+     epics_put(PILATUS_EXPSRTM_PV,cnt_time_val, 1)
+     epics_put(PILATUS_ACQMODE_PV,0, 1)  # Internal trigger 
+     epics_put(PILATUS_NFRAME_PV, 1, 1)
+     epics_put(PILATUS_NEXPFRM_PV, 1, 1)
+
+
+def user_getcounts '{
+    local pv_roi, j, pv
+
+...
+   # using image_count routine  
+    } else if ( EPICS_COUNT == 4 ) {
+        S[iroi] = 0
+        S[iroi] = epics_get(PILATUS_ROI_PV)
+
+

+ Performance measurements

+

+ The following measurements were done to demonstrate the performance that can be + obtained with the areaDetector Pilatus driver.

+
    +
  1. AcquireMode=Internal, NumImages=1000, AcquireTime=.005, AcquirePeriod=.01, NumExposures=1. + The time to collect this series should be exactly 10.0 seconds. The actual time + was measured using the EPICS camonitor program. It printed the time when acquisition + was started (Acquire changed to Acquire=1) and when acquisition was complete (Acquire + changed to Done=0). The time was 10.022 seconds. This includes the time for camserver + to save all 1000 images to disk (366 MB), and for pilatusROI to read each file, + correct the bad pixels and flat field, compute the ROIs, and post the ROIs to EPICS. + It also posted all of the images to EPICS. The total additional time was less than + 0.03 seconds for all 1000 images.
  2. +
  3. AcquireMode=Internal, NImages=1, ExposureTime=.01, NExposures=1. An EPICS sscan + record was used to collect 1000 points. There were no positioner PVs (to eliminate + motor overhead). The only detector trigger was the Pilatus Acquire PV. The only + detector PV was ROI1:0:Total_RBV. In this mode camserver is being told to individually + collect each file. If there were no overhead then time to collect this series should + be exactly 10.0 seconds. The actual time measured using the EPICS camonitor program + was 45.514 seconds. The overhead is thus 35.514 seconds, or 35 ms per point. In + this single-frame mode pilatusROI is thus able to collect >20 images/second. For + comparison, another measurement was done using the same EPICS sscan record, but + using a Joerger VSC16 scaler as the detector trigger and detector. The preset time + was also .01 seconds. The elapsed time for a 1000 point scan was 16.068 seconds, + so the overhead was 6.068 seconds, or 6 ms per point.
  4. +
  5. AcquireMode=Ext. Enable, NImages=1000, NExposures=1. SPEC was used to collect + 1000 points using + trajectory scanning mode with the Newport XPS motor controller. The following + SPEC command was used: +
          lup chi -2 2 1000 .015
    +      
    + This tells SPEC to do a relative scan of the chi axis from -2 degrees to +2 degrees + with 1000 points at .015 seconds/point. On our kappa diffractometer this entails + a coordinated motion of the phi, kappa and omega axes. The EPICS trajectory scanning + software downloads the non-linear trajectory that SPEC computes into the XPS controller, + which executes it. As the motors are moving the XPS outputs synchronization pulses + at the period of the collection time, .015 seconds in this case. These pulses are + stretched (see Hardware notes below) and used as the + external input to the Pilatus. The time to execute this scan should be 15.0 seconds. + The actual time was 16.3 seconds, measured using camonitor on the Acquire PV. Again, + this includes the time for camserver to save all 1000 images to disk (366 MB), and + for pilatusROI to read each file, correct the bad pixels and flat field, compute + the ROIs, and post the ROIs to EPICS. It also posted the images to EPICS at 1Hz + (15 images total). The total additional time was less than 1.3 seconds for all 1000 + images. As soon as the acquisition was complete SPEC plotted the net counts in the + first ROI (containing the Bragg peak) as follows: +
    +

    + 1000 point SPEC scan with 15 ms per point collected in 16.3 seconds

    + pilatusROI_spec.png
    +

    +

    + For comparison this identical scan was executed in traditional step-scanning mode, + where the motors stopped at each point in the scan. The Pilatus was run in Internal + mode with NImages=1. The total time for the scan was 870 seconds (more than 14 minutes), + compared to 16.3 seconds in trajectory mode. Most of this overhead is the settling + time for the motors, with only a small fraction due to the Pilatus single-exposure + mode. The trajectory scanning mode is thus more than 50 times faster to execute + the identical SPEC scan.
  6. +
+

+  

+

+ Hardware notes

+

+ Trigger pulses

+

+ The Pilatus supports 3 types of external triggering. In External Trigger mode (the + camserver ExtTrigger command) the Pilatus uses the programmed values of ExposureTime, + ExposurePeriod, NImages and NExposures. It waits for a single external trigger, + then waits for Delay seconds and then collects the entire sequence. It is very similar + to Internal mode with NImages>1, except that it waits for a trigger to begin collecting + the sequence.

+

+ In External Enable mode (the camserver ExtEnable command) the Pilatus uses the external + signal to control acquisition. Only NImages and NExposures are used, ExposureTime + and ExposurePeriod are not used. When the signal is high the detector counts, and + on the transition to low it begins its readout.

+

+ In External MultiTrigger Mode (the camserver ExtMTrigger command) the Pilatus uses + the programmed ExposureTime, in addition to NImages and NExposures. Each external + trigger pulse causes the Pilatus to collect one image at the programmed exposure + time. This mode works well with a trigger source like the Newport motor controllers + or the SIS380x multichannel scaler, that put out a short trigger pulse for each + image. One only needs to take care that the time between external trigger pulses + is at least 4msec longer than the programmed exposure time, to allow time for the + detector to read out before the next trigger pulse arrives.

+

+ When using the External Enable mode, we use an inexpensive analog pulse generator + to convert the trigger pulses from the MM4005 and XPS to a form suitable for External + Enable mode with the Pilatus. This is the solution we have developed that seems + to be reliable:

+ +

+ The Tenma TGP110 seems to be currently called a Tenma 72-6860, and lists for about + $350 new at Newark. +

+

+ Detector Voltage

+

+ When we were initially testing the Pilatus in the lab, we had many errors in External + Enable mode, where it did not seem to be seeing the external pulses. camserver would + get DMA timeouts, and need to be restarted. Dectris said these were happening because + the cables on our detector are longer than normal, and the voltage drop from the + power supply to the detector was leading to marginal voltage values. They suggested + shortening the cables or increasing the supply voltage slightly. When moving the + detector to the hutch these problems initially went away. However, they then recurred, + and we fixed the problem by increasing the power supply voltage from 4.4 to 4.7 + volts at the detector.

+

+ Dectris has since informed me that they have increased the power supply voltage + on all new Pilatus systems, so this should no longer be an issue.

+

+ Restrictions

+

+ The following are some current restrictions of the pilatusROI SNL program:

+ + + diff --git a/documentation/pluginDoc.html b/documentation/pluginDoc.html index de71034..d3da193 100755 --- a/documentation/pluginDoc.html +++ b/documentation/pluginDoc.html @@ -1,446 +1,448 @@ - - - areaDetector Plugins - - -
-

- areaDetector Plugins

-

- September 20, 2008

-

- Mark Rivers

-

- University of Chicago

-
-

- Contents

- -

- Overview

-

- A powerful feature of the areaDetector module - is the concept of plugins. A plugin is code that is called by a driver that passes - NDArray data in a callback. Plugins can be used to process array data in real time. - Existing plugins convert data to standard asyn arrays (NDPluginStdArrays), save - data to disk (NDPluginFile), and select regions-of-interest (NDPluginROI). New plugins - could be written to perform functions like finding the centroid of a beam, etc. - Once a plugin is written it will work with any areaDetector driver. Plugins have - the the following properties: -

- -

- NDPluginDriver

-

- NDPluginDriver inherits from asynNDArrayDriver. - NDPluginDriver is the class from which actual plugins are directly derived. The - NDPluginDriver class handles most of the details of processing NDArray callbacks - from the driver. Plugins derived from this class typically need to implement the - processCallbacks method, the drvUser method, and one or more of the write(Int32, - Float64, Octet) methods. The NDPluginDriver public interface is defined in NDPluginDriver.h - as follows: -

-
class NDPluginDriver : public asynNDArrayDriver {
-public:
-    NDPluginDriver(const char *portName, int queueSize, int blockingCallbacks, 
-                 const char *NDArrayPort, int NDArrayAddr, int maxAddr, int paramTableSize,
-                 int maxBuffers, size_t maxMemory, int interfaceMask, int interruptMask);
-                 
-    /* These are the methods that we override from asynNDArrayDriver */
-    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
-    virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars,
-                          size_t *nActual);
-    virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value,
-                                        size_t nElements, size_t *nIn);
-    virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, 
-                                     const char **pptypeName, size_t *psize);
-                                     
-    /* These are the methods that are new to this class */
-    virtual void processCallbacks(NDArray *pArray);
-    int createFileName(int maxChars, char *fullFileName);
-...
-}
-
-

- The methods of the NDPluginDriver class are: -

- -

- NDPluginDriver defines parameters that all plugin drivers should implement if possible. - These parameters are defined by enum values with an associated asyn interface, and - access (read-only or read-write). The EPICS database NDPluginBase.template provides - access to these standard plugin parameters, listed in the following table. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Parameter Definitions in NDPluginDriver.h and EPICS Record Definitions in NDPluginBase.template
- Enum name - asyn interface - Access - Description - drvUser string - EPICS record name - EPICS record type
- asyn NDArray driver doing callbacks
- NDPluginDriverArrayPort - asynOctet - r/w - asyn port name for NDArray driver that will make callbacks to this plugin. This - port can be changed at run time, connecting the plugin to a different NDArray driver. - NDARRAY_PORT - $(P)$(R)NDArrayPort
- (P)$(R)NDArrayPort_RBV
- stringout
- stringin
- NDPluginDriverArrayAddr - asynInt32 - r/w - asyn port address for NDArray driver that will make callbacks to this plugin. This - address can be changed at run time, connecting the plugin to a different address - in the NDArray driver. - NDARRAY_ADDR - $(P)$(R)NDArrayAddress
- $(P)$(R)NDArrayAddress_RBV
- longout
- longin
- Callback enable, minimum time, and statistics
- NDPluginDriverEnableCallbacks - asynInt32 - r/w - Enable (1) or disable (0) callbacks from the driver to this plugin. If callbacks - are disabled then the plugin will normally be idle and consume no CPU resources. - ENABLE_CALLBACKS - $(P)$(R)EnableCallbacks
- $(P)$(R)EnableCallbacks_RBV
- bo
- bi
- NDPluginDriverBlockingCallbacks - asynInt32 - r/w - 0 = callbacks from the driver do not block; the NDArray data is put on a queue and - the callback processes in its own thread. -
- 1 = callbacks from the driver block; the callback processes in the driver callback - thread.
- BLOCKING_CALLBACKS - $(P)$(R)CallbacksBlock
- $(P)$(R)CallbacksBlock_RBV
- bo
- bi
- NDPluginDriverMinCallbackTime - asynFloat64 - r/w - The minimum time in seconds between calls to processCallbacks. Any callbacks occuring - before this minimum time has elapsed will be ignored. 0 means no minimum time, i.e. - process all callbacks. - MIN_CALLBACK_TIME - $(P)$(R)MinCallbackTime
- $(P)$(R)MinCallbackTime_RBV
- ao
- ai
- NDPluginDriverArrayCounter - asynInt32 - r/w - Counter that increments by 1 each time an NDArray callback is processed - ARRAY_COUNTER - $(P)$(R)ArrayCounter
- $(P)$(R)ArrayCounter_RBV
- longout
- longin
- N/A - N/A - r/o - Rate (Hz) at which ArrayCounter is incrementing. Computed in database. - N/A - $(P)$(R)ArrayRate_RBV - calc
- NDPluginDriverDroppedArrays - asynInt32 - r/w - Counter that increments by 1 each time an NDArray callback occurs when NDPluginDriverBlockingCallbacks=0 - and the plugin driver queue is full, so the callback cannot be processed. - DROPPED_ARRAYS - $(P)$(R)DroppedArrays
- $(P)$(R)DroppedArrays_RBV
- longout
- longin
- Information about last NDArray callback data
- NDPluginDriverNDimensions - asynInt32 - r/o - Number of dimensions in last NDArray callback data - ARRAY_NDIMENSIONS - $(P)$(R)NDimensions_RBV - longin
- NDPluginDriverDimensions - asynInt32Array - r/o - Dimensions in last NDArray callback data - ARRAY_DIMENSIONS - $(P)$(R)Dimensions_RBV - waveform
- N/A - N/A - r/o - First dimension of NDArray callback data - N/A - $(P)$(R)ArraySize0_RBV - longin
- N/A - N/A - r/o - Second dimension of NDArray callback data - N/A - $(P)$(R)ArraySize1_RBV - longin
- NDPluginDriverDataType - asynInt32 - r/o - Data type of last NDArray callback data (NDDataType_t). - DATA_TYPE - $(P)$(R)DataType_RBV - mbbi
- NDPluginDriverUniqueId - asynInt32 - r/o - Unique ID number of last NDArray callback data - UNIQUE_ID - $(P)$(R)UniqueId_RBV - longin
- NDPluginDriverTimeStamp - asynFloat64 - r/o - Time stamp number of last NDArray callback data - TIME_STAMP - $(P)$(R)TimeStamp_RBV - ai
- Debugging control
- N/A - N/A - N/A - asyn record to control debugging (asynTrace) - N/A - $(P)$(R)AsynIO - asyn
- - + + + areaDetector Plugins + + +
+

+ areaDetector Plugins

+

+ September 20, 2008

+

+ Mark Rivers

+

+ University of Chicago

+
+

+ Contents

+ +

+ Overview

+

+ A powerful feature of the areaDetector module + is the concept of plugins. A plugin is code that is called by a driver that passes + NDArray data in a callback. Plugins can be used to process array data in real time. + Existing plugins convert data to standard asyn arrays (NDPluginStdArrays), save + data to disk (NDPluginFile), and select regions-of-interest (NDPluginROI). New plugins + could be written to perform functions like finding the centroid of a beam, etc. + Once a plugin is written it will work with any areaDetector driver. Plugins have + the the following properties: +

+ +

+ NDPluginDriver

+

+ NDPluginDriver inherits from asynNDArrayDriver. + NDPluginDriver is the class from which actual plugins are directly derived. The + NDPluginDriver class handles most of the details of processing NDArray callbacks + from the driver. Plugins derived from this class typically need to implement the + processCallbacks method, the drvUser method, and one or more of the write(Int32, + Float64, Octet) methods. The NDPluginDriver public interface is defined in NDPluginDriver.h + as follows: +

+
class NDPluginDriver : public asynNDArrayDriver {
+public:
+    NDPluginDriver(const char *portName, int queueSize, int blockingCallbacks, 
+                 const char *NDArrayPort, int NDArrayAddr, int maxAddr, int paramTableSize,
+                 int maxBuffers, size_t maxMemory, int interfaceMask, int interruptMask);
+                 
+    /* These are the methods that we override from asynNDArrayDriver */
+    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
+    virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars,
+                          size_t *nActual);
+    virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value,
+                                        size_t nElements, size_t *nIn);
+    virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, 
+                                     const char **pptypeName, size_t *psize);
+                                     
+    /* These are the methods that are new to this class */
+    virtual void processCallbacks(NDArray *pArray);
+    int createFileName(int maxChars, char *fullFileName);
+...
+}
+
+

+ The methods of the NDPluginDriver class are: +

+ +

+ NDPluginDriver defines parameters that all plugin drivers should implement if possible. + These parameters are defined by enum values with an associated asyn interface, and + access (read-only or read-write). The EPICS database NDPluginBase.template provides + access to these standard plugin parameters, listed in the following table. Note that to + reduce the width of this table the enum names have been split into 2 lines, but these are + just a single name, for example NDPluginDriverArrayPort. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Parameter Definitions in NDPluginDriver.h and EPICS Record Definitions in NDPluginBase.template
+ Enum name + asyn interface + Access + Description + drvUser string + EPICS record name + EPICS record type
+ asyn NDArray driver doing callbacks
+ NDPluginDriver
ArrayPort
+ asynOctet + r/w + asyn port name for NDArray driver that will make callbacks to this plugin. This + port can be changed at run time, connecting the plugin to a different NDArray driver. + NDARRAY_PORT + $(P)$(R)NDArrayPort
+ (P)$(R)NDArrayPort_RBV
+ stringout
+ stringin
+ NDPluginDriver
ArrayAddr
+ asynInt32 + r/w + asyn port address for NDArray driver that will make callbacks to this plugin. This + address can be changed at run time, connecting the plugin to a different address + in the NDArray driver. + NDARRAY_ADDR + $(P)$(R)NDArrayAddress
+ $(P)$(R)NDArrayAddress_RBV
+ longout
+ longin
+ Callback enable, minimum time, and statistics
+ NDPluginDriver
EnableCallbacks
+ asynInt32 + r/w + Enable (1) or disable (0) callbacks from the driver to this plugin. If callbacks + are disabled then the plugin will normally be idle and consume no CPU resources. + ENABLE_CALLBACKS + $(P)$(R)EnableCallbacks
+ $(P)$(R)EnableCallbacks_RBV
+ bo
+ bi
+ NDPluginDriver
BlockingCallbacks
+ asynInt32 + r/w + 0 = callbacks from the driver do not block; the NDArray data is put on a queue and + the callback processes in its own thread. +
+ 1 = callbacks from the driver block; the callback processes in the driver callback + thread.
+ BLOCKING_CALLBACKS + $(P)$(R)CallbacksBlock
+ $(P)$(R)CallbacksBlock_RBV
+ bo
+ bi
+ NDPluginDriver
MinCallbackTime
+ asynFloat64 + r/w + The minimum time in seconds between calls to processCallbacks. Any callbacks occuring + before this minimum time has elapsed will be ignored. 0 means no minimum time, i.e. + process all callbacks. + MIN_CALLBACK_TIME + $(P)$(R)MinCallbackTime
+ $(P)$(R)MinCallbackTime_RBV
+ ao
+ ai
+ NDPluginDriver
ArrayCounter
+ asynInt32 + r/w + Counter that increments by 1 each time an NDArray callback is processed + ARRAY_COUNTER + $(P)$(R)ArrayCounter
+ $(P)$(R)ArrayCounter_RBV
+ longout
+ longin
+ N/A + N/A + r/o + Rate (Hz) at which ArrayCounter is incrementing. Computed in database. + N/A + $(P)$(R)ArrayRate_RBV + calc
+ NDPluginDriver
DroppedArrays
+ asynInt32 + r/w + Counter that increments by 1 each time an NDArray callback occurs when NDPluginDriverBlockingCallbacks=0 + and the plugin driver queue is full, so the callback cannot be processed. + DROPPED_ARRAYS + $(P)$(R)DroppedArrays
+ $(P)$(R)DroppedArrays_RBV
+ longout
+ longin
+ Information about last NDArray callback data
+ NDPluginDriver
NDimensions
+ asynInt32 + r/o + Number of dimensions in last NDArray callback data + ARRAY_NDIMENSIONS + $(P)$(R)NDimensions_RBV + longin
+ NDPluginDriver
Dimensions
+ asynInt32Array + r/o + Dimensions in last NDArray callback data + ARRAY_DIMENSIONS + $(P)$(R)Dimensions_RBV + waveform
+ N/A + N/A + r/o + First dimension of NDArray callback data + N/A + $(P)$(R)ArraySize0_RBV + longin
+ N/A + N/A + r/o + Second dimension of NDArray callback data + N/A + $(P)$(R)ArraySize1_RBV + longin
+ NDPluginDriver
DataType
+ asynInt32 + r/o + Data type of last NDArray callback data (NDDataType_t). + DATA_TYPE + $(P)$(R)DataType_RBV + mbbi
+ NDPluginDriver
UniqueId
+ asynInt32 + r/o + Unique ID number of last NDArray callback data + UNIQUE_ID + $(P)$(R)UniqueId_RBV + longin
+ NDPluginDriver
TimeStamp
+ asynFloat64 + r/o + Time stamp number of last NDArray callback data + TIME_STAMP + $(P)$(R)TimeStamp_RBV + ai
+ Debugging control
+ N/A + N/A + N/A + asyn record to control debugging (asynTrace) + N/A + $(P)$(R)AsynIO + asyn
+ +