areaDetector Cameralink driver

  February 24, 2016

Timothy J. Madden, Argonne National Laboratory


Table of Contents

Introduction

This is an EPICS areaDetector driver for any detector using raw serial communication to a Camera Link frame grabber. The driver is in use at the Advanced Photon Source to control the high speed Dimax and sCMOS Edge cameras from PCO, as well as the custom APS-designed Platinum detector. The Cameralink driver currently supports Windows 32 and 64 bit platforms, but will soon support Linux. ADCameralink is a class library to be inherited by detector drivers. There is no iocs directory as ADCameralink is not intended to be built into a stand-alone application. 

There are two parts to ADCameralink. A driver called ADCameralink inherits from ADDriver provides functions for grabbing images from the Camera Link frame grabber.Also, camLinkSerial, which inherits asynPortDriver, provides serial port I/O  similar to drvAsynSerialPort.  

The Camera Link frame grabbers ship with a software API and library. This driver hides all frame grabber API calls in a C++ interface called grabberInterface.h. To support new frame grabbers, a developer muvst write a new C++ class implementing grabberInterface.h specific to that frame grabber. The Makefile should be changed to link against the new grabber vendor libraries. The grabber vendor libraries are available from the vendors. The Silicon Software libraries can be downloaded here. ADCameralink specifically supports the Micro Enable IV grabber from Silicon Software. The Dalsa drivers require the purchase of a license of their software called Sapera.  Because Dalsa used to be called Coreco, the source code in this driver refers to "Coreco" rather than Dalsa.



CameraLink specific parameters

The ADCameralink driver implements the following parameters in addition to those in asynNDArrayDriver.h and ADDriver.h.


