Original Design#

Note

This page was the initial plan for what PVI would do. The produce features have now been removed and only direct conversion to a Device representation and then formatting of UIs is supported now. This page is kept now to record the design in case full integration into areaDetector is revisited in the future.

digraph pvi_flowchart { bgcolor=transparent rankdir=LR node [fontname=Arial fontsize=10 shape=box style=filled fillcolor="#8BC4E9"] edge [fontname=Arial fontsize=10 arrowhead=vee] { rank=same; "pilatus.pvi.yaml" "pilatus.cpp" "pilatus.h" } PVI [shape=doublecircle] "pilatus.local.yaml" -> PVI "pilatus.pvi.yaml" -> PVI PVI -> "pilatus_parameters.h" PVI -> "pilatus_parameters.template" PVI -> "pilatus_parameters.opi" PVI -> "pilatus_parameters.adl" PVI -> "pilatus_parameters.edl" PVI -> "pilatus_parameters.csv" "pilatus_parameters.template" -> "pilatus.template" [label="included in"] "pilatus_parameters.h" -> "pilatus.h" [label="included in"] "pilatus.cpp" -> "libPilatus.so" "pilatus.h" -> "libPilatus.so" "pilatus_parameters.csv" -> "pilatus.rst" [label="included in"] "pilatus_parameters.adl" -> "pilatus.adl" [label="linked from"] "pilatus_parameters.edl" -> "pilatus.edl" [label="linked from"] "pilatus_parameters.opi" -> "pilatus.opi" [label="linked from"] }

Aims of PVI#

Aim

Description

Reduce boilerplate

At the moment you can write a simple asyn port driver in code, but there is a lot of boilerplate to connect it to the outside world. The createParam section, the database template records, and the lowest level screens are all quite repetitive and each layer looks like it could be autogenerated without much extra information

Reduce copy paste errors

At the moment it is easy to create screens and database templates via copy and paste, but not changing a record name or parameter leads to hard to track down errors

Support site specific styles for screens

Each site has their own style for screens, and many sites have their own site specific display manager. Rather than start with one display manager and convert, PVI takes a cut down Channel description (just a type, pv and widget), and lets the site specific template generate the screen according to local styles

How it works#

The YAML file contains information about each asyn parameter that will be exposed by the driver, it’s name, type, description, initial value, which record type it uses, whether it is writeable or read only, which widget should be used, etc. PVI reads these and passes them to Producer that creates intermediate Record, Channel and AsynParam objects. These are passed to a site specific Formatter which takes the tree of intermediate objects and writes a parameter CPP file, database template, and site specific screens to disk.

YAML file#

The YAML file is formed of a number of sections:

Section

Description

includes

The YAML files to use as base classes for superclasses

local

A local override YAML file for site specific changes

producer

Producer that knows how to create Records and Channels from the Components

formatter

Site specific Formatter which can format the output files

components

Tree of Components for each logical asyn parameter arranged in logical GUI groups

The Components are created from the YAML file with local overrides (also incorporating the base classes for screens). These are passed to the Producer which produces AsynParameters, Records and Channels. These are then passed to the Formatter which outputs them to file:

digraph pvi_products { bgcolor=transparent node [fontname=Arial fontsize=10 shape=box style=filled fillcolor="#8BC4E9"] edge [fontname=Arial fontsize=10 arrowhead=vee] Intermediate [label="[Record(),\n Channel(),\n AsynParameter()]"] Products [label="Template\nScreens\nDriver Params\nDocumentation"] {rank=same; Components -> Producer -> Intermediate -> Formatter -> Products} }

Here’s a cut down pilatus.yaml file that might describe a parameter in a detector:

