UK Astronomy Technology Centre Chris Tierney
Royal Observatory, Edinburgh 31st March 2001

Source code files supplied with the NAOMI EPICS software, with reference to the Pickoff assembly

All of the source code for the NAOMI mechanism control software is located in the directory naomiMechs/src, under the top-level NAOMI software directory.

The source code files fall into the following categories:

Description of devAssControl_pickoff.c

The structure of the assembly code is the same for each of the NAOMI assemblies. Device support for the assemblyControl record must provide the following functions, given in the file devAssControl.h:
typedef struct {
    long            number;
    DEVSUPFUN       devReport;
    DEVSUPFUN       devInit;
    DEVSUPFUN       initDeviceSupport;
    DEVSUPFUN       devGetIoIntInfo;
    DEVSUPFUN       checkAttributes;
    DEVSUPFUN       stopDirective;
    DEVSUPFUN       initMode;
    DEVSUPFUN       moveMode;
    DEVSUPFUN       trackMode;
    DEVSUPFUN       jogMode;
    DEVSUPFUN       indexMode;
    DEVSUPFUN       testMode;
    DEVSUPFUN       ackReceived;
    DEVSUPFUN       updateMode;
} ASSEMBLY_CONTROL_DSET;

In practice, the devReport and devGetIoIntInfo functions are not implemented for any of the assemblies. The device support functions implemented for the pickoff assembly can be found listed at the top of devAssControl_pickoff.c:

/*
 *  Device support function prototypes
 */

static long pickAckReceived(ASSEMBLY_CONTROL_RECORD *);
static long pickCheckAttributes(ASSEMBLY_CONTROL_RECORD *);
static long pickIndexMode (ASSEMBLY_CONTROL_RECORD *);
static long pickInitDeviceSupport(ASSEMBLY_CONTROL_RECORD *);
static long pickInitMode (ASSEMBLY_CONTROL_RECORD *);
static long pickMoveMode (ASSEMBLY_CONTROL_RECORD *);
static long pickStopDirective(ASSEMBLY_CONTROL_RECORD *);
static long pickTestMode (ASSEMBLY_CONTROL_RECORD *);
static long pickTrackMode (ASSEMBLY_CONTROL_RECORD *);
static long pickJogMode (ASSEMBLY_CONTROL_RECORD *);
static long pickUpdateMode (ASSEMBLY_CONTROL_RECORD *);

The functions are called by record support at the following times:

Mode-specific device support functions

Record support responds to a START directive by calling the checkAttributes() function, followed by one of the mode-specific device support functions, depending upon the current value of the MODE field of the record.

Some of these functions (for TEST and UPDATE modes, for example) take very little action and return. These modes are not implemented in the NAOMI software. The other modes (INIT, INDEX, MOVE, TRACK, JOG and the stopDirective() function), however, respond by building a list of tasks to perform, starting the first task, and returning. When the task is complete, either by callback (timeout) or when one or more of the devices has returned to the IDLE state, the ackReceived() function clears the current task from the list and begins the next one. When all tasks are complete, ackReceived informs record support that the assemblyControl record may return to the IDLE state from BUSY.

We examine here the operation of the pickIndexMode() and pickMoveMode() functions.

This list of tasks defined for this assembly is enumerated at the top of the file:

/*
 * List of tasks to ask the Assembly to do.
 */

typedef enum
{
    PICK_IX_DEV1_LOW       = 1, 
    PICK_IX_DEV1_HIGH      = 2, 
    PICK_IX_DEV2_LOW       = 3, 
    PICK_IX_DEV2_HIGH      = 4, 
    PICK_IX_DEV3_LOW       = 5, 
    PICK_IX_DEV3_HIGH      = 6, 
    PICK_IX_DEV4_HOME      = 7, 
    PICK_IX_DEV5_LOW       = 8,   
    PICK_IX_DEV5_HIGH      = 9, 
    PICK_IX_DEV1_REIX      = 10, 
    PICK_IX_DEV2_REIX      = 11, 
    PICK_IX_DEV3_REIX      = 12, 
    PICK_IX_DEV4_REIX      = 13, 
    PICK_IX_DEV5_REIX      = 14, 
    PICK_MV_ALL            = 15,
    PICK_MV_DEV1           = 16,
    PICK_MV_DEV2           = 17,
    PICK_MV_DEV3           = 18,
    PICK_MV_DEV4           = 19,
    PICK_MV_DEV5           = 20,
    PICK_MV_DEV5_SAFE      = 21,
    PICK_JG_ALL            = 22,
    PICK_JG_DEV1           = 23,
    PICK_JG_DEV2           = 24,
    PICK_JG_DEV3           = 25,
    PICK_JG_DEV4           = 26,
    PICK_JG_DEV5           = 27,
    PICK_INIT_ALL          = 28,
    PICK_INIT_DEV1         = 29,
    PICK_INIT_DEV2         = 30,
    PICK_INIT_DEV3         = 31,
    PICK_INIT_DEV4         = 32,
    PICK_INIT_DEV5         = 33,
    PICK_STOP_ALL          = 34
} tPickTaskList;