Parameter Definitions in ADCameraLink.h and EPICS Record Definitions in coreco.template
Parameter index variable asyn interface Access Description drvInfo string EPICS record name EPICS record type
cor_run_counter
asynInt32 R Increments when image grab thread runs.
cor_run_counter
$(P)$(R)cor_run_counter longin
cor_frame_to_null
asynInt32 WR counts thrown away frames.
cor_frame_to_null
$(P)$(R)cor_frame_to_null_RBV $(P)$(R)cor_frame_to_null longin longout
cor_is_grab
asynInt32 WR 1 for grab mode, 0 does nothing.
cor_is_grab
$(P)$(R)cor_is_grab_RBV $(P)$(R)cor_is_grab longin longout
cor_num_coreco_buffers
asynInt32 WR Number of buffers on grabber.
cor_num_coreco_buffers
$(P)$(R)cor_num_coreco_buffers_RBV $(P)$(R)cor_num_coreco_buffers longin longout
cor_check_timestamps
asynInt32 WR check for lost frames by examening time stamps.
cor_check_timestamps
$(P)$(R)cor_check_timestamps_RBV $(P)$(R)cor_check_timestamps longin longout
cor_check_timestamps
asynInt32 R Descripttion
cor_check_timestamps
$(P)$(R)cor_num_buffers_RBV longin
cor_num_free_buffers
asynInt32 R have to fix this...
cor_num_free_buffers
$(P)$(R)cor_num_free_buffers_RBV longin
cor_is_abort
asynInt32 WR 1 to abort grab mode. 0 to do nothing.
cor_is_abort
$(P)$(R)cor_is_abort_RBV $(P)$(R)cor_is_abort longin longout
cor_grabber_type
asynInt32 R Tells which vender made grabber.
cor_grabber_type
$(P)$(R)cor_grabber_type_RBV longin
cor_is_freeze
asynInt32 WR 1 to freeze image grabbing.
cor_is_freeze
$(P)$(R)cor_is_freeze_RBV $(P)$(R)cor_is_freeze longin longout
cor_is_snap
asynInt32 WR 1 to snap one frame.
cor_is_snap
$(P)$(R)cor_is_snap_RBV $(P)$(R)cor_is_snap longin longout
cor_is_loadccf
asynInt32 W write 1 to load grabber config. file.
cor_is_loadccf
$(P)$(R)cor_is_loadccf longout
cor_use_fpga
asynInt32 R 1 if we are using fpga on grabber. Only dalsa Andaconda has fpga.
cor_use_fpga
$(P)$(R)cor_use_fpga mbbo
cor_is_load_fpga_regs
asynInt32 W Load foga regs from file.
cor_is_load_fpga_regs
$(P)$(R)cor_is_load_fpga_regs longout
cor_is_read_fpga_regs
asynInt32 W Dump fpga registers to screen.
cor_is_read_fpga_regs
$(P)$(R)cor_is_read_fpga_regs longout
cor_ccf_filename
asynOctetWrite WR Nema of config. file.
cor_ccf_filename
$(P)$(R)cor_ccf_filename $(P)$(R)cor_ccf_filename_RBV stringout stringin
cor_fpga_command
asynInt32 R Command sent to FPGA.
cor_fpga_command
$(P)$(R)cor_fpga_command_RBV mbbi
cor_fpga_num_imgs2ave
asynInt32 WR Number of frames for FPGA to average.
cor_fpga_num_imgs2ave
$(P)$(R)cor_fpga_num_imgs2ave $(P)$(R)cor_fpga_num_imgs2ave_RBV longout longin
cor_compression_rate
asynInt32 WR Compression rate done on FPGA.
cor_compression_rate
$(P)$(R)cor_compression_rate $(P)$(R)cor_compression_rate_RBV longout longin
cor_fpga__reg_filename
asynOctetWrite WR Filename of FPGA register settings.
cor_fpga__reg_filename
$(P)$(R)cor_fpga_reg_filename $(P)$(R)cor_fpga_reg_filename_RBV stringout stringin
cor_is_sleep
asynInt32 W 1 to sleep every time image grab thread loops.
cor_is_sleep
$(P)$(R)cor_is_sleep longout
cor_sleep_ms
asynInt32 W How long image thread sleeps between loops.
cor_sleep_ms
$(P)$(R)cor_sleep_ms longout
cor_fpga_filename
asynOctetWrite WR name of FPGA firmware to load into FPGA,
cor_fpga_filename
$(P)$(R)cor_fpga_filename $(P)$(R)cor_fpga_filename_RBV stringout stringin
cor_input_filename
asynOctetWrite WR to simulate camera, name if iamge to load into grabber from file.
cor_input_filename
$(P)$(R)cor_input_filename $(P)$(R)cor_input_filename_RBV stringout stringin
cor_dark_filename
asynOctetWrite WR name if file to which dark image is saved.
cor_dark_filename
$(P)$(R)cor_dark_filename $(P)$(R)cor_dark_filename_RBV stringout stringin
cor_fpga_save_dark
asynInt32 W 1 to dave darks.
cor_fpga_save_dark
$(P)$(R)cor_fpga_save_dark longout
cor_input_from_file
asynInt32 R 1 to read image from disk into grabber.
cor_input_from_file
$(P)$(R)cor_input_from_file mbbo
cor_load_img_file
asynInt32 W deprecated?
cor_load_img_file
$(P)$(R)cor_load_img_file longout
cor_make_viewer
asynInt32 W display debug viewer, from grabber library. 
cor_make_viewer
$(P)$(R)cor_make_viewer longout
cor_sub_flag
asynInt32 R 1 for FPGA dark subtraction.
cor_sub_flag
$(P)$(R)cor_sub_flag_RBV longin
cor_comp_flag
asynInt32 R 1 for FPGA compression.
cor_comp_flag
$(P)$(R)cor_comp_flag_RBV longin
cor_acc_flag
asynInt32 R 1 for FPGA accumulation.
cor_acc_flag
$(P)$(R)cor_acc_flag_RBV longin
cor_store_flag
asynInt32 R FPGA low level flag
cor_store_flag
$(P)$(R)cor_store_flag_RBV longin
cor_read_flag
asynInt32 R FPGA low level flag  cor_read_flag
$(P)$(R)cor_read_flag_RBV longin
cor_saw_flag
asynInt32 R FPGA low level flag  cor_saw_flag
$(P)$(R)cor_saw_flag_RBV longin
cor_dec_flag
asynInt32 R FPGA low level flag  cor_dec_flag
$(P)$(R)cor_dec_flag_RBV longin
cor_abs_flag
asynInt32 R FPGA low level flag  cor_abs_flag
$(P)$(R)cor_abs_flag_RBV longin
cor_comp_threshold
asynInt32 WR Threshiold for image compression.
cor_comp_threshold
$(P)$(R)cor_comp_threshold_RBV $(P)$(R)cor_comp_threshold longin longout
cor_frame_dec_rate
asynInt32 WR Compression rate.
cor_frame_dec_rate
$(P)$(R)cor_frame_dec_rate_RBV $(P)$(R)cor_frame_dec_rate longin longout
cor_load_dark_2_fpga
asynInt32 W Load dark from file into FPGA.
cor_load_dark_2_fpga
$(P)$(R)cor_load_dark_2_fpga longout
cor_coreco_message
asynOctetRead R Error messages from grabber vendor library.
cor_coreco_message
$(P)$(R)cor_coreco_message_RBV stringin
cor_cant_get_ndarray
asynInt32 WR 1 if we can't get ND array. Error condition.
cor_cant_get_ndarray
$(P)$(R)cor_cant_get_ndarray $(P)$(R)cor_cant_get_ndarray_RBV longout longin
cor_num_repeat_timestamp
asynInt32 WR 1 if image timestamp is repeated, meaning repeated frame.
cor_num_repeat_timestamp
$(P)$(R)cor_num_repeat_timestamp_RBV $(P)$(R)cor_num_repeat_timestamp longin longout
cor_num_missed_timestamp
asynInt32 WR 1 for missed timestamp, for missed frame. If timestamp increments longer than sime time, then we missed a stamp.
cor_num_missed_timestamp
$(P)$(R)cor_num_missed_timestamp_RBV $(P)$(R)cor_num_missed_timestamp longin longout
cor_missed_ts_wait
asynInt32 WR time above which we assume a missed frame.
cor_missed_ts_wait
$(P)$(R)cor_missed_ts_wait_RBV $(P)$(R)cor_missed_ts_wait longin longout
cor_nd_datasize
asynInt32 R Data size in nd array.
cor_nd_datasize
$(P)$(R)cor_nd_datasize_RBV longin
cor_est_buffers_left
asynInt32 R Estimated ND Arraus left.
cor_est_buffers_left
$(P)$(R)cor_est_buffers_left_RBV longin
cor_max_ndbuffers
asynInt32 R Max ND Arrays we can store.
cor_max_ndbuffers
$(P)$(R)cor_max_ndbuffers_RBV longin
cor_max_ndmemory
asynInt32 R Max ND Arrauy memory.
cor_max_ndmemory
$(P)$(R)cor_max_ndmemory_RBV longin
cor_free_ndbuffers
asynInt32 R Free NDArraus.
cor_free_ndbuffers
$(P)$(R)cor_free_ndbuffers_RBV longin
cor_num_ndbuffers
asynInt32 R Number of created ND Arrauys.
cor_num_ndbuffers
$(P)$(R)cor_num_ndbuffers_RBV longin
cor_alloc_ndmemory
asynInt32 R Amount of created ND Array memory.
cor_alloc_ndmemory
$(P)$(R)cor_alloc_ndmemory_RBV longin
cor_total_missed_frames
asynInt32 WR counts total missed frames forever.
cor_total_missed_frames
$(P)$(R)cor_total_missed_frames $(P)$(R)cor_total_missed_frames_RBV longout longin
cor_recent_missed_frames
asynInt32 WR counts missed frames since last check.
cor_recent_missed_frames
$(P)$(R)cor_recent_missed_frames $(P)$(R)cor_recent_missed_frames_RBV longout longin
cor_num_buff_frames
asynInt32 R Number of buffers on grabber.
cor_num_buff_frames
$(P)$(R)cor_num_buff_frames_RBV longin
cor_num_bad_fpga_headers
asynInt32 WR 1 for bad FPGA data.
cor_num_bad_fpga_headers
$(P)$(R)cor_num_bad_fpga_headers $(P)$(R)cor_num_bad_fpga_headers_RBV longout longin
cor_sap_buffer_count
asynInt32 WR Number of buffers in grabber.
cor_sap_buffer_count
$(P)$(R)cor_sap_buffer_count $(P)$(R)cor_sap_buffer_count_RBV longout longin
cor_comp_num_images
asynInt32 R Number of FPGA compressed iamges in one frame.
cor_comp_num_images
$(P)$(R)cor_comp_num_images_RBV longin
cor_comp_pixels0
asynInt32 R Num pixels in comp image.
cor_comp_pixels0
$(P)$(R)cor_comp_pixels0_RBV longin
cor_comp_pixels_error
asynInt32 R Error on compression.
cor_comp_pixels_error
$(P)$(R)cor_comp_pixels_error_RBV longin
cor_max_comp_pixels
asynInt32 R Max num pixels we can put into compressed iamge.
cor_max_comp_pixels
$(P)$(R)cor_max_comp_pixels_RBV longin
cor_compression_error
asynInt32 R Error on compression.
cor_compression_error
$(P)$(R)cor_compression_error_RBV longin
cor_num_thresh_std
asynFloat64 WR Number of std.deviations of noise for compression threshold.
cor_num_thresh_std
$(P)$(R)cor_num_thresh_std $(P)$(R)cor_num_thresh_std_RBV ao ai
cor_fpga_usr_command
asynInt32 WR Command sent to FPGA.
cor_fpga_usr_command
$(P)$(R)cor_fpga_usr_command $(P)$(R)cor_fpga_usr_command_RBV mbbo mbbi
cor_filename_in_fpga
asynOctetRead R FPGA filename.
cor_filename_in_fpga
$(P)$(R)cor_filename_in_fpga_RBV stringin
cor_use_image_mode
asynInt32 WR Set FPGA algoration.
cor_use_image_mode
$(P)$(R)cor_use_image_mode_RBV $(P)$(R)cor_use_image_mode longin longout
cor_is_trigpin0
asynInt32 WR Set grabber trigger pin 1, 0
cor_is_trigpin0
$(P)$(R)cor_is_trigpin0_RBV $(P)$(R)cor_is_trigpin0 longin longout
cor_is_trigpin1
asynInt32 WR Set grabber trigger pin 1, 0   cor_is_trigpin1
$(P)$(R)cor_is_trigpin1_RBV $(P)$(R)cor_is_trigpin1 longin longout
cor_is_trigpin2
asynInt32 WR Set grabber trigger pin 1, 0   cor_is_trigpin2
$(P)$(R)cor_is_trigpin2_RBV $(P)$(R)cor_is_trigpin2 longin longout
cor_is_trigpin3
asynInt32 WR Set grabber trigger pin 1, 0   cor_is_trigpin3
$(P)$(R)cor_is_trigpin3_RBV $(P)$(R)cor_is_trigpin3 longin longout