type: AsynProducer
prefix: $(P)$(R)
label: pilatus
asyn_port: $(PORT)
address: $(ADDR)
timeout: $(TIMEOUT)
parent: ADDriver
parameters:
  - type: Group
    name: ComponentGroupOne
    layout:
      type: Grid
    children:
      - type: AsynBinary
        name: ResetPower
        description: ResetPower
        index_name: PilatusResetPower
        drv_info: RESET_POWER
        access: W
        record_fields:
          ZNAM: Done
          ONAM: Reset

      - type: AsynBusy
        name: ThresholdApply
        description: ThresholdApply
        index_name: PilatusThresholdApply
        drv_info: THRESHOLD_APPLY
        access: W
        initial: "0"
        record_fields:
          ZNAM: Done
          ONAM: Apply

      - type: AsynFloat64
        name: ImageFileTmot
        description: Timeout for image file
        index_name: PilatusImageFileTmot
        drv_info: IMAGE_FILE_TMOT
        access: W
        initial: "20"
        record_fields:
          PREC: "3"
          EGU: s

      - type: AsynFloat64
        name: Wavelength
        description: Wavelength
        index_name: PilatusWavelength
        drv_info: WAVELENGTH
        access: W
        initial: "1.54"
        record_fields:
          PREC: "4"
          EGU: Angstroms

      - type: AsynFloat64
        name: EnergyLow
        description: EnergyLow
        index_name: PilatusEnergyLow
        drv_info: ENERGY_LOW
        access: W
        initial: "0"
        record_fields:
          PREC: "3"
          EGU: eV

      - type: AsynFloat64
        name: EnergyHigh
        description: EnergyHigh
        index_name: PilatusEnergyHigh
        drv_info: ENERGY_HIGH
        access: W
        initial: "0"
        record_fields:
          PREC: "3"
          EGU: eV

      - type: AsynFloat64
        name: DetDist
        description: DetDist
        index_name: PilatusDetDist
        drv_info: DET_DIST
        access: W
        initial: "1000"
        record_fields:
          PREC: "3"
          EGU: mm

      - type: AsynFloat64
        name: DetVOffset
        description: DetVOffset
        index_name: PilatusDetVOffset
        drv_info: DET_VOFFSET
        access: W
        initial: "0"
        record_fields:
          PREC: "3"
          EGU: mm

      - type: AsynFloat64
        name: BeamX
        description: BeamX
        index_name: PilatusBeamX
        drv_info: BEAM_X
        access: W
        initial: "0"
        record_fields:
          PREC: "3"
          EGU: pixels

      - type: AsynFloat64
        name: BeamY
        description: BeamY
        index_name: PilatusBeamY
        drv_info: BEAM_Y
        access: W
        initial: "0"
        record_fields:
          PREC: "3"
          EGU: pixels

      - type: AsynFloat64
        name: Flux
        description: Flux
        index_name: PilatusFlux
        drv_info: FLUX
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: ph/s

      - type: AsynFloat64
        name: FilterTransm
        description: FilterTransm
        index_name: PilatusFilterTransm
        drv_info: FILTER_TRANSM
        access: W
        initial: "1.0"
        record_fields:
          PREC: "4"

      - type: AsynFloat64
        name: StartAngle
        description: StartAngle
        index_name: PilatusStartAngle
        drv_info: START_ANGLE
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: AngleIncr
        description: AngleIncr
        index_name: PilatusAngleIncr
        drv_info: ANGLE_INCR
        access: W
        initial: "0.1"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Det2theta
        description: Det2theta
        index_name: PilatusDet2theta
        drv_info: DET_2THETA
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Polarization
        description: Polarization
        index_name: PilatusPolarization
        drv_info: POLARIZATION
        access: W
        initial: "0.99"
        record_fields:
          PREC: "4"

      - type: AsynFloat64
        name: Alpha
        description: Alpha
        index_name: PilatusAlpha
        drv_info: ALPHA
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Kappa
        description: Kappa
        index_name: PilatusKappa
        drv_info: KAPPA
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Phi
        description: Phi
        index_name: PilatusPhi
        drv_info: PHI
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: PhiIncr
        description: PhiIncr
        index_name: PilatusPhiIncr
        drv_info: PHI_INCR
        access: W
        initial: "0.1"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Chi
        description: Chi
        index_name: PilatusChi
        drv_info: CHI
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: ChiIncr
        description: ChiIncr
        index_name: PilatusChiIncr
        drv_info: CHI_INCR
        access: W
        initial: "0.1"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: Omega
        description: Omega
        index_name: PilatusOmega
        drv_info: OMEGA
        access: W
        initial: "0"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynFloat64
        name: OmegaIncr
        description: OmegaIncr
        index_name: PilatusOmegaIncr
        drv_info: OMEGA_INCR
        access: W
        initial: "0.1"
        record_fields:
          PREC: "4"
          EGU: deg

      - type: AsynString
        name: OscillAxis
        description: OscillAxis
        index_name: PilatusOscillAxis
        drv_info: OSCILL_AXIS
        access: W
        initial: X, CW

      - type: AsynLong
        name: NumOscill
        description: NumOscill
        index_name: PilatusNumOscill
        drv_info: NUM_OSCILL
        access: W
        initial: "1"

      - type: AsynWaveform
        name: BadPixelFile
        description: BadPixelFile
        index_name: PilatusBadPixelFile
        drv_info: BAD_PIXEL_FILE
        access: W
        record_fields:
          NELM: "256"
          FTVL: CHAR

      - type: AsynWaveform
        name: FlatFieldFile
        description: FlatFieldFile
        index_name: PilatusFlatFieldFile
        drv_info: FLAT_FIELD_FILE
        access: W
        record_fields:
          NELM: "256"
          FTVL: CHAR

      - type: AsynWaveform
        name: CbfTemplateFile
        description: CbfTemplateFile
        index_name: PilatusCbfTemplateFile
        drv_info: CBFTEMPLATEFILE
        access: W
        record_fields:
          NELM: "256"
          FTVL: CHAR

      - type: AsynWaveform
        name: HeaderString
        description: HeaderString
        index_name: PilatusHeaderString
        drv_info: HEADERSTRING
        access: W
        record_fields:
          NELM: "68"
          FTVL: CHAR

      - type: AsynBinary
        name: Armed
        description: Armed
        index_name: PilatusArmed
        drv_info: ARMED
        access: R
        read_record_suffix: Armed
        record_fields:
          SCAN: I/O Intr
          ZNAM: Unarmed
          ONAM: Armed

      - type: AsynLong
        name: NumBadPixels
        description: Number of bad pixels
        index_name: PilatusNumBadPixels
        drv_info: NUM_BAD_PIXELS
        access: R
        read_record_suffix: NumBadPixels
        record_fields:
          SCAN: I/O Intr

      - type: AsynBinary
        name: FlatFieldValid
        description: Flat field valid
        index_name: PilatusFlatFieldValid
        drv_info: FLAT_FIELD_VALID
        access: R
        read_record_suffix: FlatFieldValid
        record_fields:
          SCAN: I/O Intr
          ZNAM: No
          ONAM: Yes

      - type: AsynInt32
        name: PixelCutOff
        description: PixelCutOff_RBV
        index_name: PilatusPixelCutOff
        drv_info: PIXEL_CUTOFF
        access: R
        record_fields:
          SCAN: I/O Intr
          EGU: counts

      - type: AsynFloat64
        name: Temp0
        description: Temp0_RBV
        index_name: PilatusThTemp0
        drv_info: TH_TEMP_0
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: C

      - type: AsynFloat64
        name: Temp1
        description: Temp1_RBV
        index_name: PilatusThTemp1
        drv_info: TH_TEMP_1
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: C

      - type: AsynFloat64
        name: Temp2
        description: Temp2_RBV
        index_name: PilatusThTemp2
        drv_info: TH_TEMP_2
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: C

      - type: AsynFloat64
        name: Humid0
        description: Humid0_RBV
        index_name: PilatusThHumid0
        drv_info: TH_HUMID_0
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: "%"

      - type: AsynFloat64
        name: Humid1
        description: Humid1_RBV
        index_name: PilatusThHumid1
        drv_info: TH_HUMID_1
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: "%"

      - type: AsynFloat64
        name: Humid2
        description: Humid2_RBV
        index_name: PilatusThHumid2
        drv_info: TH_HUMID_2
        access: R
        record_fields:
          SCAN: I/O Intr
          PREC: "1"
          EGU: "%"

      - type: AsynString
        name: TVXVersion
        description: TVXVersion_RBV
        index_name: PilatusTvxVersion
        drv_info: TVXVERSION
        access: R
        record_fields:
          SCAN: I/O Intr

      - type: AsynLong
        name: ResetPowerTime
        description: Reset module power wait time
        index_name: PilatusResetPowerTime
        drv_info: RESET_POWER_TIME
        initial: "1"
        record_fields:
          SCAN: I/O Intr
          EGU: Seconds

      - type: AsynFloat64
        name: DelayTime
        description: DelayTime
        index_name: PilatusDelayTime
        drv_info: DELAY_TIME
        initial: "0"
        record_fields:
          SCAN: I/O Intr
          PREC: "6"
          EGU: s

      - type: AsynFloat64
        name: ThresholdEnergy
        description: Energy threshold
        index_name: PilatusThreshold
        drv_info: THRESHOLD
        initial: "10.000"
        record_fields:
          SCAN: I/O Intr
          PREC: "3"
          EGU: keV

      - type: AsynBinary
        name: ThresholdAutoApply
        description: ThresholdAutoApply
        index_name: PilatusThresholdAutoApply
        drv_info: THRESHOLD_AUTO_APPLY
        initial: "1"
        record_fields:
          SCAN: I/O Intr
          ZNAM: No
          ONAM: Yes

      - type: AsynFloat64
        name: Energy
        description: X-ray Energy
        index_name: PilatusEnergy
        drv_info: ENERGY
        initial: "20.000"
        record_fields:
          SCAN: I/O Intr
          PREC: "3"
          EGU: keV

      - type: AsynLong
        name: MinFlatField
        description: Minimum flat field value
        index_name: PilatusMinFlatField
        drv_info: MIN_FLAT_FIELD
        initial: "100"
        record_fields:
          SCAN: I/O Intr
          EGU: Counts

      - type: AsynMultiBitBinary
        name: GapFill
        description: GapFill
        index_name: PilatusGapFill
        drv_info: GAP_FILL
        initial: "0"
        record_fields:
          SCAN: I/O Intr
          ZRVL: "2"
          ONVL: "0"
          TWVL: "-1"
          ZRST: N.A.
          ONST: "0"
          TWST: "-1"

      - type: AsynFloat64
        name: ProgressBarTest
        description: ProgressBar
        drv_info: PROGRESS
        access: R
        read_widget:
          type: ProgressBar
        initial: 50.0
        record_fields:
          EGU: deg
          PREC: 4
        index_name: ProgressBarTest

Screen files#

The intermediate objects are a number of Channel instances. These contain basic types (like Combo, TextInput, TextUpdate, LED, Group) and some creation hints (like label, grouping, description, display_form), but no X, Y, Width, Height or colour information. They may represent either a single widget or pair of demand/readback widgets.

The site-specific Formatter consumes these Channel objects, then produces a screen with style, sizing and layout that can be customized to the site. This means that the default layout (big screen with lots of widgets arranged in group boxes) could be produced for one site, then another site could make lots of little screens with one group per screen. Styling is also covered, so the blue/grey MEDM screens and green/grey EDM screens can be customized to fit the site style guide.

HTML Documentation#

The Parameter and record sections of the existing documentation could be reproduced, in tabular form as a csv file that can be included in rst docs:

Pilatus Parameters#

Parameter Index Variable

Asyn Interface

Access

drvInfo String

Record Names

Record Types

Description

ComponentGroupOne

PilatusResetPower

asynInt32

W

RESET_POWER

$(P)$(R)ResetPower

bo

ResetPower

PilatusThresholdApply

asynInt32

W

THRESHOLD_APPLY

$(P)$(R)ThresholdApply

busy

ThresholdApply

PilatusImageFileTmot

asynFloat64

W

IMAGE_FILE_TMOT

$(P)$(R)ImageFileTmot

ao

Timeout for image file

PilatusWavelength

asynFloat64

W

WAVELENGTH

$(P)$(R)Wavelength

ao

Wavelength

PilatusEnergyLow

asynFloat64

W

ENERGY_LOW

$(P)$(R)EnergyLow

ao

EnergyLow

PilatusEnergyHigh

asynFloat64

W

ENERGY_HIGH

$(P)$(R)EnergyHigh

ao

EnergyHigh

PilatusDetDist

asynFloat64

W

DET_DIST