Those mode-specific functions that require a task list call the internal function pickBuildList(), which examines the current mode and constructs a task list accordingly. The list constructed when in INDEX mode is specified near the top of the file:

static ASS_TASK_LIST  pickIndex[] = {
    { PICK_IX_DEV5_LOW,    FALSE, FALSE, FALSE, FALSE, TRUE  },
    { PICK_MV_DEV5_SAFE,   FALSE, FALSE, FALSE, FALSE, TRUE  },
    { PICK_IX_DEV3_HIGH,   FALSE, FALSE, TRUE,  FALSE, FALSE },
    { PICK_IX_DEV1_HIGH,   TRUE,  FALSE, FALSE, FALSE, FALSE },
    { PICK_IX_DEV1_REIX,   TRUE,  FALSE, FALSE, FALSE, FALSE },
    { PICK_IX_DEV3_LOW,    FALSE, FALSE, TRUE,  FALSE, FALSE },
    { PICK_IX_DEV3_REIX,   FALSE, FALSE, TRUE,  FALSE, FALSE },
    { PICK_IX_DEV5_LOW,    FALSE, FALSE, FALSE, FALSE, TRUE  },
    { PICK_IX_DEV5_REIX,   FALSE, FALSE, FALSE, FALSE, TRUE  },
    { PICK_MV_DEV5,        FALSE, FALSE, FALSE, FALSE, TRUE  },
    { PICK_MV_DEV1,        TRUE,  FALSE, FALSE, FALSE, FALSE },
    { PICK_MV_DEV3,        FALSE, FALSE, TRUE,  FALSE, FALSE },
    { PICK_IX_DEV2_HIGH,   FALSE, TRUE,  FALSE, FALSE, FALSE },
    { PICK_IX_DEV2_REIX,   FALSE, TRUE,  FALSE, FALSE, FALSE },
    { PICK_MV_DEV2,        FALSE, TRUE,  FALSE, FALSE, FALSE },
    { PICK_IX_DEV4_HOME,   FALSE, FALSE, FALSE, TRUE,  FALSE },
    { PICK_MV_DEV4,        FALSE, FALSE, FALSE, TRUE,  FALSE }
};

Note that the tasks are given in the order in which they will be performed. The five boolean entries given on each line specify which devices should be operated for each task. So, for instance, the first task is an INDEX to the lower limit switch from the fifth device, the CCD assembly. When the device BUSY state has undergone an IDLE-BUSY-IDLE transition, pickAckReceived() clears this task from the list of tasks maintained by the device support code and proceeds to the next task.

The list of tasks above implement the indexing procedure detailed in the documentation for the pickoff assembly screen.

pickBuildList() (after constructing a task list) and pickAckReceived() (when a task has completed) both call the function pickDoTask() to execute the next task. This function looks at the task being executed, fills an internal structure (of type ASS_DEV_PRIVATE, see file devAssControl_general.h) with appropriate motion parameters for the required devices, and calls the function pickExecuteTask() to setup and start the devices. The first task above, for example, tells pickDoTask() that device 5 must be sent a mode of MOVE, a default velocity, and a target position string "ixlow". pickExecuteTask() sends these parameters, followed by the GO directive, to the device.

The list of tasks for the assembly's MOVE mode is as follows:

static ASS_TASK_LIST  pickMoveAll[] = {
    { PICK_MV_ALL,             TRUE,  TRUE,  TRUE,  TRUE, TRUE } 
};

A move operation consists of a single task, that of moving all devices simultaneously. For this task, the pickDoTask() uses function pickMoveParameters() to calculate the motion parameters (velocity, target position etc) for each device. This is an important function which contains the algorithms that ensure that the wavefront sensor will maintain focus whilst the pickoff probe (devices 1 and 2, for this assembly) is being moved. Other assemblies have an analogous function.

[Note: In fact the single device moves, for example PICK_MV_DEV3 used in the index task list above, utilise the same function, in order that the wavefront sensor pickoff assembly finishes an index operation in focus.]

The reader is invited to examine the function (which is rather complex to reproduce here) if desired. The function implements the algorithms described in the documentation for the pickoff assembly screen, for calculating the required positions of each stage, based upon the (numeric or named position) strings found in record input fields A though E. If required (input attribute G), velocities are calculated such that the devices will finish motion at the same time. If not, default velocities are used.

Named positions for each of the devices, and offsets and parameters used in the pickMoveParameters() algorithms, are contained in pick_assembly.lut, the lookup table for the pickoff assembly.

A useful examination of the operation of the assemblyControl record can be acheived if the user changes the debug mode of the record. A menu for changing the debug mode can be found on the assemly screen.