Configuration

When using ADCameralink, first open the serial port on the frame grabber using drvCamlinkSerial. The two arguments are the name of the asyn port, "SERIAL," and the name of the serial port, "COM2." The com port name depends on the type of grabber. The Dalsa grabber maps its serial port to a COM port in the Windows system. The Silicon Software grabber does no such mapping, and the com port name "COM2" below is actually ignored. The reason is that when the driver is built, it is linked against the grabber vendor libraries.

drvCamlinkSerialConfigure("SERIAL","COM2");

Once the serial port is configured, its asyn port is passed to the camera driver that inherits ADCameralink

int myCameralinkDetector(const char *portName, const char *serverPort, int maxBuffers,
              size_t maxMemory, int priority, int stackSize),

where:
portName: asyn port of the PCO camera
serverPort: serial port passed to the driver
maxBuffers: max number of NDArrays in the queue.
maxMemory: -1, for no max limit.
priority: thread priority between 0 and 100. 50 is in the middle.
stackSize: stack size for asynPort thread in "Can block mode." See ADDriver docs for more info.


ADCameralink has no iocs directory because it is meant to be a class library that is used by specific camera drivers.


MEDM screens

One screen is provided for ADCameralink. The screen is used to pick a configuration file for the grabber, monitor memory usage, and turn on and off image grabbing.
Some grabbers contain a user-programmable FPGA. PVs are provided to allow setting up the FPGA.