$(P)$(R)DetDist

ao

DetDist

PilatusDetVOffset

asynFloat64

W

DET_VOFFSET

$(P)$(R)DetVOffset

ao

DetVOffset

PilatusBeamX

asynFloat64

W

BEAM_X

$(P)$(R)BeamX

ao

BeamX

PilatusBeamY

asynFloat64

W

BEAM_Y

$(P)$(R)BeamY

ao

BeamY

PilatusFlux

asynFloat64

W

FLUX

$(P)$(R)Flux

ao

Flux

PilatusFilterTransm

asynFloat64

W

FILTER_TRANSM

$(P)$(R)FilterTransm

ao

FilterTransm

PilatusStartAngle

asynFloat64

W

START_ANGLE

$(P)$(R)StartAngle

ao

StartAngle

PilatusAngleIncr

asynFloat64

W

ANGLE_INCR

$(P)$(R)AngleIncr

ao

AngleIncr

PilatusDet2theta

asynFloat64

W

DET_2THETA

$(P)$(R)Det2theta

ao

Det2theta

PilatusPolarization

asynFloat64

W

POLARIZATION

$(P)$(R)Polarization

ao

Polarization

PilatusAlpha

asynFloat64

W

ALPHA

$(P)$(R)Alpha

ao

Alpha

PilatusKappa

asynFloat64

W

KAPPA

$(P)$(R)Kappa

ao

Kappa

PilatusPhi

asynFloat64

W

PHI

$(P)$(R)Phi

ao

Phi

PilatusPhiIncr

asynFloat64

W

PHI_INCR

$(P)$(R)PhiIncr

ao

PhiIncr

PilatusChi

asynFloat64

W

CHI

$(P)$(R)Chi

ao

Chi

PilatusChiIncr

asynFloat64

W

CHI_INCR

$(P)$(R)ChiIncr

ao

ChiIncr

PilatusOmega

asynFloat64

W

OMEGA

$(P)$(R)Omega

ao

Omega

PilatusOmegaIncr

asynFloat64

W

OMEGA_INCR

$(P)$(R)OmegaIncr

ao

OmegaIncr

PilatusOscillAxis

asynOctetWrite

W

OSCILL_AXIS

$(P)$(R)OscillAxis

stringout

OscillAxis

PilatusNumOscill

asynInt32

W

NUM_OSCILL

$(P)$(R)NumOscill

longout

NumOscill

PilatusBadPixelFile

asynOctetWrite

W

BAD_PIXEL_FILE

$(P)$(R)BadPixelFile

waveform

BadPixelFile

PilatusFlatFieldFile

asynOctetWrite

W

FLAT_FIELD_FILE

$(P)$(R)FlatFieldFile

waveform

FlatFieldFile

PilatusCbfTemplateFile

asynOctetWrite

W

CBFTEMPLATEFILE

$(P)$(R)CbfTemplateFile

waveform

CbfTemplateFile

PilatusHeaderString

asynOctetWrite

W

HEADERSTRING

$(P)$(R)HeaderString

waveform

HeaderString

PilatusArmed

asynInt32

R

ARMED

$(P)$(R)Armed

bi

Armed

PilatusNumBadPixels

asynInt32

R

NUM_BAD_PIXELS

$(P)$(R)NumBadPixels

longin

Number of bad pixels

PilatusFlatFieldValid

asynInt32

R

FLAT_FIELD_VALID

$(P)$(R)FlatFieldValid

bi

Flat field valid

PilatusPixelCutOff

asynInt32

R

PIXEL_CUTOFF

$(P)$(R)PixelCutOff_RBV

ai

PixelCutOff_RBV

PilatusThTemp0

asynFloat64

R

TH_TEMP_0

$(P)$(R)Temp0_RBV

ai

Temp0_RBV

PilatusThTemp1

asynFloat64

R

TH_TEMP_1

$(P)$(R)Temp1_RBV

ai

Temp1_RBV

PilatusThTemp2

asynFloat64

R

TH_TEMP_2

$(P)$(R)Temp2_RBV

ai

Temp2_RBV

PilatusThHumid0

asynFloat64

R

TH_HUMID_0

$(P)$(R)Humid0_RBV

ai

Humid0_RBV

PilatusThHumid1

asynFloat64

R

TH_HUMID_1

$(P)$(R)Humid1_RBV

ai

Humid1_RBV

PilatusThHumid2

asynFloat64

R

TH_HUMID_2

$(P)$(R)Humid2_RBV

ai

Humid2_RBV

PilatusTvxVersion

asynOctetRead

R

TVXVERSION

$(P)$(R)TVXVersion_RBV

stringin

TVXVersion_RBV

PilatusResetPowerTime

asynInt32

RW

RESET_POWER_TIME

$(P)$(R)ResetPowerTime, $(P)$(R)ResetPowerTime_RBV

longout, longin

Reset module power wait time

PilatusDelayTime

asynFloat64

RW

DELAY_TIME

$(P)$(R)DelayTime, $(P)$(R)DelayTime_RBV

ao, ai

DelayTime

PilatusThreshold

asynFloat64

RW

THRESHOLD

$(P)$(R)ThresholdEnergy, $(P)$(R)ThresholdEnergy_RBV

ao, ai

Energy threshold

PilatusThresholdAutoApply

asynInt32

RW

THRESHOLD_AUTO_APPLY

$(P)$(R)ThresholdAutoApply, $(P)$(R)ThresholdAutoApply_RBV

bo, bi

ThresholdAutoApply

PilatusEnergy

asynFloat64

RW

ENERGY

$(P)$(R)Energy, $(P)$(R)Energy_RBV

ao, ai

X-ray Energy

PilatusMinFlatField

asynInt32

RW

MIN_FLAT_FIELD

$(P)$(R)MinFlatField, $(P)$(R)MinFlatField_RBV

longout, longin

Minimum flat field value

PilatusGapFill

asynInt32

RW

GAP_FILL

$(P)$(R)GapFill, $(P)$(R)GapFill_RBV

mbbo, mbbi

GapFill

ProgressBarTest

asynFloat64

R

PROGRESS

$(P)$(R)ProgressBarTest_RBV

ai

ProgressBar

Questions#

I am fairly happy with the scheme set out above, but there are a lot of implementation questions. Here are the most pressing:

One-time generation and checked into source control or generated by Makefile?#

The process would probably be:

  • If pvi cli tool available, build products as part of make

  • Check in products to source control

  • End users will only regenerate build products if pvi tool installed

ADGenICam would be supported by building a GenICamProducer which took no components, just a path to a GenICam XML file

Which screen tools to support?#

I suggest creating adl and edl files initially, following the example of makeAdl.py in ADGenICam, then expanding to support opi, bob and ui files natively. This would avoid needing screen converters installed

Drivers#

The generated header file contains the string parameters, and defines the parameters to make the interface. In this example we have a header file pilatusDetectorParamSet.h:

#ifndef PilatusDetectorParamSet_H
#define PilatusDetectorParamSet_H

#include "ADDriverParamSet.h"

#define PilatusResetPowerString "RESET_POWER"
#define PilatusThresholdApplyString "THRESHOLD_APPLY"
#define PilatusImageFileTmotString "IMAGE_FILE_TMOT"
#define PilatusWavelengthString "WAVELENGTH"
#define PilatusEnergyLowString "ENERGY_LOW"
#define PilatusEnergyHighString "ENERGY_HIGH"
#define PilatusDetDistString "DET_DIST"
#define PilatusDetVOffsetString "DET_VOFFSET"
#define PilatusBeamXString "BEAM_X"
#define PilatusBeamYString "BEAM_Y"
#define PilatusFluxString "FLUX"
#define PilatusFilterTransmString "FILTER_TRANSM"
#define PilatusStartAngleString "START_ANGLE"
#define PilatusAngleIncrString "ANGLE_INCR"
#define PilatusDet2thetaString "DET_2THETA"
#define PilatusPolarizationString "POLARIZATION"
#define PilatusAlphaString "ALPHA"
#define PilatusKappaString "KAPPA"
#define PilatusPhiString "PHI"
#define PilatusPhiIncrString "PHI_INCR"
#define PilatusChiString "CHI"
#define PilatusChiIncrString "CHI_INCR"
#define PilatusOmegaString "OMEGA"
#define PilatusOmegaIncrString "OMEGA_INCR"
#define PilatusOscillAxisString "OSCILL_AXIS"
#define PilatusNumOscillString "NUM_OSCILL"
#define PilatusBadPixelFileString "BAD_PIXEL_FILE"
#define PilatusFlatFieldFileString "FLAT_FIELD_FILE"
#define PilatusCbfTemplateFileString "CBFTEMPLATEFILE"
#define PilatusHeaderStringString "HEADERSTRING"
#define PilatusArmedString "ARMED"
#define PilatusNumBadPixelsString "NUM_BAD_PIXELS"
#define PilatusFlatFieldValidString "FLAT_FIELD_VALID"
#define PilatusPixelCutOffString "PIXEL_CUTOFF"
#define PilatusThTemp0String "TH_TEMP_0"
#define PilatusThTemp1String "TH_TEMP_1"
#define PilatusThTemp2String "TH_TEMP_2"
#define PilatusThHumid0String "TH_HUMID_0"
#define PilatusThHumid1String "TH_HUMID_1"
#define PilatusThHumid2String "TH_HUMID_2"
#define PilatusTvxVersionString "TVXVERSION"
#define PilatusResetPowerTimeString "RESET_POWER_TIME"
#define PilatusDelayTimeString "DELAY_TIME"
#define PilatusThresholdString "THRESHOLD"
#define PilatusThresholdAutoApplyString "THRESHOLD_AUTO_APPLY"
#define PilatusEnergyString "ENERGY"
#define PilatusMinFlatFieldString "MIN_FLAT_FIELD"
#define PilatusGapFillString "GAP_FILL"
#define ProgressBarTestString "PROGRESS"

const std::string pilatusParamTree = \
"{\"parameters\":[{\"type\": \"Group\", \"name\": \"ComponentGroupOne\", \"label\": \"\", \"layout\": {\"type\": \"Grid\", \"labelled\": true}, \"children\": [{\"type\": \"SignalW\", \"name\": \"WaitForPlugins\", \"label\": \"\", \"pv\": \"WaitForPlugins\", \"widget\": {\"type\": \"CheckBox\"}}, {\"type\": \"SignalW\", \"name\": \"EmptyFreeList\", \"label\": \"\", \"pv\": \"EmptyFreeList\", \"widget\": {\"type\": \"CheckBox\"}}, {\"type\": \"SignalW\", \"name\": \"NDAttributesMacros\", \"label\": \"\", \"pv\": \"NDAttributesMacros\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"NDAttributesFile\", \"label\": \"\", \"pv\": \"NDAttributesFile\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ADCoreVersion\", \"label\": \"\", \"pv\": \"ADCoreVersion_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"DriverVersion\", \"label\": \"\", \"pv\": \"DriverVersion_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"PortName\", \"label\": \"\", \"pv\": \"PortName_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Manufacturer\", \"label\": \"\", \"pv\": \"Manufacturer_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Model\", \"label\": \"\", \"pv\": \"Model_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"SerialNumber\", \"label\": \"\", \"pv\": \"SerialNumber_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"SDKVersion\", \"label\": \"\", \"pv\": \"SDKVersion_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"FirmwareVersion\", \"label\": \"\", \"pv\": \"FirmwareVersion_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"AcquireBusyCB\", \"label\": \"\", \"pv\": \"AcquireBusyCB\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"BayerPattern\", \"label\": \"\", \"pv\": \"BayerPattern_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ArraySizeX\", \"label\": \"\", \"pv\": \"ArraySizeX_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ArraySizeY\", \"label\": \"\", \"pv\": \"ArraySizeY_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ArraySizeZ\", \"label\": \"\", \"pv\": \"ArraySizeZ_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ArraySize\", \"label\": \"\", \"pv\": \"ArraySize_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Codec\", \"label\": \"\", \"pv\": \"Codec_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"CompressedSize\", \"label\": \"\", \"pv\": \"CompressedSize_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"UniqueId\", \"label\": \"\", \"pv\": \"UniqueId_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"TimeStamp\", \"label\": \"\", \"pv\": \"TimeStamp_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"EpicsTSSec\", \"label\": \"\", \"pv\": \"EpicsTSSec_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"EpicsTSNsec\", \"label\": \"\", \"pv\": \"EpicsTSNsec_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"NDAttributesStatus\", \"label\": \"\", \"pv\": \"NDAttributesStatus\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"PoolMaxMem\", \"label\": \"\", \"pv\": \"PoolMaxMem\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"PoolUsedMem\", \"label\": \"\", \"pv\": \"PoolUsedMem\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"PoolAllocBuffers\", \"label\": \"\", \"pv\": \"PoolAllocBuffers\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"PoolFreeBuffers\", \"label\": \"\", \"pv\": \"PoolFreeBuffers\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"NumQueuedArrays\", \"label\": \"\", \"pv\": \"NumQueuedArrays\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"Acquire\", \"label\": \"\", \"pv\": \"Acquire\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"\", \"read_widget\": null}, {\"type\": \"SignalRW\", \"name\": \"NDimensions\", \"label\": \"\", \"pv\": \"NDimensions\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"NDimensions_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"Dimensions\", \"label\": \"\", \"pv\": \"Dimensions\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"Dimensions_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"DataType\", \"label\": \"\", \"pv\": \"DataType\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"DataType_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ColorMode\", \"label\": \"\", \"pv\": \"ColorMode\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"ColorMode_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ArrayCounter\", \"label\": \"\", \"pv\": \"ArrayCounter\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"ArrayCounter_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ArrayCallbacks\", \"label\": \"\", \"pv\": \"ArrayCallbacks\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ArrayCallbacks_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"FilePathExists\", \"label\": \"\", \"pv\": \"FilePathExists_RBV\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"FullFileName\", \"label\": \"\", \"pv\": \"FullFileName_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"NumCaptured\", \"label\": \"\", \"pv\": \"NumCaptured_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"WriteStatus\", \"label\": \"\", \"pv\": \"WriteStatus\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"WriteMessage\", \"label\": \"\", \"pv\": \"WriteMessage\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"FilePath\", \"label\": \"\", \"pv\": \"FilePath\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"FilePath_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"CreateDirectory\", \"label\": \"\", \"pv\": \"CreateDirectory\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"CreateDirectory_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"FileName\", \"label\": \"\", \"pv\": \"FileName\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"FileName_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"FileNumber\", \"label\": \"\", \"pv\": \"FileNumber\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"\", \"read_widget\": null}, {\"type\": \"SignalRW\", \"name\": \"AutoIncrement\", \"label\": \"\", \"pv\": \"AutoIncrement\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"AutoIncrement_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"FileTemplate\", \"label\": \"\", \"pv\": \"FileTemplate\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"FileTemplate_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"AutoSave\", \"label\": \"\", \"pv\": \"AutoSave\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"AutoSave_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"WriteFile\", \"label\": \"\", \"pv\": \"WriteFile\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"WriteFile_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"ReadFile\", \"label\": \"\", \"pv\": \"ReadFile\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ReadFile_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"FileFormat\", \"label\": \"\", \"pv\": \"FileFormat\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"FileFormat_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"FileWriteMode\", \"label\": \"\", \"pv\": \"FileWriteMode\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"FileWriteMode_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"Capture\", \"label\": \"\", \"pv\": \"Capture\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"Capture_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"NumCapture\", \"label\": \"\", \"pv\": \"NumCapture\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"NumCapture_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"DeleteDriverFile\", \"label\": \"\", \"pv\": \"DeleteDriverFile\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"DeleteDriverFile_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"LazyOpen\", \"label\": \"\", \"pv\": \"LazyOpen\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"LazyOpen_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"TempSuffix\", \"label\": \"\", \"pv\": \"TempSuffix\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"TempSuffix_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"ReadStatus\", \"label\": \"\", \"pv\": \"ReadStatus\", \"widget\": {\"type\": \"CheckBox\"}}, {\"type\": \"SignalR\", \"name\": \"MaxSizeX\", \"label\": \"\", \"pv\": \"MaxSizeX_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"MaxSizeY\", \"label\": \"\", \"pv\": \"MaxSizeY_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"TimeRemaining\", \"label\": \"\", \"pv\": \"TimeRemaining_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"NumExposuresCounter\", \"label\": \"\", \"pv\": \"NumExposuresCounter_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"NumImagesCounter\", \"label\": \"\", \"pv\": \"NumImagesCounter_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"DetectorState\", \"label\": \"\", \"pv\": \"DetectorState_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"StatusMessage\", \"label\": \"\", \"pv\": \"StatusMessage_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"StringToServer\", \"label\": \"\", \"pv\": \"StringToServer_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"StringFromServer\", \"label\": \"\", \"pv\": \"StringFromServer_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ShutterStatus\", \"label\": \"\", \"pv\": \"ShutterStatus_RBV\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"ShutterControlEPICS\", \"label\": \"\", \"pv\": \"ShutterControlEPICS\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"TemperatureActual\", \"label\": \"\", \"pv\": \"TemperatureActual\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"BinX\", \"label\": \"\", \"pv\": \"BinX\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"BinX_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"BinY\", \"label\": \"\", \"pv\": \"BinY\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"BinY_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"MinX\", \"label\": \"\", \"pv\": \"MinX\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"MinX_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"MinY\", \"label\": \"\", \"pv\": \"MinY\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"MinY_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"SizeX\", \"label\": \"\", \"pv\": \"SizeX\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"SizeX_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"SizeY\", \"label\": \"\", \"pv\": \"SizeY\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"SizeY_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ReverseX\", \"label\": \"\", \"pv\": \"ReverseX\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ReverseX_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"ReverseY\", \"label\": \"\", \"pv\": \"ReverseY\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ReverseY_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"AcquireTime\", \"label\": \"\", \"pv\": \"AcquireTime\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"AcquireTime_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"AcquirePeriod\", \"label\": \"\", \"pv\": \"AcquirePeriod\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"AcquirePeriod_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"Gain\", \"label\": \"\", \"pv\": \"Gain\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"Gain_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"FrameType\", \"label\": \"\", \"pv\": \"FrameType\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"FrameType_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ImageMode\", \"label\": \"\", \"pv\": \"ImageMode\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"ImageMode_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"TriggerMode\", \"label\": \"\", \"pv\": \"TriggerMode\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"TriggerMode_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"NumExposures\", \"label\": \"\", \"pv\": \"NumExposures\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"NumExposures_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"NumImages\", \"label\": \"\", \"pv\": \"NumImages\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"NumImages_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ShutterMode\", \"label\": \"\", \"pv\": \"ShutterMode\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"ShutterMode_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ShutterControl\", \"label\": \"\", \"pv\": \"ShutterControl\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ShutterControl_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"ShutterOpenDelay\", \"label\": \"\", \"pv\": \"ShutterOpenDelay\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"ShutterOpenDelay_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ShutterCloseDelay\", \"label\": \"\", \"pv\": \"ShutterCloseDelay\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"ShutterCloseDelay_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"Temperature\", \"label\": \"\", \"pv\": \"Temperature\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"Temperature_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"ResetPower\", \"label\": \"\", \"pv\": \"ResetPower\", \"widget\": {\"type\": \"CheckBox\"}}, {\"type\": \"SignalW\", \"name\": \"ThresholdApply\", \"label\": \"\", \"pv\": \"ThresholdApply\", \"widget\": {\"type\": \"CheckBox\"}}, {\"type\": \"SignalW\", \"name\": \"ImageFileTmot\", \"label\": \"\", \"pv\": \"ImageFileTmot\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Wavelength\", \"label\": \"\", \"pv\": \"Wavelength\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"EnergyLow\", \"label\": \"\", \"pv\": \"EnergyLow\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"EnergyHigh\", \"label\": \"\", \"pv\": \"EnergyHigh\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"DetDist\", \"label\": \"\", \"pv\": \"DetDist\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"DetVOffset\", \"label\": \"\", \"pv\": \"DetVOffset\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"BeamX\", \"label\": \"\", \"pv\": \"BeamX\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"BeamY\", \"label\": \"\", \"pv\": \"BeamY\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Flux\", \"label\": \"\", \"pv\": \"Flux\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"FilterTransm\", \"label\": \"\", \"pv\": \"FilterTransm\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"StartAngle\", \"label\": \"\", \"pv\": \"StartAngle\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"AngleIncr\", \"label\": \"\", \"pv\": \"AngleIncr\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Det2theta\", \"label\": \"\", \"pv\": \"Det2theta\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Polarization\", \"label\": \"\", \"pv\": \"Polarization\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Alpha\", \"label\": \"\", \"pv\": \"Alpha\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Kappa\", \"label\": \"\", \"pv\": \"Kappa\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Phi\", \"label\": \"\", \"pv\": \"Phi\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"PhiIncr\", \"label\": \"\", \"pv\": \"PhiIncr\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Chi\", \"label\": \"\", \"pv\": \"Chi\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"ChiIncr\", \"label\": \"\", \"pv\": \"ChiIncr\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"Omega\", \"label\": \"\", \"pv\": \"Omega\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"OmegaIncr\", \"label\": \"\", \"pv\": \"OmegaIncr\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"OscillAxis\", \"label\": \"\", \"pv\": \"OscillAxis\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"NumOscill\", \"label\": \"\", \"pv\": \"NumOscill\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"BadPixelFile\", \"label\": \"\", \"pv\": \"BadPixelFile\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"FlatFieldFile\", \"label\": \"\", \"pv\": \"FlatFieldFile\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"CbfTemplateFile\", \"label\": \"\", \"pv\": \"CbfTemplateFile\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalW\", \"name\": \"HeaderString\", \"label\": \"\", \"pv\": \"HeaderString\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Armed\", \"label\": \"\", \"pv\": \"Armed\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"NumBadPixels\", \"label\": \"\", \"pv\": \"NumBadPixels\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"FlatFieldValid\", \"label\": \"\", \"pv\": \"FlatFieldValid\", \"widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalR\", \"name\": \"PixelCutOff\", \"label\": \"\", \"pv\": \"PixelCutOff_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Temp0\", \"label\": \"\", \"pv\": \"Temp0_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Temp1\", \"label\": \"\", \"pv\": \"Temp1_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Temp2\", \"label\": \"\", \"pv\": \"Temp2_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Humid0\", \"label\": \"\", \"pv\": \"Humid0_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Humid1\", \"label\": \"\", \"pv\": \"Humid1_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"Humid2\", \"label\": \"\", \"pv\": \"Humid2_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"TVXVersion\", \"label\": \"\", \"pv\": \"TVXVersion_RBV\", \"widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ResetPowerTime\", \"label\": \"\", \"pv\": \"ResetPowerTime\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"ResetPowerTime_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"DelayTime\", \"label\": \"\", \"pv\": \"DelayTime\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"DelayTime_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ThresholdEnergy\", \"label\": \"\", \"pv\": \"ThresholdEnergy\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"ThresholdEnergy_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"ThresholdAutoApply\", \"label\": \"\", \"pv\": \"ThresholdAutoApply\", \"widget\": {\"type\": \"CheckBox\"}, \"read_pv\": \"ThresholdAutoApply_RBV\", \"read_widget\": {\"type\": \"LED\"}}, {\"type\": \"SignalRW\", \"name\": \"Energy\", \"label\": \"\", \"pv\": \"Energy\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"Energy_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"MinFlatField\", \"label\": \"\", \"pv\": \"MinFlatField\", \"widget\": {\"type\": \"TextWrite\", \"lines\": 1}, \"read_pv\": \"MinFlatField_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalRW\", \"name\": \"GapFill\", \"label\": \"\", \"pv\": \"GapFill\", \"widget\": {\"type\": \"ComboBox\", \"choices\": []}, \"read_pv\": \"GapFill_RBV\", \"read_widget\": {\"type\": \"TextRead\", \"lines\": 1}}, {\"type\": \"SignalR\", \"name\": \"ProgressBarTest\", \"label\": \"\", \"pv\": \"ProgressBarTest_RBV\", \"widget\": {\"type\": \"ProgressBar\"}}]}]}";

class pilatusDetectorParamSet : public virtual ADDriverParamSet {
public:
    pilatusDetectorParamSet() {
        this->add(PilatusResetPowerString, asynParamInt32, &PilatusResetPower);
        this->add(PilatusThresholdApplyString, asynParamInt32, &PilatusThresholdApply);
        this->add(PilatusImageFileTmotString, asynParamFloat64, &PilatusImageFileTmot);
        this->add(PilatusWavelengthString, asynParamFloat64, &PilatusWavelength);
        this->add(PilatusEnergyLowString, asynParamFloat64, &PilatusEnergyLow);
        this->add(PilatusEnergyHighString, asynParamFloat64, &PilatusEnergyHigh);
        this->add(PilatusDetDistString, asynParamFloat64, &PilatusDetDist);
        this->add(PilatusDetVOffsetString, asynParamFloat64, &PilatusDetVOffset);
        this->add(PilatusBeamXString, asynParamFloat64, &PilatusBeamX);
        this->add(PilatusBeamYString, asynParamFloat64, &PilatusBeamY);
        this->add(PilatusFluxString, asynParamFloat64, &PilatusFlux);
        this->add(PilatusFilterTransmString, asynParamFloat64, &PilatusFilterTransm);
        this->add(PilatusStartAngleString, asynParamFloat64, &PilatusStartAngle);
        this->add(PilatusAngleIncrString, asynParamFloat64, &PilatusAngleIncr);
        this->add(PilatusDet2thetaString, asynParamFloat64, &PilatusDet2theta);
        this->add(PilatusPolarizationString, asynParamFloat64, &PilatusPolarization);
        this->add(PilatusAlphaString, asynParamFloat64, &PilatusAlpha);
        this->add(PilatusKappaString, asynParamFloat64, &PilatusKappa);
        this->add(PilatusPhiString, asynParamFloat64, &PilatusPhi);
        this->add(PilatusPhiIncrString, asynParamFloat64, &PilatusPhiIncr);
        this->add(PilatusChiString, asynParamFloat64, &PilatusChi);
        this->add(PilatusChiIncrString, asynParamFloat64, &PilatusChiIncr);
        this->add(PilatusOmegaString, asynParamFloat64, &PilatusOmega);
        this->add(PilatusOmegaIncrString, asynParamFloat64, &PilatusOmegaIncr);
        this->add(PilatusOscillAxisString, asynParamOctet, &PilatusOscillAxis);
        this->add(PilatusNumOscillString, asynParamInt32, &PilatusNumOscill);
        this->add(PilatusBadPixelFileString, asynParamOctet, &PilatusBadPixelFile);
        this->add(PilatusFlatFieldFileString, asynParamOctet, &PilatusFlatFieldFile);
        this->add(PilatusCbfTemplateFileString, asynParamOctet, &PilatusCbfTemplateFile);
        this->add(PilatusHeaderStringString, asynParamOctet, &PilatusHeaderString);
        this->add(PilatusArmedString, asynParamInt32, &PilatusArmed);
        this->add(PilatusNumBadPixelsString, asynParamInt32, &PilatusNumBadPixels);
        this->add(PilatusFlatFieldValidString, asynParamInt32, &PilatusFlatFieldValid);
        this->add(PilatusPixelCutOffString, asynParamInt32, &PilatusPixelCutOff);
        this->add(PilatusThTemp0String, asynParamFloat64, &PilatusThTemp0);
        this->add(PilatusThTemp1String, asynParamFloat64, &PilatusThTemp1);
        this->add(PilatusThTemp2String, asynParamFloat64, &PilatusThTemp2);
        this->add(PilatusThHumid0String, asynParamFloat64, &PilatusThHumid0);
        this->add(PilatusThHumid1String, asynParamFloat64, &PilatusThHumid1);
        this->add(PilatusThHumid2String, asynParamFloat64, &PilatusThHumid2);
        this->add(PilatusTvxVersionString, asynParamOctet, &PilatusTvxVersion);
        this->add(PilatusResetPowerTimeString, asynParamInt32, &PilatusResetPowerTime);
        this->add(PilatusDelayTimeString, asynParamFloat64, &PilatusDelayTime);
        this->add(PilatusThresholdString, asynParamFloat64, &PilatusThreshold);
        this->add(PilatusThresholdAutoApplyString, asynParamInt32, &PilatusThresholdAutoApply);
        this->add(PilatusEnergyString, asynParamFloat64, &PilatusEnergy);
        this->add(PilatusMinFlatFieldString, asynParamInt32, &PilatusMinFlatField);
        this->add(PilatusGapFillString, asynParamInt32, &PilatusGapFill);
        this->add(ProgressBarTestString, asynParamFloat64, &ProgressBarTest);

        this->paramTree = pilatusParamTree;
    }

    int PilatusResetPower;
    #define FIRST_PILATUSDETECTORPARAMSET_PARAM PilatusResetPower
    int PilatusThresholdApply;
    int PilatusImageFileTmot;
    int PilatusWavelength;
    int PilatusEnergyLow;
    int PilatusEnergyHigh;
    int PilatusDetDist;
    int PilatusDetVOffset;
    int PilatusBeamX;
    int PilatusBeamY;
    int PilatusFlux;
    int PilatusFilterTransm;
    int PilatusStartAngle;
    int PilatusAngleIncr;
    int PilatusDet2theta;
    int PilatusPolarization;
    int PilatusAlpha;
    int PilatusKappa;
    int PilatusPhi;
    int PilatusPhiIncr;
    int PilatusChi;
    int PilatusChiIncr;
    int PilatusOmega;
    int PilatusOmegaIncr;
    int PilatusOscillAxis;
    int PilatusNumOscill;
    int PilatusBadPixelFile;
    int PilatusFlatFieldFile;
    int PilatusCbfTemplateFile;
    int PilatusHeaderString;
    int PilatusArmed;
    int PilatusNumBadPixels;
    int PilatusFlatFieldValid;
    int PilatusPixelCutOff;
    int PilatusThTemp0;
    int PilatusThTemp1;
    int PilatusThTemp2;
    int PilatusThHumid0;
    int PilatusThHumid1;
    int PilatusThHumid2;
    int PilatusTvxVersion;
    int PilatusResetPowerTime;
    int PilatusDelayTime;
    int PilatusThreshold;
    int PilatusThresholdAutoApply;
    int PilatusEnergy;
    int PilatusMinFlatField;
    int PilatusGapFill;
    int ProgressBarTest;
};

#endif // PilatusDetectorParamSet_H

The existing pilatus.cpp is then modified to remove these parameters definitions and use the param set API.

Database Template File#

According to the demand and readback properties of the component, the following records are created:

# This file was automatically generated
# *** Please do not edit this file: edit the source file instead. ***

# Group: ComponentGroupOne
record(bo, "$(P)$(R)ResetPower")
{
    field(DESC, "ResetPower")
    field(DTYP, "asynInt32")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))RESET_POWER")
    field(ZNAM, "Done")
    field(ONAM, "Reset")
}

record(busy, "$(P)$(R)ThresholdApply")
{
    field(DESC, "ThresholdApply")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))THRESHOLD_APPLY")
    field(ONAM, "Apply")
}

record(ao, "$(P)$(R)ImageFileTmot")
{
    field(DESC, "Timeout for image file")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "20")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))IMAGE_FILE_TMOT")
    field(PREC, "3")
    field(EGU,  "s")
}

record(ao, "$(P)$(R)Wavelength")
{
    field(DESC, "Wavelength")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "1.54")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))WAVELENGTH")
    field(PREC, "4")
    field(EGU,  "Angstroms")
}

record(ao, "$(P)$(R)EnergyLow")
{
    field(DESC, "EnergyLow")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ENERGY_LOW")
    field(PREC, "3")
    field(EGU,  "eV")
}

record(ao, "$(P)$(R)EnergyHigh")
{
    field(DESC, "EnergyHigh")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ENERGY_HIGH")
    field(PREC, "3")
    field(EGU,  "eV")
}

record(ao, "$(P)$(R)DetDist")
{
    field(DESC, "DetDist")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "1000")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DET_DIST")
    field(PREC, "3")
    field(EGU,  "mm")
}

record(ao, "$(P)$(R)DetVOffset")
{
    field(DESC, "DetVOffset")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DET_VOFFSET")
    field(PREC, "3")
    field(EGU,  "mm")
}

record(ao, "$(P)$(R)BeamX")
{
    field(DESC, "BeamX")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))BEAM_X")
    field(PREC, "3")
    field(EGU,  "pixels")
}

record(ao, "$(P)$(R)BeamY")
{
    field(DESC, "BeamY")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))BEAM_Y")
    field(PREC, "3")
    field(EGU,  "pixels")
}

record(ao, "$(P)$(R)Flux")
{
    field(DESC, "Flux")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLUX")
    field(PREC, "4")
    field(EGU,  "ph/s")
}

record(ao, "$(P)$(R)FilterTransm")
{
    field(DESC, "FilterTransm")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "1.0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))FILTER_TRANSM")
    field(PREC, "4")
}

record(ao, "$(P)$(R)StartAngle")
{
    field(DESC, "StartAngle")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))START_ANGLE")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)AngleIncr")
{
    field(DESC, "AngleIncr")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0.1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ANGLE_INCR")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Det2theta")
{
    field(DESC, "Det2theta")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DET_2THETA")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Polarization")
{
    field(DESC, "Polarization")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0.99")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))POLARIZATION")
    field(PREC, "4")
}

record(ao, "$(P)$(R)Alpha")
{
    field(DESC, "Alpha")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ALPHA")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Kappa")
{
    field(DESC, "Kappa")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))KAPPA")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Phi")
{
    field(DESC, "Phi")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))PHI")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)PhiIncr")
{
    field(DESC, "PhiIncr")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0.1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))PHI_INCR")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Chi")
{
    field(DESC, "Chi")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))CHI")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)ChiIncr")
{
    field(DESC, "ChiIncr")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0.1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))CHI_INCR")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)Omega")
{
    field(DESC, "Omega")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))OMEGA")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(ao, "$(P)$(R)OmegaIncr")
{
    field(DESC, "OmegaIncr")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0.1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))OMEGA_INCR")
    field(PREC, "4")
    field(EGU,  "deg")
}

record(stringout, "$(P)$(R)OscillAxis")
{
    field(DESC, "OscillAxis")
    field(PINI, "YES")
    field(DTYP, "asynOctetWrite")
    field(VAL,  "X, CW")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))OSCILL_AXIS")
}

record(longout, "$(P)$(R)NumOscill")
{
    field(DESC, "NumOscill")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))NUM_OSCILL")
}

record(waveform, "$(P)$(R)BadPixelFile")
{
    field(DESC, "BadPixelFile")
    field(DTYP, "asynOctetWrite")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))BAD_PIXEL_FILE")
    field(NELM, "256")
    field(FTVL, "CHAR")
}

record(waveform, "$(P)$(R)FlatFieldFile")
{
    field(DESC, "FlatFieldFile")
    field(DTYP, "asynOctetWrite")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLAT_FIELD_FILE")
    field(NELM, "256")
    field(FTVL, "CHAR")
}

record(waveform, "$(P)$(R)CbfTemplateFile")
{
    field(DESC, "CbfTemplateFile")
    field(DTYP, "asynOctetWrite")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))CBFTEMPLATEFILE")
    field(NELM, "256")
    field(FTVL, "CHAR")
}

record(waveform, "$(P)$(R)HeaderString")
{
    field(DESC, "HeaderString")
    field(DTYP, "asynOctetWrite")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))HEADERSTRING")
    field(NELM, "68")
    field(FTVL, "CHAR")
}

record(bi, "$(P)$(R)Armed")
{
    field(DESC, "Armed")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ARMED")
    field(ZNAM, "Unarmed")
    field(ONAM, "Armed")
}

record(longin, "$(P)$(R)NumBadPixels")
{
    field(DESC, "Number of bad pixels")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))NUM_BAD_PIXELS")
}

record(bi, "$(P)$(R)FlatFieldValid")
{
    field(DESC, "Flat field valid")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))FLAT_FIELD_VALID")
    field(ZNAM, "No")
    field(ONAM, "Yes")
}

record(ai, "$(P)$(R)PixelCutOff_RBV")
{
    field(DESC, "PixelCutOff_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))PIXEL_CUTOFF")
    field(EGU,  "counts")
}

record(ai, "$(P)$(R)Temp0_RBV")
{
    field(DESC, "Temp0_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_TEMP_0")
    field(PREC, "1")
    field(EGU,  "C")
}

record(ai, "$(P)$(R)Temp1_RBV")
{
    field(DESC, "Temp1_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_TEMP_1")
    field(PREC, "1")
    field(EGU,  "C")
}

record(ai, "$(P)$(R)Temp2_RBV")
{
    field(DESC, "Temp2_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_TEMP_2")
    field(PREC, "1")
    field(EGU,  "C")
}

record(ai, "$(P)$(R)Humid0_RBV")
{
    field(DESC, "Humid0_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_HUMID_0")
    field(PREC, "1")
    field(EGU,  "%")
}

record(ai, "$(P)$(R)Humid1_RBV")
{
    field(DESC, "Humid1_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_HUMID_1")
    field(PREC, "1")
    field(EGU,  "%")
}

record(ai, "$(P)$(R)Humid2_RBV")
{
    field(DESC, "Humid2_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TH_HUMID_2")
    field(PREC, "1")
    field(EGU,  "%")
}

record(stringin, "$(P)$(R)TVXVersion_RBV")
{
    field(DESC, "TVXVersion_RBV")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynOctetRead")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))TVXVERSION")
}

record(longin, "$(P)$(R)ResetPowerTime_RBV")
{
    field(DESC, "Reset module power wait time")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))RESET_POWER_TIME")
    field(EGU,  "Seconds")
}

record(longout, "$(P)$(R)ResetPowerTime")
{
    field(DESC, "Reset module power wait time")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))RESET_POWER_TIME")
    field(EGU,  "Seconds")
}

record(ai, "$(P)$(R)DelayTime_RBV")
{
    field(DESC, "DelayTime")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DELAY_TIME")
    field(PREC, "6")
    field(EGU,  "s")
}

record(ao, "$(P)$(R)DelayTime")
{
    field(DESC, "DelayTime")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DELAY_TIME")
    field(PREC, "6")
    field(EGU,  "s")
}

record(ai, "$(P)$(R)ThresholdEnergy_RBV")
{
    field(DESC, "Energy threshold")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))THRESHOLD")
    field(PREC, "3")
    field(EGU,  "keV")
}

record(ao, "$(P)$(R)ThresholdEnergy")
{
    field(DESC, "Energy threshold")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "10.000")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))THRESHOLD")
    field(PREC, "3")
    field(EGU,  "keV")
}

record(bi, "$(P)$(R)ThresholdAutoApply_RBV")
{
    field(DESC, "ThresholdAutoApply")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))THRESHOLD_AUTO_APPLY")
    field(ZNAM, "No")
    field(ONAM, "Yes")
}

record(bo, "$(P)$(R)ThresholdAutoApply")
{
    field(DESC, "ThresholdAutoApply")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "1")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))THRESHOLD_AUTO_APPLY")
    field(ZNAM, "No")
    field(ONAM, "Yes")
}

record(ai, "$(P)$(R)Energy_RBV")
{
    field(DESC, "X-ray Energy")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ENERGY")
    field(PREC, "3")
    field(EGU,  "keV")
}

record(ao, "$(P)$(R)Energy")
{
    field(DESC, "X-ray Energy")
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(VAL,  "20.000")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))ENERGY")
    field(PREC, "3")
    field(EGU,  "keV")
}

record(longin, "$(P)$(R)MinFlatField_RBV")
{
    field(DESC, "Minimum flat field value")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))MIN_FLAT_FIELD")
    field(EGU,  "Counts")
}

record(longout, "$(P)$(R)MinFlatField")
{
    field(DESC, "Minimum flat field value")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "100")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))MIN_FLAT_FIELD")
    field(EGU,  "Counts")
}

record(mbbi, "$(P)$(R)GapFill_RBV")
{
    field(DESC, "GapFill")
    field(SCAN, "I/O Intr")
    field(DTYP, "asynInt32")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))GAP_FILL")
    field(ZRVL, "2")
    field(ONVL, "0")
    field(TWVL, "-1")
    field(ZRST, "N.A.")
    field(ONST, "0")
    field(TWST, "-1")
}

record(mbbo, "$(P)$(R)GapFill")
{
    field(DESC, "GapFill")
    field(PINI, "YES")
    field(DTYP, "asynInt32")
    field(VAL,  "0")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))GAP_FILL")
    field(ZRVL, "2")
    field(ONVL, "0")
    field(TWVL, "-1")
    field(ZRST, "N.A.")
    field(ONST, "0")
    field(TWST, "-1")
}

record(ai, "$(P)$(R)ProgressBarTest_RBV")
{
    field(DESC, "ProgressBar")
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))PROGRESS")
    field(PREC, "4")
    field(EGU,  "deg")
}

The top level pilatus.template includes this file, as well as records that provide logic (for things like the arrayRate and EPICSShutter in areaDetector).

UI#

Finally, UI elements can be generated for each component for multiple graphical applications. For example, the following EDM screen is generated:

../_images/pilatus_edl.png

This can serve as a low level overview of the entire system, as well as a convenient pallette for constructing higher level, more structured screens.

Ongoing Development#

Once a module is working with PVI (either an existing module after the YAML is created from the templates using the one time generation script, or a newly written module) it will then be necessary to update the YAML file in future development. Here is an example of necessary changes to add a new parameter, with and without PVI:

With PVI#

Update YAML file:

- type: AsynFloat64
  name: DelayTime
  description: Delay in seconds between the external trigger and the start of image acquisition
  role: Setting
  initial: 0
  record_fields:
    PREC: 3
    EGU: s

And then run pvi (or possibly just make, if it is integrated into a Makefile). It can then be shared with other sites who can generate their own required files.

Without PVI#

Update template:

# Delay time in External Trigger mode.
record(ao, "$(P)$(R)DelayTime")
{
    field(PINI, "YES")
    field(DTYP, "asynFloat64")
    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DELAY_TIME")
    field(EGU,  "s")
    field(VAL,  "0")
    field(PREC, "6")
}

record(ai, "$(P)$(R)DelayTime_RBV")
{
    field(DTYP, "asynFloat64")
    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))DELAY_TIME")
    field(EGU,  "s")
    field(PREC, "6")
    field(SCAN, "I/O Intr")
}

Update header file:

...
#define PilatusDelayTimeString "DELAY_TIME"
...
createParam(PilatusDelayTimeString, asynParamFloat64, &PilatusDelayTime);
...
int PilatusDelayTime;
...

Update docs:

* - Delay in seconds between the external trigger and the start of image acquisition
  - DELAY_TIME
  - $(P)$(R)DelayTime
  - ao

Update screens (of course, this will actually involve editing with a graphical interface):

"text update" {
    object {
        x=604
        y=146
        width=80
        height=18
    }
    monitor {
        chan="$(P)$(R)DelayTime_RBV"
        clr=54
        bclr=4
    }
    align="horiz. centered"
    limits {
    }
}
"text entry" {
    object {
        x=540
        y=145
        width=59
        height=20
    }
    control {
        chan="$(P)$(R)DelayTime"
        clr=14
        bclr=51
    }
    limits {
    }
}
text {
    object {
        x=435
        y=145
        width=100
        height=20
    }
    "basic attribute" {
        clr=14
    }
    textix="Delay time"
    align="horiz. right"
}

Then either add equivalent changes to other screen types or use autoconvert, if available, and add any site specific details to any of these files (such as autosave and archiver tags).

Class Hierarchy#

Drivers will access their parameters via a param set, either using inheritance or composition. The class hierarchy for param sets mirrors the drivers. Each of the ‘base’ classes (classes not instantiated directly) has-a paramSet containing its parameters in addition to its parent class(es). The most derived classes inherit their param sets so that they have direct access to all parameter indexes (and so that the source code does not have to change to insert paramSet-> to access them).

There is a new method asynPortDriver::createParams that iterates the member vector of asynParamSet storing parameter definitions and calls asynPortDriver::createParam (no ‘s’) on each of them. If the vector is empty (i.e. if it only has the default asynParamSet and not a specific implementation) it has no effect. This means asynPortDriver can be inherited from as before with no change.

Virtual inheritance is required for two reasons. Primarily, it ensures only a single instance of asynParamSet is created and it is shared throughout the class hierarchy to ensure asynPortDriver can find the child parameters. It also means that the most derived class must call the constructors for all virtual base classes before the non-virtual base classes. This means the constructors are called in the correct order such that when the asynPortDriver constructor the asynParamSet parameterDefinitions is fully populated when createParams is called.

Change Summary#

  • asyn : - Created asynParamSet

    • New overloaded asynPortDriver constructor that takes an asynParamSet* and calls createParams()

  • ADCore : - asynNDArrayDriver parameters split into asynNDArrayDriverParamSet : Constructor updated to take an asynNDArrayDriverParamSet*. Updated to access parameters via paramSet->

    • ADDriver parameters split into ADDriverParamSet : Constructor updated to take an ADDriverParamSet*. Updated to access parameters via paramSet->

    • NDPluginDriver inherits asynNDArrayDriverParamSet in addition to asynNDArrayDriver : Updated to access parameters via paramSet->. Child classes work with no changes

    • Some trivial updates to the tests

  • ADSimDetector : - simDetector parameters split into simDetectorParamSet

    • simDetector inherits from simDetectorParamSet in addition to ADDriver

    • Can access parameters as before

  • ADPilatus : - Equivalent to ADSimDetector changes

  • motor : - asynMotorController parameters split into asynMotorControllerParamSet

    • Updated to access parameters via paramSet->

  • pmac : - pmacController parameters split into pmacControllerParamSet

    • pmacCSController same

    • Each inherit from their own param set (which inherits asynMotorControllerParamSet) in addition to asynMotorController

    • Can access parameters as before

Caveats#

There are some changes that are unavoidable without inserting edge cases into the generation logic and making the YAML schema more complicated. Some examples are:

  1. The first param index used for calling base class methods is inconsistently named, so we will have to agree a consistent way to generate them and make them the same.

  2. Any readback parameters will have an _RBV suffix added. Some existing readbacks do not have this, e.g. Armed in pilatusDetector.

  3. FIRST_DRIVER_PARAM needs to be defined in the main header file based on the FIRST_DRIVER_PARAM_INDEX defined in the param set header file, appending paramSet-> or not depending on whether it inherits the param set or not. (This could possibly be handled in a better way by adding more logic to the asynParamSet - see [Possible Further Work])

  4. Asyn parameter names will be the same as the name of the index variable. The value can be overridden to define drvInfo for drvUserCreate dynamic parameters.

Next Steps#

A script is in development to perform the generation of an initial YAML file from a template. The idea being that after this point, everything is generated from the YAML file and any changes are made there and everything regenerated. New drivers can use a YAML file from the start.

The current hierarchy (base classes have-a param set while the most derived class is-a param set) is inconsistent and confusing, but it has the benefit that people are not forced to change drivers inheriting from these base classes to access parameters via paramSet->, they just need to inherit the parent param set. It also means that the most derived classes cannot be inherited from alongside an extended param set (this is not necessarily a problem, but it seems like an unnecessary restriction). It would be clearer to remove this and require all child classes to use the param set explicitly, removing the need for virtual inheritance. This would just need an addition to the extern C calls to create the param set and pass it into the constructor of the driver. Another option is to create a class that inherits from the driver and the param set, with no additional logic. This could then instantiate the param set and pass it to the driver constructor. Either solution would resolve caveat 3, because all classes will access FIRST_DRIVER_PARAM via paramSet->.

Possible Further Work#

Adopting this framework could make it easier to make other improvements to the C++ code, such as:

  • Move some asynPortDriver functionality into asynParamSet / asynParam (See ADEiger eigerParam) : - Reduce the size of asynPortDriver

    • Possibility of typed subclasses of asynParam to reduce if statements for handling the many asynParamType values in slightly different ways

  • Simplify the sharing of file writing functionality between some drivers : - ADPilatus and NDPluginFile-derived classes - Parameters could be split out of asynNDArrayDriver into a FileWriterParamSet, which could then be included via composition only where required, rather than every driver and plugin under asynNDArrayDriver having these parameters.