esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% ccd.mac
#%NAME%
#  General macros for all CCD cameras
#%CATEGORY% Detection, Ccd
#
#%LOG%
#
#$Revision: 5.56 $
#$Log: ccd.mac,v $
#Revision 5.56  2023/03/20 14:20:24  guilloud
#fix test of VERSION + ccd_is_ok_and_on()
#
#Revision 5.55  2023/02/13 12:54:17  guilloud
#fix typo preventing good initialization of CCD_DS.
#
#Revision 5.54  2021/12/02 11:19:35  guilloud
#fix for active/unactive CCD device
#+ccds_check() +ccd_is_ok(ccd_config_index, verbose)
#
#Revision 5.53  2021/07/28 15:02:13  claustre
#Fixed bug with local variable in ccdoff + fix ccdresetupall with version-dependent code
#
#Revision 5.52  2021/03/17 13:26:57  guilloud
#fix bug to avoid to be on CCD with greatest index after ccdmenu.
# update ccd_pc_devinfo
# some typo
#
#Revision 5.51  2021/02/22 17:04:59  witsch
#correction of the macros starting and stopping a gui. Under some circumstances, 
#the kill for the gui could stop the entire X11 system.
#
#Revision 5.50  2021/02/02 15:53:05  mauro
#CCD_ON is disabled when the camera is off. It avoids unnecessary image_par.
#
#Revision 5.49  2021/01/25 13:59:59  mauro
#fixed ccdoff  including image_par(ccd_u,"unusable") for spec versions <6.06.01
#
#Revision 5.48  2020/03/24 18:03:36  witsch
#In macro _ccdmenu CCDS is the number of CCDS with YES in config !!!
#However there might be one with a YES which might still not be usable.

###### hummm
# CCDS builtin is : 1 + index of last CCD in the config list.
#                   including YES OFF and NO controller.
#
# Example:
# Image          DEVICE   ADDR  <>MODE                                      <>TYPE
#  0  YES                    1              AI Solutions DAQ-ATDC (master) 2D (US>
#  1   NO
#  2  YES                    1              AI Solutions DAQ-ATDC (master) 2D (US>
#  3  OFF                    1              AI Solutions DAQ-ATDC (master) 2D (US>
#  4  YES                    1              AI Solutions DAQ-ATDC (master) 2D (US>
#  5   NO
#
# 285.CYRIL> p CCDS
# 5
#########

#Change the macro to search for ccds up to 20 and offer them in the menu.
#
#Revision 5.47  2018/10/03 09:49:20  homsrego
#fixed ccdoff and ccdresetupall including image_par(ccd_u,"unusable") for new spec versions (>6.06.01)
#
#Revision 5.46  2018/03/19 15:49:27  witsch
#list_init destroys the content of the HEADER array and thus some of the
#contents go missing after a call to ccdmenu. I cant see, why the array
#needs cleaning at that point. list_init replaced with list_test! HW 19.3.2018
#
#Revision 5.45  2017/10/10 14:18:03  witsch
#adapt file to the use of Spec release younger than 6.06.01,
#where image_par(x, "controller") will yield an error,
#use image_par(x, "unusable") instead !
#The changes have been made to check on the release number and
#thus the old code remains.
#
#Revision 5.44  2017/06/27 13:48:48  witsch
#A last missing thing to provide the private lima setup at the first time
#calling ccdmenu.
#
#Revision 5.43  2017/06/26 14:36:39  witsch
#Inconsistent handling of array CCD_DS_CONTR, where the strings LIMA and
#LIMATACO were used from different macros. ccd.mac used LIMATACO and the
#lima macros used LIMA, which lead to strange behaviours like offereing
#no private setup for LIMA device servers at the very first ccdmenu call.
#
#Revision 5.42  2016/06/30 13:27:08  witsch
#integration of BM25 VHR camera (in order to use BLISS ccd.mac rather than private ccd.mac.
#
#Revision 5.41  2016/06/22 08:34:49  petitdem
#Send image header in Dserver saving mode
#
#Revision 5.40  2013/09/17 12:19:56  claustre
#Fixed pb with ccdresetup when called without reconfig.
#
#Revision 5.39  2012/10/15 11:38:28  beteva
#corrected checking of the Oxidis version
#
#Revision 5.38  2012/10/04 12:49:20  guilloud
#fix bug : "preset" time not stored on a ccdtake => lost after a ccdresetup.
#
#Revision 5.37  2012/10/03 16:05:47  ahoms
#Unified code filling motor and counter names and values in file header
#
#Revision 5.36  2012/05/21 11:40:13  sole
#Strings starting by a space have to be kept within double quotes. Make sure there is no leading space. See /sware/exp/saxs/doc/SaxsKeywords.pdf
#
#Revision 5.35  2011/07/12 13:21:43  petitdem
#Add Bpm LimaTaco
#
#Revision 5.34  2011/04/29 14:27:35  guijarro
#bug fix: ROI counters integration value from ushort to long, to handle detectors with more than 16 bits per peixel
#
#Revision 5.33  2011/04/06 12:59:35  guilloud
#add comments.
#
#Revision 5.32  2011/03/16 13:41:25  claustre
#Added sub functions _ccdintegron/off() to fix a bug in ccdintegr which always
#called ccdintegron/off on active ccd (CCD_U).
#
#Revision 5.31  2011/02/08 12:25:25  claustre
#Added support for ccdbpm for PROSILICA.
#Create a _ccd_savecounts() chained to user_scan_loop scans and user_handlecounts for ct.
#
#Revision 5.30  2010/12/01 17:06:29  papillon
#* change in ccdnewfile to get the last image number
#
#Revision 5.29  2010/10/26 09:34:45  papillon
#* add a hook in ccd private menu for lima macros
#
#Revision 5.28  2010/10/19 15:29:17  homsrego
#* ccdfilename: custom format fixed to 1 char the nr of digits.
#
#Revision 5.27  2010/10/11 10:52:56  claustre
#Modified ccd_createarray to check if image depth has changed and then
#resize the data array.
#
#Revision 5.26  2010/09/29 18:01:49  petitdem
#manage shared array of 4 bytes long (Pilatus)
#
#Revision 5.25  2010/09/28 11:30:21  homsrego
#ccdfilename: included dir in the return value in the case of custom format
#
#Revision 5.24  2010/05/17 15:44:26  papillon
#* add private menu/setup for pco
#
#Revision 5.23  2010/02/01 12:30:36  guilloud
#add ccd_add_header_param and ccd_show_sup_header.
#*little cleanning.
#
#Revision 5.22  2009/12/08 10:25:41  papillon
#* bug in ccdcreateR solved by D.Wermeille
#
#Revision 5.21  2009/11/10 16:35:20  ahoms
#Modified f3send to work with Frelon2k (dsespia); kept old as f5send
#
#Revision 5.20  2009/02/10 10:23:23  guijarro
#do not try to change mode for SCANNER
#
#Revision 5.19  2009/01/21 09:12:27  guilloud
#add _user_ccd_header_info for additional header informations.
#in ccdsum : Adds a supplementary header info : the number of images summed.
#
#Revision 5.18  2008/12/02 10:25:24  papillon
#* Changes for ANDOR CCD only:
#- added vertical shift speed parameter
#- added preamplifier gain parameter
#
#Revision 5.17  2008/11/24 13:56:49  papillon
#* Changes for ANDOR CCD:
#- Possibility to change ADC speed
#- Utility macro for temperature setpoint (andortemp)
#
#Revision 5.15  2008/09/02 10:01:48  papillon
#* Correct oxidis version checking
#
#Revision 5.14  2008/08/26 07:27:46  papillon
#*** empty log message ***
#
#Revision 5.13  2008/08/26 06:46:04  papillon
#* forget a parenthesis !!!
#
#Revision 5.12  2008/08/13 14:38:45  papillon
#* add Dserver auto-save mode for espia ccds
#
#Revision 5.11  2008/07/17 14:17:49  rey
#Documentation changes.
#
#Revision 5.10  2008/07/01 16:38:34  ahoms
#Added local cleanup in ccdtake to restore the original ext_trig.
#Modified ccdstart to allow passing 0 as nr. of images (live mode).
#
#Revision 5.9  2007/11/14 09:46:37  claustre
#ccdsetup now tests if the camera is configured
#
#Revision 5.8  2007/10/26 15:10:29  claustre
#Added a new menu optio to select the display GUI (onze/oxidis)
#
#Revision 5.7  2007/10/24 06:52:06  claustre
#added call to _ccd_cdef() in ccdmenu, ccdon, ccdoff to force
#the cdef even if ccdresetupall has not been called.
#
#Revision 5.6  2007/10/15 07:45:41  claustre
#_gess_camera is now a function with the ccd unit number as parameters to fix
#a bug when it was called from different macro using a local variable _ccd_u.
#
#Revision 5.5  2007/10/02 11:45:01  guilloud
#change comments and indentation for camera_online macro.
#
#Revision 5.4  2007/10/01 14:38:35  papillon
#* Change andor cooler option
#
#Revision 5.3  2007/10/01 14:08:03  papillon
#* Added private menu for ANDOR
#
#Revision 5.2  2007/10/01 12:40:10  claustre
#bug fixes about private menu
#
#Revision 5.1  2007/09/21 13:24:13  claustre
#fix bug with option 61 of the private config menu, and clean it up
#
#Revision 5.0  2007/08/28 11:13:04  claustre
#Refactored version with a ccdresetup macro to reapply the
#camera configuration after a reset of the server
#
#Revision 4.37  2007/03/22 13:40:33  claustre
#change ccdmode (mar scanner macro) to resize the image_data shm.
#
#Revision 4.36  2006/12/20 21:53:03  goetz
#fixed bug in handling roi's with multiple cameras defined
#
#Revision 4.35  2006/12/20 10:14:28  berruyer
#in _ccdnewfile declare variable line as local
#
#Revision 4.34  2006/10/04 08:59:40  berruyer
#save parameters for concat mode are the same as for spec mode (ccdnewfile)
#
#Revision 4.33  2006/08/02 08:17:27  papillon
#add a user hook ccd_presave in __ccdsave
#
#Revision 4.32  2006/02/28 15:42:54  ahoms
#Corrected ccd_frelonsetup parameters in ccdsetup
#
#Revision 4.31  2005/09/21 11:35:58  pepellin
#Use clscreen()
#
#Revision 4.30  2005/08/23 14:33:37  claustre
#removed old meteor_ macro called by ccdsetup.
#
#Revision 4.29  2005/07/20 14:46:53  claustre
#Removed Meteor specific menu and added a more general menu for all
#the cameras which support the BPM calculation (Meteor, Frelon, Sensicam)
#
#Revision 4.28  2005/07/12 14:56:33  ahoms
#Added possibility of setting both ext_trigger and soft_preset to 0.
#Added user_pre/poststart to ccd_pre/poststart.
#
#Revision 4.27  2005/07/06 16:49:28  ahoms
#Added option to calculate intensity SUM/AVE/SD only in a RoI
#
#Revision 4.26  2005/06/13 10:20:19  sole
#stupid bug removed
#
#Revision 4.25  2005/06/13 10:12:19  sole
#CCD_SAVE_COUNTERS variable added. SPEC counters will only be saved if activated thru ccdmenu.
#
#Revision 4.24  2005/06/13 08:11:53  sole
#user_waitacq, ccd_pre_createarray, ccd_post_createarray defined as cdef macros
#
#Revision 4.23  2005/03/31 13:18:38  claustre
#added mar-scanner specfic macros and cleaned up ccdmenu
#
#Revision 4.19  2004/10/21 15:27:00  fernande
#ccdsetup changed. Readapted to id22
#
#Revision 4.18  2004/09/27 13:14:04  claustre
#Hoops, forget a "\n" in ccdmenu !!
#
#Revision 4.17  2004/09/27 12:15:36  claustre
#reintroduced the changes done in version 4.7 and lost by mistake: ccdintegron and ccdintegroff were added to fix a bug in the appli ccdconfig
#ccdmenu should not be afected
#Plus removed the obsolete use of ccdplot option in ccdintegr macro
#
#Revision 4.16  2004/09/14 09:52:22  fernande
#f3_dump: message changed
#
#Revision 4.15  2004/09/14 09:47:57  fernande
#f3send modified to work better with device server
#old f3send kept as f4send
#
#Revision 4.14  2004/09/07 08:56:14  fernande
#f3_dump modified to not print 0 when the camera frelon is not
#connected
#
#Revision 4.13  2004/06/29 15:21:04  fernande
#ccdon does a cdef to user_getcounts at the END of the function, to
#avoid problems with incorrect values of multimeters in EDF files
#
#Revision 4.12  2004/06/25 12:05:41  claustre
#Commented out line 636, redondante with 534 (ccd_other_show)
#
#Revision 4.11  2004/06/24 09:14:32  claustre
#added use of the meteor private setup macros.
#
#Revision 4.10  2004/06/15 13:33:40  fernande
#added setup for RoI granularity for the Sensicam
#Now private setup of sensicam shows the granularity too
#Added all this stuff also for The ESRF general CCD controller
#
#Revision 4.9  2004/06/07 14:43:49  claustre
#ccdlive stopped with Esc key.
#
#Revision 4.8  2004/04/23 12:09:11  berruyer
#in __ccdsave : change file name to save data outside scans
#in __ccdsave : reset points index after each line
#
#Revision 4.6  2004/02/17 12:36:05  claustre
#In previous version ccdread has lost special code for the mar345 scanner. It has been reintroduced now!.
#
#Revision 4.5  2004/01/09 17:18:36  fernande
#macros ls pwd etc were removed
#
#Revision 4.4  2003/11/07 15:24:58  fernande
#little bug showing private config when multiples cameras fixed
#
#Revision 4.3  2003/08/21 18:00:20  fernande
#Gilles berruyer added Concatenation Saving mode in scans
#Saves a single file with all the frames at the end of the scan
#macros _unix and _newunix were removed
#
#Revision 4.2  2003/05/20 17:34:57  fernande
#bug fixed in the sixth argument of the macro ccdintegr .
#
#Revision 4.1  2002/04/11 11:10:18  fernande
#new waitacq (shows the image number during a ccdtake)
#
#Revision 4.0  2002/04/11 11:08:16  icntl
#Multi CCD. These macros can manage several CCD devices at the same time.
#
#%DESCRIPTION%
# Gives the user macros to work with the CCD cameras. The main
# problem are the different features of different cameras.
#%DL%
#%DT% Taking images %DD%
#  %DL%
#    %DT% ccdtake %DD% Takes one image. Does not save the image.
#    %DT% ccdtakeall %DD% All ccds configured take one image.
#    %DT% ccdlive %DD% Takes images continiously until ^c is pressed.
#    %DT% ccdsum  %DD% Takes a number of images and sums them up.
#  %XDL%
#%DT% Saving images to disk %DD% This can also be configured from ccdmenu
#  %DL%
#    %DT% ccdnewfile %DD% Defines prefix, suffix and run number for
#                          the files.
#    %DT% ccdsave %DD% Saves the image taken with ccdtake.
#  %XDL%
#%DT% Setting up parameters %DD% CCD cameras must be configured either by
# ccdmenu (interactive and for all ccd devices) or by ccdsetup (can be called
# with arguments and once per ccd device.
#  %DL%
#    %DT% ccdmenu %DD% Configures the general parameters of all CCD devices.
#    %DT% ccdsetup %DD% Configures the general parameters of a particular CCD.
#    %DT% ccdroi %DD% Defines a region of interest
#    %DT% ccdbin %DD% Defines a row and column binning for the camera
# Use ccdmenu instead
#    %DT% ccdinfo %DD% Shows current ccd configuration
#  %XDL%
#%DT% Scanning %DD%
#  %DL%
#    %DT% ccdon %DD% Instructs spec to take imaged at every scan point
#    %DT% ccdoff%DD% Spec will not take images at every scan point anymore
#  %XDL%
#%XDL%
# Special Documentation for Spec internal functions
#%DL%
#%DT% image_par(device,"halt") %DD%
#%DT% image_par(device,"run") %DD%
#  Prepares the camera to run. Will start exposure depending on preset and
#  programmed modes.
#
#  1.) Preset 0 : (Cmd : image_par(0,"preset",0) )
#   The camera will be started to expose until
#   stopped by a TTL signal (Princeton & Frelon)
#   on EXT_TRIG input.
#
#  2.) If we have a preset time  (Cmd : image_par(0,"preset",1.4))
#   a.) Not in external trigger mode (Cmd : image_par(0,"ext_trig",0))
#      The camera will expose the preset time.
#   b.) We are in external trigger mode (Cmd : image_par(0,"ext_trig",1))
#     i.) We are not in preopen mode (Cmd : image_par(0,"pre_open",0))
#        The camera will wait for the external trigger. It will open
#    the shutter and start exposing for the preset time when the
#    TTL trigger signal is activated.
#     ii.) We are in preopen mode (Cmd : image_par(0,"pre_open",1))
#        The camera will open the shutter. It will continue to clear the
#     ccd chip until the external trigger comes. At that point it will
#        expose for the preset time and close the shutter.
#
#%DT% wait (0x4) %DD%
#
#  Will wait until all acquire devices are finished. For our cameras
#  this function will wait until the image is in the computer memory.
#
#%DT% wait (0x24) %DD%
#
#  Returns true if the device is still acquiring. For the cameras
#  that means that the image is not yet in memory.
#
#%DT% image_get (device, ARRAY) %DD%
#  Will put the image in the spec array ARRAY. Will not start any
#  acquisition but waits until the image is in memory.
#
#
#%DT% image_par(device,parameter) %DD%
#%DL%
#%DT%   "row_beg" "row_end" "col_beg" "col_end" %DD%
#     Program reagion of interest on the ccd chip
#%DT%   "row_bin" "col_bin" %DD%
#     Binning factor on the ccd chip. A binning factor must be an
#     integer value. It represents the number of pixels which are
#     read out together.
#%DT%   "rows" "cols" %DD%
#     Rows and cols of the ccd chip taking into account the binning.
#     (i.e. 1024 x 1024 with a binning factor of 2 2 will report
#      512 rows and 512 cols)
#
#%DT%   "ext_trig" "pre_open" %DD%
#     Determ. the function of the external TRIG TTL input. See
#     image_par(device,"run") above.
#
#%DT%   "auto_run" "soft_preset" "add_time" %DD%
#     Flags which influence the way the camera reacts when the user
#     types ct. If auto_run is true then the camera is programmed to start
#     before SPECs timer is started. The gate output from the timer might
#     be used to gate the camera when this is possible in hardware.
#     Princeton : For the moment I did not find a way to do that. Therefore
#       the shutter is programmed to open (preopen) and the clearing to be
#       stopped when the software gives the "run" command. Some ms before the
#       timer is started. On the falling edge of the signal, a very sort image
#       is taken. This should ressemble very much a start / stop mode where the
#       start signal is given by software but the stop signal by hardware.
#       As long as the shutter is gated by SPEC's timer, this should not be
#       much of a problem.
#%DT%      soft_preset : %DD%
#       This flag can be used to program the camera to expose the
#       same time as the SPEC timer. The camera is started slightly earlier and
#       stops slightly earlier as both time bases (SPEC and the camera) are
#       set to the same value.
#%DT%      add_time : %DD%
#       When the shutter is controlled by the SPEC timer it can be
#       useful to add a certain time to compensate for the early opening of
#       the camera. In this way the camera will expose all the time while
#       the shutter (controlled by SPEC's timer) is open. The value to be
#       given is in seconds.
#
#%DT%   "preset" %DD%
#     The time in seconds the camera will acquire. A zero value means
#     forever.
#
#%DT%   "ext_shutter" %DD%
#     Flag only for princeton. If true, the optical shutter of the
#     camera is controlled by an external TTL input on the controller.
#
#%DT%   "slow_adc" %DD%
#     Flag only for princeton. The slower adc is used if there is a
#     choice of two adc. If there is only one adc installed in the
#     controller, this flag has no effect.
#
#%DT%   "clean_scans" %DD%
#     Do not know so precisely yet. Might not be the number of full
#     clean scans because it is put to a very high number in the PI
#     code. There to be tried.
#%XDL%
#
#%DT% Configuring the camera in spec: %DD%
#
#You have to add the following line in SPECs configuration screen:
#%PRE%
#CCD-like       DEVICE   ADDR  <>MODE                         <>TYPE
#0    YES    /dev/sdv0      1                Princeton CCD Interface
#
#addr == 1                       EEV_1152x1242_3ph
#addr == 2                   TEK_1024x1024_B_100ns
#
#%PRE%
#%XDL%
# History
#    DFC 2001/10/24: ccdintegr fixed (now we can always take it off, even
#            if the counter was not defined)
#
#%EXAMPLE%
#%SETUP%
# The ccd camera must be configured with specs configuration
# editor. The macro ccdsetup must run at least once. It is therefore
# suggested to put it into your startup file (idxxsetup.mac).
#%END%

need spec_utils

#%UU%
#%MDESC% Show current setup for a given camera.
def ccdinfo '{
  if (image_par(CCD_U,"controller") == "PRINCE") {
    ccd_prince_info
    ccd_general_info
  } else if (image_par(CCD_U,"controller") == "FRELON") {
    ccd_frelon_info
    ccd_general_info
  } else if (image_par(CCD_U,"controller") == "PHM") {
    ccd_photom_info
  } else if (image_par(CCD_U,"controller") == "PCI_DV") {
    ccd_photonic_info
  } else if (image_par(CCD_U,"controller") == "CCD_PC") {
    ccd_pc_devinfo
  }
}'

#=======================================================================
#=======================================================================
# 2018/09/27 rh - fixed ccdon and ccdresetupall including
#                 image_par(ccd_u,"unusable") for new spec versions
#                 (>6.06.01)
#=======================================================================
#=======================================================================



#%IU%
#%MDESC% Declaration of all globals used in ccdmenu, ccdsetup and ccdresetupall.
def _ccd_globals '{
    global CCD_U CCD_ON CCD_SOFT_PRESET CCD_SOFT_INIT CCD_PRESET CCD_ADD_TIME
    global ROI_ACTIVE CCD_ROI CCD_DS CCD_DS_CONTR CCD_INCH CCD_DEPTH
    global CCD_TRIG CCDSAVE CCDSAVE_MODE
    global CCD_DIR CCD_PREFIX CCD_SUFFIX CCD_N ARRAYNAME

    global CCD_INTEG CCD_SUM CCD_MNE CCD_MNE2 CCD_NORM CCD_CNTROI
    global CCD_PLOT
    global ROI_GRAIN
    global CCD_SAVE_COUNTERS
    CCD_SAVE_COUNTERS = 0

    global CCD_EXT_HEADER  MY_EXT_HEADER
    global CCDREAD_MODE
    global CCD_GUI
    global CCD_BIN
    # those need to be at least ONE
    if (CCD_BIN[_ccd_u]["row_bin"]==0 && CCD_BIN[_ccd_u]["col_bin"]==0){
        CCD_BIN[_ccd_u]["row_bin"] = 1
        CCD_BIN[_ccd_u]["col_bin"] = 1
    }

    global CCD_SUP_HEADER
    # list_init destroys the content of the HEADER array and thus some of the
    # contents go missing after a call to ccdmenu. I cant see, why the array
    # needs cleaning at that point. list_init replaced with list_test ! HW 19.3.2018
    list_test CCD_SUP_HEADER
}'

def ccdsetup2 '_ccdmenu'
def ccdmenu '_ccdmenu'
#%UU%
#%MDESC% Interactive macro to configure all ccd devices.
#
def _ccdmenu '{

    local controller _ccd_u option ii jj _ccd_plot_mode
    local _set_trigg _CCD_U_old _guiname _cont
    local unusable

    _ccd_globals

    # permanent cdefs
    _ccd_cdef()

    # use builtin variable CCDS instead of NO_CCDS
    # while ((controller=image_par(NO_CCDS,"controller"))!=-1){
        # NO_CCDS++
    # }

    clscreen() #clean up the screen after the error message
    tty_cntl("md");printf("\n\n\n   CCD Devices Configured (with a running DS):\n\n")
    tty_cntl("me")

    if (_ccd_version_after_60601()){
        # from this release on image_par(x, "controller") yields an error,
        # use image_par(x, "unusable") instead !

        # CCDS builtin is : 1 + index of last CCD controller in the config list.
        #                   including YES, OFF and NO controllers.
        # but There might be one with a YES which might still not be usable
        printf("              config                  \n")
        printf("              index   \"controller\"  \"device_id/ds url\"          \n")
        printf("            -------------------------------------------------------------------------\n")
        for (jj = 0; jj < CCDS; jj++) {
            unusable = image_par(jj, "unusable")  # YES (DS ok or not) -> 0
                                                  # NO -> 1  ; OFF -> 1
            if (!unusable) {
                tty_cntl("md")
                printf("                %d - :",jj)
                tty_cntl("me")
                controller=image_par(jj,"controller")
                printf("   %s      %s  %s\n",controller,                           \
                image_par(jj,"device_id"),(CCD_U==jj)?"<ACTIVE>":"")

                if (controller == "CCD_PC") {
                    CCD_DS[jj] = image_par(jj, "device_id")
                }
            }
        }

    } else { # versions older than 6.06.01

        printf("\n\n\n PLEASE UPDATE SPEC. \n")
        printf("   version 6.06.01 has been released in 2017.\n")
        printf("   your version is %s. \n\n\n", VERSION)
        exit

####        while (ii<CCDS) {
####            controller=image_par(ii,"controller")
####            tty_cntl("md")
####            printf("                %d - :",ii)
####            tty_cntl("me")
####            printf("   %s (%s)  %s\n",controller,                           \
####                   image_par(ii,"device_id"),(CCD_U==ii)?"<ACTIVE>":"")
####            if (controller=="CCD_PC") {
####                CCD_DS[ii]=image_par(ii, "device_id")
####            }
####            ii++
####        }
####        if (CCD_U >= CCDS){
####            CCD_U=0
####        }
    }

    if ($#){
        _ccd_u=$1
    }
    else {
        _ccd_u = getval("\n\n     Option?  ",CCD_U)
    }

    # CCDS is an immutable spec variable, which shows the number of
    # DEFINED ccds. With blank positions in the list in config,
    # this leads to big index numbers for a small content for CCDS.
    # the test can`t be maintained as such.
    # if (_ccd_u >= CCDS) {
        # printf("\n\n CCD DEVICE %d NOT CONFIGURED!!  \n", _ccd_u)
        # exit
    # }

    # resetup to update the spec cache
    ccdresetup _ccd_u

    option=1
    while(option!=0) {
        clscreen()
        tty_cntl("md")
        printf("  CCD device %d : ",\ _ccd_u)
        tty_cntl("me")
        printf("[0..%d] \t", CCDS-1)
        tty_cntl("md")
        controller=image_par(_ccd_u,"controller")
        printf("%s...%s\n",controller,(CCD_U==_ccd_u)?"<ACTIVE>":       \
               "<not_active>")
        tty_cntl("md"); tty_cntl("us")
        printf("                                                         \t\t\t\n")
        tty_cntl("me"); tty_cntl("ue")
        tty_cntl("me")
        printf("   1 - Take an image during ct/scans . . . . . . . .:")
        tty_cntl("md");printf("%s\n",CCD_ON[_ccd_u]?"<YES>":"<NO>")
        tty_cntl("me")
        if (CCD_ON[_ccd_u]) {
            printf("        11 -  External signal  . . . . . . . . . . .:")
            tty_cntl("md")
            if (!CCD_TRIG[_ccd_u]) {
                printf("<NONE>\n")
                _set_trigg = 0
            }else {
                if (CCD_SOFT_PRESET[_ccd_u]) {
                    printf("<START>\n")
                    _set_trigg = 1
                } else {
                    printf("<GATE>\n")
                    _set_trigg = 2
                }
            }
            tty_cntl("me")
            printf("        12 -  Exposure time  . . . . . . . . . . . .:")
            tty_cntl("md")
            if (CCD_SOFT_PRESET[_ccd_u]) {
                printf("COUNT_TIME + %g (addtime)\n",CCD_ADD_TIME[_ccd_u])
            } else
                printf("<EXT_GATE>\n")

            tty_cntl("me")
            printf("        13 -  Read the image . . . . . . . . . . . .:")
            tty_cntl("md")
            if (CCDREAD_MODE[_ccd_u]==0) printf("<Always>\n")
            else if (CCDREAD_MODE[_ccd_u]==1) printf("<Never>\n")
            tty_cntl("me")
            if (CCDREAD_MODE[_ccd_u] !=1) {
                printf("        14 -  Integrate pixel values in counter. . .:")
                if (CCD_INTEG[_ccd_u]) {
                    tty_cntl("md")
                    printf("<YES>\n")
                    tty_cntl("me")
                    printf("                Options:")
                    tty_cntl("md")
                    printf("<%s>",CCD_NORM[_ccd_u]?((CCD_NORM[__ccd_u]==2)?"Std":"Avg"):"Intgr")
                    printf(" <mne:")
                    printf("%s %s>",(CCD_NORM[_ccd_u]==2)?CCD_MNE2[_ccd_u]:"",CCD_MNE[_ccd_u])
                    printf(" <RoI:")
                    if (CCD_CNTROI[_ccd_u]["active"])
                        printf("[%d,%d-%d,%d]>\n", \
                               CCD_CNTROI[_ccd_u]["col_beg"], \
                               CCD_CNTROI[_ccd_u]["row_beg"], \
                               CCD_CNTROI[_ccd_u]["col_end"], \
                               CCD_CNTROI[_ccd_u]["row_end"])
                    else
                        printf("NO>\n")
                    tty_cntl("me")

                } else {
                    tty_cntl("md")
                    printf("<NO>\n\n")
                    tty_cntl("me")
                }
            } else printf("\n")
        }  else printf("\n\n\n\n")
        printf("   2 - Save during ct/scan . . . . . . . . . . . . .:")
        tty_cntl("md");
        printf("%s\n",CCDSAVE[_ccd_u]?"<YES>":"<NO>")
        tty_cntl("me")
        printf("        Mode:");tty_cntl("md")
        if (CCDSAVE_MODE[_ccd_u] == 0)
            printf("<Spec>")
        else if (CCDSAVE_MODE[_ccd_u] == 1)
            printf("<Dserver>")
        else if (CCDSAVE_MODE[_ccd_u] == 2)
            printf("<Spec Concats. in scans>")
        else if (CCDSAVE_MODE[_ccd_u] == 3)
            printf("<Dserver multiframe 1 file>")
        else if (CCDSAVE_MODE[_ccd_u] == 4)
            printf("<Dserver auto-save mode>")
            tty_cntl("me"); printf ("\n")
            printf("        File:")
        if (CCDSAVE_MODE[_ccd_u]==1 || CCDSAVE_MODE[_ccd_u]==3 || CCDSAVE_MODE[_ccd_u]==4) {
            local __dir __prefix __inum
            __dir = image_par(_ccd_u,"file_dir")
            __prefix = image_par(_ccd_u,"file_prefix")
            __suffix = image_par(_ccd_u,"file_suffix")
            __inum = image_par(_ccd_u,"file_inum")

            tty_cntl("md")
            printf("<%s/%s%03d%s>\n",__dir,__prefix,__inum,__suffix)
            tty_cntl("me")
            printf("              dir    -> ")
            tty_cntl("md");printf(" %s\n",__dir)
            tty_cntl("me")
            printf("              prefix -> ")
            tty_cntl("md");printf(" %s\n",__prefix)
            tty_cntl("me")
            printf("              suffix -> ")
            tty_cntl("md");printf(" %s",__suffix)
            tty_cntl("me")
            printf(", next run -> ")
            tty_cntl("md");printf(" %s\n",__inum)
            tty_cntl("me")
        } else  {
            tty_cntl("md")
            printf("<%s>\n",\
                   ccdfilename(CCD_DIR[_ccd_u],CCD_PREFIX[_ccd_u],CCD_N[_ccd_u],CCD_SUFFIX[_ccd_u]))
            tty_cntl("me")
            printf("              dir    -> ")
            tty_cntl("md");printf(" %s\n",CCD_DIR[_ccd_u])
            tty_cntl("me")
            printf("              prefix -> ")
            tty_cntl("md");printf(" %s\n",CCD_PREFIX[_ccd_u])
            tty_cntl("me")
            printf("              suffix -> ")
            tty_cntl("md");printf(" %s",CCD_SUFFIX[_ccd_u])
            tty_cntl("me")
            printf(", next run -> ")
            tty_cntl("md");printf(" %d\n",CCD_N[_ccd_u])
            tty_cntl("me")
        }
        printf("   3 - BINNING . . . . . . . . . . . . . . . . . . .:")
        tty_cntl("md")
        if (CCD_BIN[_ccd_u]["row_bin"]==1 && CCD_BIN[_ccd_u]["col_bin"]==1){
            printf("<NO>\n")
        } else {
            printf("(row,col)=(%d,%d)\n",\
                   CCD_BIN[_ccd_u]["row_bin"],\
                   CCD_BIN[_ccd_u]["col_bin"])
        }
        tty_cntl("me")
         printf("   4 - ROI . . . . . . . . . . . . . . . . . . . . .:")
        tty_cntl("md");printf("%s\n",ROI_ACTIVE[_ccd_u]?"<YES>":"<NO>")
        tty_cntl("me")
        if (ROI_ACTIVE[_ccd_u]) {
            printf("                 Y -> ")
            tty_cntl("md")
            printf(" %d , %d\n",CCD_ROI[_ccd_u]["row_beg"],\
                   CCD_ROI[_ccd_u]["row_end"])
            tty_cntl("me")
            printf("                 X -> ")
            tty_cntl("md");
            printf(" %d , %d\n",CCD_ROI[_ccd_u]["col_beg"],\
                   CCD_ROI[_ccd_u]["col_end"])
            tty_cntl("me")
        } else printf("\n\n")

        printf("   5 - Use a display GUI . . . . . . . . . . . . . .:")
        tty_cntl("md")
        _guiname = CCD_GUI[_ccd_u]["guiconf"]?"<Oxidis>":"<Onze>"
        _guiname = "<YES>"_guiname
        printf("%s\n",CCD_GUI[_ccd_u]["on"]?_guiname:"<NO>")
        tty_cntl("me")

        printf("\n   6 - CCD device private config ...\n\n")

        printf("   7 - Set Active\n")
        printf("   0 - Exit")
        option = getval("\n\t\t     Option?  ",0)

        if (option == 1 ) {
            if (CCD_ON[_ccd_u]) {
                ccdoff _ccd_u
            } else {
                if ((CCD_TRIG[_ccd_u] == 0) && \
                    (CCD_SOFT_PRESET[_ccd_u] == 0) && \
                    !CCD_SOFT_INIT[_ccd_u]) {
                    CCD_SOFT_PRESET[_ccd_u] = 1
                    image_par(_ccd_u, "soft_preset", CCD_SOFT_PRESET[_ccd_u])
                    CCD_SOFT_INIT[_ccd_u] = 1
                }
                ccdon _ccd_u
            }
        }
        if (option == 11 ) {
            printf("\n\n    NONE => camera exposes during the counting time\n")
            printf("    START=> camera starts with the edge of the signal\n")
            printf("    GATE => camera exposes while the signal is active\n")
            _set_trigg = \
                getval("External signal: 0=NONE 1=START 2=GATE"\
                       , _set_trigg)
            if (_set_trigg) {
                CCD_TRIG[_ccd_u] = 1
                if (_set_trigg==2)
                    CCD_SOFT_PRESET[_ccd_u] = 0
                else
                    CCD_SOFT_PRESET[_ccd_u] = 1
            } else {
                CCD_TRIG[_ccd_u] = 0
                CCD_SOFT_PRESET[_ccd_u] = 1
            }
            image_par(_ccd_u,"ext_trig", CCD_TRIG[_ccd_u])
            image_par(_ccd_u, "soft_preset", CCD_SOFT_PRESET[_ccd_u])
        }
        if (option == 12 ) {
            local spreset
            spreset = CCD_SOFT_PRESET[_ccd_u]
            spreset = yesno("Preset ccd exposure time", spreset)
            CCD_SOFT_PRESET[_ccd_u] = spreset
            if (image_par(_ccd_u, "soft_preset", spreset)) {
                CCD_ADD_TIME[_ccd_u]= \
                    getval("Prolong ccd exposure time [s]",\
                           image_par(_ccd_u,"add_time"))
                image_par(_ccd_u,"add_time", \
                          CCD_ADD_TIME[_ccd_u])
            } else {
                CCD_PRESET[_ccd_u] = 0
                image_par(_ccd_u, "preset", CCD_PRESET[_ccd_u])
            }
        }
        if (option == 13) {
            CCDREAD_MODE[_ccd_u] = !CCDREAD_MODE[_ccd_u]
        }
        if (option == 14) {
            ccdintegr _ccd_u
        }

        if (option == 2 ) {
            _CCD_U_old=CCD_U
            CCD_U=_ccd_u
            ccdnewfile
            CCD_U=_CCD_U_old
        }

        if (option == 3 ) {
            _CCD_U_old=CCD_U
            CCD_U=_ccd_u
            ccdbin
            CCD_U=_CCD_U_old
        }
        if (option == 4 ) {
            _CCD_U_old=CCD_U
            CCD_U=_ccd_u
            ccdroi
            CCD_U=_CCD_U_old
        }
        if (option == 5 ) {
            _CCD_U_old=CCD_U
            CCD_U=_ccd_u
            ccdgui
            CCD_U=_CCD_U_old
        }
        if (option == 6) {
            _CCD_U_old=CCD_U
            CCD_U=_ccd_u
            _ccd_private_menu
            CCD_U=_CCD_U_old
        }
        if (option == 7 ) {CCD_U=_ccd_u}
        if (option == 0) {ccd_createarray _ccd_u; break }
    }
}'


cdef("_user_ccd_private_menu", "", "__ccd")

def _ccd_private_menu '{
    option=1

    _guess_camera(_ccd_u)
    _user_ccd_private_menu

    while(option!=0) {
        clscreen()
        tty_cntl("md")
        printf("  CCD device %d : ",\ _ccd_u)
        tty_cntl("me")
        printf("[0..%d] \t",CCDS-1)
        tty_cntl("md")
        controller=image_par(_ccd_u,"controller")
        printf("%s...%s\n",controller,(CCD_U==_ccd_u)?"<ACTIVE>":\
                                "<not_active>")
        tty_cntl("md"); tty_cntl("us")
            printf("                                                      \t\t\t\n")
        tty_cntl("me"); tty_cntl("ue")
        tty_cntl("me")
        printf ("\n\n\n")
        _ccd_private_show
        printf("\n\n")
        printf("   0 - Back to main menu")
        option = getval("\n\n\t\t     Option?  ",0)
        _ccd_private_setup
    }
    option=1
}'

def ccd_other_show ''

def _ccd_private_show '{
        local soft_roi
        if (controller=="FRELON")  {
                printf("   1 - FRELON private config:\n")
                if (ROI_ACTIVE[_ccd_u]) {
                        printf(\
            "        Frelon RoI by software. . . . . . . . . . . :")
                        tty_cntl("md")
                        soft_roi=image_par(_ccd_u,"soft_roi")
                        printf("%s\n",soft_roi?"<YES>":"<NO>")
                        tty_cntl("me")
                } else {
                        printf("\n")
                }
                printf("        Frelon input channel . . . . . . . . . . . .:")
                tty_cntl("md")
                printf("%s\n",CCD_INCH[_ccd_u]?CCD_INCH[_ccd_u]:"All (1&2&3&4)")
                tty_cntl("me")
                ccd_other_show
        }  else if (controller=="PRINCE")  {
                printf("   1 - PRINCE private config:\n")
                _ccd_prince_private_show
                ccd_other_show
        } else if (controller=="CCD_PC") {
                printf("   1 - CCD device server private config(%s):\n",\
                        CCD_DS_CONTR[_ccd_u])
            CCD_DEPTH[_ccd_u] = image_par(_ccd_u,"bytes_pixel")
            if (CCD_DS_CONTR[_ccd_u]=="")
            _guess_camera(_ccd_u)
            if (CCD_DS_CONTR[_ccd_u]=="FRELON") {
            _ccd_frelon_ds_private_show
        } else if (CCD_DS_CONTR[_ccd_u]=="PCPRINCE") {
            _ccd_prince_private_show
        } else if (CCD_DS_CONTR[_ccd_u]=="SENSI") {
            _ccd_sensi_private_show
        } else if (CCD_DS_CONTR[_ccd_u]=="ANDOR") {
            _ccd_andor_private_show
        } else if (CCD_DS_CONTR[_ccd_u]=="PCO") {
            _ccd_pco_private_show
        } else if (CCD_DS_CONTR[_ccd_u]=="VHR") {
            _ccd_vhr_private_show
        } else {
            _guess_camera(_ccd_u)
            printf("\n\n")
        }
        ccdbpm_private_show

        ccd_other_show
        } else if (controller=="SENSI") {
               printf("   1 - SENSI private config(%s):\n",\
                            CCD_DS_CONTR[_ccd_u])
            ccd_other_show
        } else if (controller=="SCANNER") {
            local _fformat
            printf("   1 - SCANNER config: \n")
            printf("        11 -  Mode . . . . .  . . . . . . . . . . . :")
              tty_cntl("md")
            printf("< %d >\n", image_par(_ccd_u,"mode")  )
              tty_cntl("me")
            printf("        12 -  View Factor (1/xth of image seen). . .:")
              tty_cntl("md")
            printf("< %d >\n", image_par(_ccd_u,"view_factor")  )
              tty_cntl("me")
            printf("        13 -  Erase . . . \n")
               printf("        14 -  Set image header . . . \n")
            printf("        15 -  Set Dserver file . . .:\n")
            local __dir __prefix __inum
            __dir = image_par(_ccd_u,"file_dir")
            __prefix = image_par(_ccd_u,"file_prefix")
            __suffix = image_par(_ccd_u,"file_suffix")
            __inum = image_par(_ccd_u,"file_inum")

            tty_cntl("md")
            printf("<%s/%s%03d%s>\n",__dir,__prefix,__inum,__suffix)
            tty_cntl("me")
               printf("              dir    -> ")
              tty_cntl("md");printf(" %s\n",__dir)
              tty_cntl("me")
                printf("              prefix -> ")
              tty_cntl("md");printf(" %s\n",__prefix)
              tty_cntl("me")
                printf("              suffix -> ")
              tty_cntl("md");printf(" %s",__suffix)
              tty_cntl("me")
            printf(", next run -> ")
              tty_cntl("md");printf(" %s\n",__inum)
              tty_cntl("me")
        } else {
               printf("   \n\n\n")
        }
}'
def ccd_other_setup ''

def _guess_camera(ccd_u) '{
    local _myarr[] _myguess _ind

    split (CCD_DS[ccd_u],_myarr,"/")
        #take care of nethost (e.g. //surya/d05/meteor2/eh2)
        _ind=(_myarr[0]=="")? 4:1
    _myguess= substr(_myarr[_ind],2,4)
        # first char can be capital last can be numbers
    if (_myguess == "rinc"  ||_myguess == "RINC")
        CCD_DS_CONTR[ccd_u]="PCPRINCE"
    if (_myguess == "relo"  ||_myguess == "RELO")
        CCD_DS_CONTR[ccd_u]="FRELON"
    if (_myguess == "ensi"  ||_myguess == "ENSI")
        CCD_DS_CONTR[ccd_u]="SENSI"
    if (_myguess == "eteo"  ||_myguess == "ETEO")
        CCD_DS_CONTR[ccd_u]="METEOR"
    if (_myguess == "ndor" || _myguess == "NDOR")
        CCD_DS_CONTR[ccd_u]="ANDOR"
    if (_myguess == "rosi" || _myguess == "ROSI")
        CCD_DS_CONTR[ccd_u]="PROSILICA"
    if (_myguess == "imat" || _myguess == "IMAT")
        CCD_DS_CONTR[ccd_u]="LIMA"
        _myguess= substr(_myarr[_ind], 1, 3)
    if (_myguess == "pco" || _myguess == "PCO" || _myguess == "Pco")
        CCD_DS_CONTR[ccd_u]="PCO"
    if (_myguess == "vhr" || _myguess == "VHR")
        CCD_DS_CONTR[ccd_u]="VHR"
}'

def ccdbpm_private_show ''
def ccdbpm_private_setup ''

def _ccd_private_setup '{
    local controller

    # this is only for the sensicam  (for the moment)
    # so we have to make sure that is not set when it is not sensicam
    ROI_GRAIN[CCD_U]=0

    controller = image_par(CCD_U,"controller")
    if (controller=="FRELON") {
        ccd_frelonsetup
    }else if (controller=="PRINCE") {
        ccd_pisetup
    }else if (controller=="CCD_PC") {
        CCD_DS[CCD_U]=image_par(CCD_U,"device_id")
        _guess_camera(CCD_U)
        if (option == 1) {
                    CCD_DS_CONTR[CCD_U]=getval("Name of camera used",CCD_DS_CONTR[CCD_U])

            if (CCD_DS_CONTR[CCD_U]=="FRELON")  {
                _ccd_frelon_ds_private_setup
            } else if (CCD_DS_CONTR[CCD_U]=="PCPRINCE") {
                ccd_pisetup_temp
            } else if (CCD_DS_CONTR[CCD_U]=="SENSI") {
                   sensi_setup
            }
        }
        if (CCD_DS_CONTR[CCD_U]=="ANDOR") {
            _ccd_andor_private_setup
        }
        if (CCD_DS_CONTR[CCD_U]=="PCO") {
            _ccd_pco_private_setup
        }
        if (CCD_DS_CONTR[CCD_U]=="VHR") {
            _ccd_vhr_private_setup
        }
        ccdbpm_private_setup

    } else if (controller=="SCANNER") {
        _ccd_scanner_setup
    }
    ccd_other_setup
}'

def _ccd_frelon_ds_private_show '{

                global FRELON2000
                if (image_par(_ccd_u ,"type")&0x10)  {
                        FRELON2000=1
                } else {
                        FRELON2000=0
                }

                #if (ROI_ACTIVE[_ccd_u]) {
                #        printf(\
                #      "        Frelon RoI by software. . . . . . . . . . . :")
                #        tty_cntl("md")
                #        #soft_roi=image_par(_ccd_u,"soft_roi")
                #        #printf("%s\n",soft_roi?"<YES>":"<NO>")
                #        printf("NOT SUPPORTED YET")
                #        tty_cntl("me")
                #} else {
                #        printf("\n")
                #}
                printf("        Frelon input channel . . . . . . . . . . . .:")
                tty_cntl("md")
                printf("%s\n",CCD_INCH[_ccd_u]?CCD_INCH[_ccd_u]:"All (1&2&3&4)")
                tty_cntl("me")
        #ccd_other_show
}'

def _ccd_prince_private_show '{

                printf("       Shutter . . . . . . . . . . . . . . . . . . .:")
                tty_cntl("md")
                #printf("%s%s\n",\
                #        image_par(CCD_U,"pre_open")?"<PRE_OPEN>":"",\
                #        image_par(CCD_U,"ext_shutter")?"<EXT_SHUT>":"")
                printf("\n") # i have to change this....:-)
                tty_cntl("me")
                printf("       ADC . . . . . . . . . . . . . . . . . . . . .:")
                tty_cntl("md")
                printf("%s\n",\
                        image_par(_ccd_u,"slow_adc")?"<SLOW>":"<FAST>")
                tty_cntl("me")
}'

#it only sets the ROI_GRAIN which can be done here
# Anyway RoI does not work for sensicam otherwise
def _ccd_sensi_private_show '{
        # This is to try to get it right at the beginning
        if (ROI_GRAIN[_ccd_u]==0)
            ROI_GRAIN[_ccd_u] = 32

                printf("       ROI GRANULARITY. . . . . . . . . . . . . . . .:")
                tty_cntl("md")
                printf("%d\n",ROI_GRAIN[_ccd_u])
                tty_cntl("me")
}'

#%UU% [<setpoint>]
#%MDESC%
# Without argument, read cooler status, actual and setpoint temperature
# %BR%
# With <setpoint> argument, set the input setpoint and wait that temperature
# has stabilized at this set point value.
#
def andortemp '{
    local cooler temprd tempsp
    if (CCD_DS_CONTR[CCD_U]!="ANDOR") {
        printf("Current CCD is not an ANDOR !!")
        exit
    }

    if ($#!=1) {
        cooler= image_par(CCD_U, "talk", "Cooler")
        temprd= image_par(CCD_U, "talk", "Temperature")
        tempsp= image_par(CCD_U, "talk", "TempSetPoint")

        if (cooler==2) cooler="ON (temp. not reached)"
        else if (cooler==1) cooler="ON (stabilized)"
        else if (cooler==0) cooler="OFF (or unchanged)"
        else cooler="UNCHANGED"

        print "<ANDOR TEMPERATURE STATUS>"
        print  "* Cooler status..........:", cooler
        printf("* Temperature set point..: %d\n", tempsp)
        printf("* Actual temperature.....: %d\n", temprd)
    }
    else {
        print "<ANDOR TEMPERATURE>"
        tempsp= int($1)
        image_par(CCD_U, "talk", sprintf("TempSetPoint=%d", tempsp))
        image_par(CCD_U, "talk", "Cooler=1")
        printf("* Temperature set point..: %d\n", tempsp)
        cooler= 2
        while (cooler != 1) {
            sleep(4.0)
            temprd= image_par(CCD_U, "talk", "Temperature")
            cooler= image_par(CCD_U, "talk", "Cooler")
            printf("\r* Waiting Temperature (%d) ...", temprd)
        }
        printf("* Temperature reached....: %d\n", temprd)
    }
}'

def _ccd_andor_getparlist(name) '{
    local vlist narg varg[] iarg

    vlist= image_par(_ccd_u, "talk", sprintf("list%s", name))
    if (length(vlist)>0) {
        narg= split(vlist, varg, ",")
        ANDOR_PAR[name]["nb"]= narg
        for (iarg=0; iarg<narg; iarg++) {
            ANDOR_PAR[name][iarg]= varg[iarg]+0.
        }
    } else {
        ANDOR_PAR[name]["nb"]= 0
    }
}'

def _ccd_andor_update_pars '{
    global ANDOR_PAR[]
    local vlist narg varg[] iarg

    vlist= image_par(_ccd_u, "talk", "list")
    narg= split(vlist, varg, ":")
    for (iarg=0; iarg<narg; iarg++) {
        ANDOR_PAR[varg[iarg]]= image_par(_ccd_u, "talk", varg[iarg])
    }

    _ccd_andor_getparlist("adc")
    _ccd_andor_getparlist("vss")
    _ccd_andor_getparlist("gain")
}'


def _ccd_andor_private_show '{
    local shmode cooler

    _ccd_andor_update_pars


    printf("     11 - ADC SPEED . . . . . . . . . . .: ")
    tty_cntl("md"); printf("%g MHz\n", ANDOR_PAR["adc"][ANDOR_PAR["AdcSpeed"]]); tty_cntl("me")

    printf("     12 - Vertical Shift Speed. . . . . .: ")
    tty_cntl("md"); printf("%g us\n", ANDOR_PAR["vss"][ANDOR_PAR["VSSpeed"]]); tty_cntl("me")

    printf("     13 - PreAmplifier Gain . . . . . . .: ")
    tty_cntl("md"); printf("x%d\n", ANDOR_PAR["gain"][ANDOR_PAR["PreampGain"]]); tty_cntl("me")

    if (ANDOR_PAR["ShutterMode"]==1) shmode= "OPEN"
    else if (ANDOR_PAR["ShutterMode"]==2) shmode= "CLOSE"
    else shmode= "AUTO"

        printf("     14 - SHUTTER\n")
    printf("              Mode . . . . . . . . . . . : ")
    tty_cntl("md"); printf("%s\n", shmode); tty_cntl("me")
    printf("              TTL Level to open . . . . .: ")
    tty_cntl("md"); printf("%s\n", ANDOR_PAR["ShutterLevel"]?"HIGH":"LOW"); tty_cntl("me")
    printf("              Opening/Closing Time (ms) .: ")
    tty_cntl("md"); printf("%d\n", ANDOR_PAR["ShutterTime"]); tty_cntl("me")

    if (ANDOR_PAR["Cooler"]==2) cooler="ON (temp. not reached)"
    else if (ANDOR_PAR["Cooler"]==1) cooler="ON (stabilized)"
    else if (ANDOR_PAR["Cooler"]==0) cooler="OFF (or unchanged)"
    else cooler="UNCHANGED"

    printf("\n     15 - COOLING\n")
    printf("              Status . . . . . . . . . . : ")
    tty_cntl("md"); printf("%s\n", cooler); tty_cntl("me")
    printf("              Temperature SetPoint/Actual: ")
    tty_cntl("md"); printf("%d / %d\n", ANDOR_PAR["TempSetPoint"], ANDOR_PAR["Temperature"]); tty_cntl("me")

    printf("\n     16 - Fast External Triggering. . . .: ")
    tty_cntl("md"); printf("%s\n", ANDOR_PAR["FastExtTrigger"]?"Enabled":"Disabled"); tty_cntl("me")

}'

def _ccd_andor_private_setup '{
        if (option==11) {
        local ipar iadc
        printf("\n\nAdc Speed Values:\n")
            for (ipar=0; ipar<ANDOR_PAR["adc"]["nb"]; ipar++)
            printf("    (%d) %g MHz\n", ipar, ANDOR_PAR["adc"][ipar])
        iadc= getval("Enter Adc Speed", ANDOR_PAR["AdcSpeed"])
        iadc= int(iadc)
        if ((iadc<0)||(iadc>ANDOR_PAR["adc"]["nb"])) {
            printf("\n!!! ERROR : wrong Adc Speed value !!!\n")
        } else {
            image_par(_ccd_u, "talk", sprintf("AdcSpeed=%d", iadc))
        }
        input("--- Press Enter ---")
        }
    else if (option==12) {
        local ipar ivss
        printf("\n\nVertical Shift Speed Values:\n")
        for (ipar=0; ipar<ANDOR_PAR["vss"]["nb"]; ipar++)
            printf("    (%d) %g us\n", ipar, ANDOR_PAR["vss"][ipar])
        ivss= getval("Enter VSSpeed", ANDOR_PAR["VSSpeed"])
        ivss= int(ivss)
        if ((ivss<0)||(ivss>ANDOR_PAR["vss"]["nb"])) {
            printf("\n!!! ERROR : wrong Vertical Shift Speed value !!!\n")
        } else {
            image_par(_ccd_u, "talk", sprintf("VSSpeed=%d", ivss))
        }
    }
    else if (option==13) {
        local ipar ig
        printf("\n\nPreAmplifir Gain Values:\n")
        for (ipar=0; ipar<ANDOR_PAR["gain"]["nb"]; ipar++)
            printf("    (%d) x%d\n", ipar, ANDOR_PAR["gain"][ipar])
        ig= getval("Enter Preamp Gain", ANDOR_PAR["PreampGain"])
        ig= int(ig)
        if ((ig<0)||(ig>ANDOR_PAR["gain"]["nb"])) {
            printf("!!! ERROR : wrong PreAmplifir Gain value !!!\n")
        } else {
            image_par(_ccd_u, "talk", sprintf("PreampGain=%d", ig))
        }
    }
    else if (option==14) {
        print "\n\n"
        local shmode shlvl shtime
        shmode= getval("Shutter Mode (0=Auto, 1=Open, 2=Close)", ANDOR_PAR["ShutterMode"])
        shlvl= getval("TTL Level to open shutter (0=Low, 1=High)", ANDOR_PAR["ShutterLevel"])
        shtime= getval("Opening/Closing time (ms)", ANDOR_PAR["ShutterTime"])
        printf("... Setting Shutter options ...\n")
        image_par(_ccd_u, "talk", sprintf("ShutterMode=%d", shmode))
        image_par(_ccd_u, "talk", sprintf("ShutterLevel=%d", shlvl))
        image_par(_ccd_u, "talk", sprintf("ShutterTime=%d", shtime))
        input ("--- Press Enter ---")
    }
    else if (option==15) {
        print "\n\n"
        if (ANDOR_PAR["Cooler"]!=0) {
            val= yesno("Stop the cooler", 0)
            if (val) image_par(_ccd_u, "talk", "Cooler=0")
        }
        val= ANDOR_PAR["TempSetPoint"]
        val= getval("Temperature SetPoint", val)
        if (val!=ANDOR_PAR["TempSetPoint"]) {
            image_par(_ccd_u, "talk", sprintf("TempSetPoint=%d", val))
        }
        if (ANDOR_PAR["Cooler"]<1) {
            val= yesno("Start the cooler", 1)
            if (val) image_par(_ccd_u, "talk", "Cooler=1")
        }
        input ("--- Press Enter ---")
    }
    else if (option==16) {
        image_par(_ccd_u, "talk", sprintf("FastExtTrigger=%d", (!ANDOR_PAR["FastExtTrigger"])))
        input ("--- Press Enter ---")
    }

}'

def _ccd_pco_private_show '{
    _ccd_pco_update_pars

    printf("     11 - Number of ADC . . . . . . . . .: ")
    tty_cntl("md"); printf("%d\n", PCO_PAR["adc"]["use"]); tty_cntl("me")

    printf("     12 - Cooling SetPoint  . . . . . . .: ")
    tty_cntl("md"); printf("%d C\n", PCO_PAR["tempsetpoint"]["use"]); tty_cntl("me")

    printf("          Detector Temperature  . . . . .: ")
    tty_cntl("md"); printf("%.1f C\n", PCO_PAR["temperature"]); tty_cntl("me")
}'

def _ccd_pco_private_setup '{
    local value
    if (option==11) {
        value= getval(sprintf("Number of ADC used [max=%d]",  PCO_PAR["adc"]["nb"]), PCO_PAR["adc"]["use"])
        if (value != PCO_PAR["adc"]["use"])
            image_par(_ccd_u, "talk", sprintf("adc=%d", value))
        if (value==2) {
            tty_cntl("md"); print "WARNING:"; tty_cntl("me")
            print "\tWhen using 2 ADCs, ROIs must be symetric in horizontal"
            print "\t--> reset ROIs"
            ccdroi 0
            input("--- Press Enter ---")
        }
    }

    if (option==12) {
        value= getval(sprintf("Cooling setpoint [min=%d, max=%d]", \
                PCO_PAR["tempsetpoint"]["min"], PCO_PAR["tempsetpoint"]["max"]), \
                PCO_PAR["tempsetpoint"]["use"])
        if (value != PCO_PAR["tempsetpoint"]["use"]) {
            if ((value<PCO_PAR["tempsetpoint"]["min"])||(value>PCO_PAR["tempsetpoint"]["max"])) {
                tty_cntl("md"); print "ERROR:"; tty_cntl("me")
                printf("\tCooling setpoint should be in range [%d, %d]\n", \
                        PCO_PAR["tempsetpoint"]["min"], PCO_PAR["tempsetpoint"]["max"])
                input("--- Press Enter ---")
            } else {
                image_par(_ccd_u, "talk", sprintf("tempsetpoint=%d", value))
            }
        }
    }
}'

def _ccd_pco_update_pars '{
    global PCO_PAR[]
    local vlist narg varg[] iarg

    vlist= image_par(_ccd_u, "talk", "temperature")
    if (sscanf(vlist, "%f", val1)==1) {
        PCO_PAR["temperature"]= val1
    }

    vlist= image_par(_ccd_u, "talk", "tempsetpoint")
    if (sscanf(vlist, "%d %d %d", val1, val2, val3)==3) {
        PCO_PAR["tempsetpoint"]["use"]= val1
        PCO_PAR["tempsetpoint"]["min"]= val2
        PCO_PAR["tempsetpoint"]["max"]= val3
    }

    vlist= image_par(_ccd_u, "talk", "adc")
    if (sscanf(vlist, "%d %d", val1, val2)==2) {
        PCO_PAR["adc"]["use"]= val1
        PCO_PAR["adc"]["nb"]= val2
    }
}'

#%UU% [<setpoint>]
#%MDESC%
# Without argument, read actual and setpoint temperature
# %BR%
# With <setpoint> argument, set the input setpoint and wait that temperature
# has reached set point value.
#
def pcotemp '{
    local cooler temprd tempsp

    if (CCD_DS_CONTR[CCD_U]!="PCO") {
        printf("Current CCD is not an PCO !!")
        exit
    }
    if ($#!=1) {
        _ccd_pco_update_pars
        printf("<PCO COOLING STATUS>\n")
        printf("* Cooling SetPoint.......: %d C\n", PCO_PAR["tempsetpoint"]["use"])
        printf("* Detector Temperature...: %.1f C\n", PCO_PAR["temperature"])
    } else {
        local value tempsp temprd
        _ccd_pco_update_pars
        printf("<PCO COOLING STATUS>\n")
        value= int($1)
        if ((value<PCO_PAR["tempsetpoint"]["min"])||(value>PCO_PAR["tempsetpoint"]["max"])) {
            tty_cntl("md"); print "ERROR:"; tty_cntl("me")
            printf("\tCooling setpoint should be in range [%d, %d]\n", \
                    PCO_PAR["tempsetpoint"]["min"], PCO_PAR["tempsetpoint"]["max"])
            exit
        }
        image_par(CCD_U, "talk", sprintf("tempsetpoint=%d", value))
        vlist= image_par(CCD_U, "talk", "tempsetpoint")
        sscanf(vlist, "%d", tempsp)
        printf("* Cooling SetPoint.......: %d C\n", value)
        tempset= 0
        while (!tempset) {
            value= image_par(CCD_U, "talk", "temperature")
            sscanf(value, "%f", temprd)
            printf("\r* Waiting Temperature (%.1f) ...", temprd)
            if (fabs(temprd-tempsp)<2.) tempset= 1
            else sleep(4.)
        }
        printf("\r* Temperature reached....: %.1f\n", temprd)
    }
}'

def _ccd_remote_headerinfo ()'{
        local header ccdheader

        # this macro add motor and cnt to the header
        _ccd_headerinfo

        ccdheader=""; for (key in header){ ccdheader=ccdheader key"="header[key]"\n"}
        return ccdheader
}'

def _ccd_remote_file_setup '{
    local  _file_dir _file_prefix _file_suffix _file_inum __ccd_u
    local _controller

    if ($#) {
        __ccd_u=$1
        _file_dir = $2
        _file_prefix = $3
        _file_suffix = $4
        _file_inum = $5
    }else {
        __ccd_u=CCD_U
        _controller = image_par(__ccd_u,"controller")

        _file_dir = getval("Directory ",\
                    image_par(__ccd_u,"file_dir"))
        _file_prefix = getval("File Prefix ",\
                    image_par(__ccd_u,"file_prefix"))

            if (_controller !="SCANNER")
            _file_suffix = getval("File Suffix ",\
                    image_par(__ccd_u,"file_suffix"))

        _file_inum = getval("Next image number",\
                    image_par(__ccd_u,"file_inum"))
    }
    image_par(__ccd_u,"file_dir",_file_dir)
    image_par(__ccd_u,"file_prefix",_file_prefix)
        if (_controller !="SCANNER")
        image_par(__ccd_u,"file_suffix",_file_suffix)
    image_par(__ccd_u,"file_inum",_file_inum)

}'
def _ccd_scanner_view_factor 'ccdviewfactor $*'
def _ccd_scanner_erase '{
    if (yesno("Do you really want to erase the image plate",1) )
        ccderase $*
}'
def _ccd_scanner_format_mode 'ccdmode $*'

def _ccd_scanner_setup '{

    if (option == 11) {
        _ccd_scanner_format_mode $*
    } else if (option == 12) {
        _ccd_scanner_view_factor $*
    } else if (option == 13) {
        _ccd_scanner_erase $*
    } else if (option == 14) {
        _ccd_send_hw_pars $*
   } else if (option == 15) {
        _ccd_remote_file_setup
    } else if (option == 1){
        _ccd_scanner_format_mode $*
        _ccd_scanner_view_factor $*
        _ccd_scanner_erase $*
        _ccd_send_hw_pars $*
        _ccd_remote_file_setup $*
    }
}'
def _ccd_send_hw_pars '{
    local __ccd_u _i _my_string_in _my_string_out _par_no _ccd_hw_par_str
    global CCD_HW_PAR CCD_HW_PAR_STR
    if ($#)
        __ccd_u=$1
    else
        __ccd_u=CCD_U

    _my_string_in = image_par(__ccd_u, "hw_par")
    if (_my_string_in =="") {

        CCD_HW_PAR[0] = getval("Phi start angle in degree.", \
                            CCD_HW_PAR[0])
        CCD_HW_PAR[1] = getval("Phi stop angle in degree.",\
                             CCD_HW_PAR[1])
        CCD_HW_PAR[2] = getval("Exposure time in seconds.", \
                                CCD_HW_PAR[2])
        CCD_HW_PAR[3] = getval("Range", CCD_HW_PAR[3])
        CCD_HW_PAR[4] = getval("Number of phi oscillations.", \
                                CCD_HW_PAR[4])
        CCD_HW_PAR[5] = getval("detector-to-sample distance in mm.", \
                                CCD_HW_PAR[5])
        CCD_HW_PAR[6] = getval("X-ray beam wavelength in Angstroms.", \
                                CCD_HW_PAR[6])
        _my_string_out = sprintf("opt_phi_start=%f, opt_phi_stop=%f osc_expo_time=%f opt_phi_osci=%f opt_distance=%f opt_wavelength=%f",CCD_HW_PAR[0], CCD_HW_PAR[1], CCD_HW_PAR[2], CCD_HW_PAR[4], CCD_HW_PAR[5], CCD_HW_PAR[6])
    } else {
        _par_no =split(_my_string_in, CCD_HW_PAR_STR)
        for (_i=0 ; _i<_par_no ; _i++) {
            #if there the string looks like par=value
            split(CCD_HW_PAR_STR[_i], _ccd_hw_par_str,"=")
            CCD_HW_PAR[_i] = \
                getval(sprintf("Par %d: %s", _i, \
                _ccd_hw_par_str[0]), _ccd_hw_par_str[1])
            _my_string_out = sprintf("%s %s=%s ",_my_string_out, \
                            _ccd_hw_par_str[0], \
                            CCD_HW_PAR[_i])
        }

    }

    p "Sending "  _my_string_out " to server"
    image_par(__ccd_u, "hw_par", _my_string_out)

#   if (image_par(__ccd_u,"hw_par")) #does not point to 0
#       for (_i=image_par(__ccd_u,"hw_par"); _i<6; _i++)
#           image_par(__ccd_u,"hw_par",0) # goes to 6 and then to 0
#
#   _fval = getval("Phi start angle in degree.", 0)
#   image_par(__ccd_u,"hw_par",_fval)
#   _fval = getval("Phi stop angle in degree.", 0)
#   image_par(__ccd_u,"hw_par",_fval)
#   _fval = getval("Number of phi oscilations.", 0)
#   image_par(__ccd_u,"hw_par",_fval)
#   _fval = getval("detector-to-sample distance in mm.", 0)
#   image_par(__ccd_u,"hw_par",_fval)
#   _fval = getval("X-ray beam wavelength in Angstroms.", 0)
#   image_par(__ccd_u,"hw_par",_fval)
#   _fval = getval("Exposure time in seconds.", 0)
#   image_par(__ccd_u,"hw_par",_fval)

}'


def _ccd_frelon_ds_private_setup '{
    local chsel soft_roi

    if ($#) {
        chsel = $1
    }else {
        chsel   = getval("Use channel 1,2,3,4,12,13,24,34 (0 == all)",\
                CCD_INCH[CCD_U])
    }
    #soft_roi = yesno("Simulates ROIs by Software?",\
    #           image_par(CCD_U,"soft_roi"))

    CCD_INCH[CCD_U] = chsel
    if (chsel<10) {
            image_par(CCD_U,"input_channel",(chsel == 0)?15:pow(2,chsel-1))
    } else {
            if (chsel==12)
                image_par(CCD_U,"input_channel",3)
            if (chsel==13)
                image_par(CCD_U,"input_channel",5)
            if (chsel==24)
                image_par(CCD_U,"input_channel",10)
            if (chsel==34)
                image_par(CCD_U,"input_channel",12)
    }

}'


def frelonlive '{
    local controller _exp_time

    _exp_time=getval("Exposure time",image_par(CCD_U,"preset"))
    controller = image_par(CCD_U,"controller")
    if (controller=="CCD_PC" && CCD_DS_CONTR[CCD_U]=="FRELON") {
            esrf_io(CCD_DS[CCD_U],"DevCcdSetMode",1)
    }
    image_par(CCD_U,"preset",_exp_time)
    image_par(CCD_U,"run")
    printf("Look at live images on the Computer where the ds is running.\n")
    printf(" Shared memory name is _ccd_ds_\n")
    printf(" Type ^C to stop\n")
}'


def freloncache '{
    local controller _exp_time
    global NIMAGES
    if ($#) {
        _exp_time=  $1
        NIMAGES[CCD_U]= $2
    } else {
        _exp_time=getval("Exposure time",image_par(CCD_U,"preset"))
        NIMAGES[CCD_U]=getval("Number of Images",1)
    }
    controller = image_par(CCD_U,"controller")
    if (controller=="CCD_PC" && CCD_DS_CONTR[CCD_U]=="FRELON") {
            esrf_io(CCD_DS[CCD_U],"DevCcdSetMode",2)
    }
    image_par(CCD_U,"preset",_exp_time)
    image_par(CCD_U,"images",NIMAGES[CCD_U])
    image_par(CCD_U,"run")
    ccdread

}'

def frelonlivecache '{
    local controller _exp_time
    global NIMAGES
    _exp_time=getval("Exposure time",image_par(CCD_U,"preset"))
    NIMAGES[CCD_U]=getval("Number of Images",1)

    controller = image_par(CCD_U,"controller")
    if (controller=="CCD_PC" && CCD_DS_CONTR[CCD_U]=="FRELON") {
            esrf_io(CCD_DS[CCD_U],"DevCcdSetMode",3)
    } else {
        image_par(CCD_U,"live",1)
        image_par(CCD_U,"live_cache",1)
    }
    image_par(CCD_U,"preset",_exp_time)
    image_par(CCD_U,"images",NIMAGES[CCD_U])
    image_par(CCD_U,"run")
    printf("Look at live images on the Sun where the ds is running.\n")
    printf(" Shared memory name is _ccd_ds_.\n")
        printf(" Use ccdcachefilm to save and look at the images\n\n")
    printf(" Type ^C to stop\n")

}'

def ccdcachefilm '{
    cdef("cleanup_once","image_par(CCD_U,\"images\",1)\n","_ccdfilm")
    image_par(CCD_U,"images",NIMAGES[CCD_U])
    ccdfilm
    image_par(CCD_U,"images",1)
}'
def ccdstop '{
    local controller

    controller = image_par(CCD_U,"controller")
    if (controller=="CCD_PC") {
            esrf_io(CCD_DS[CCD_U],"DevCcdStop")
    }

}'
#%UU% [ soft_preset add_time save_after_ct ]
#%MDESC% Set up macros to work with a given camera.
def ccdsetup '{
    local softp addti exttrig

    _ccd_globals

    if ($#) {

        if (image_par(CCD_U,"device_id") =="?" || image_par(CCD_U,"disable")){
          tty_cntl("md")
          printf("ccdsetup: camera %d is disabled or not responding\n",CCD_U)
          tty_cntl("me")
          exit
        }
        CCD_SOFT_PRESET[CCD_U] = $1
        image_par(CCD_U,"add_time",$2)
        CCDSAVE[CCD_U] = $3
        CCD_TRIG[CCD_U] = $4

        ccdresetup

        if (image_par(CCD_U,"controller") == "PRINCE" || \
        image_par(CCD_U,"controller") == "PRINCE_PC") {
                ccd_pisetup $5 $6 $7
        } else if (image_par(CCD_U,"controller") == "FRELON") {
                ccd_frelonsetup $4 $5 $6
        } else if (image_par(CCD_U,"controller") == "PHM") {
                ccd_photomsetup $5
        } else if (image_par(CCD_U,"controller") == "PCI_DV") {
                ccd_photonic_setup
        } else if (image_par(CCD_U,"controller") == "CCD_PC") {
                ccd_pc_ccd_setup $5 $6
        }
            ccd_createarray
        } else
        _ccdmenu
}'

# May be too dangerous !
#    cdef("config_mac","ccdresetupall;","__ccd__")
#
#%UU%
#%MDESC% call ccdresetup for all the configured cameras
def ccdresetupall '{
    local controller ccd_u
    local stat

    _ccd_globals

    # permanent cdefs
    _ccd_cdef()

# ???
#    i = 0
#    while ((controller=image_par(i, "controller"))!=-1)  i++

    #clean up the last printed line (the error message)
#    printf("%c[%dA%c[0J", 27, 1, 27)

    ccd_u=0

    while (ccd_u < CCDS) {
        if(_ccd_version_after_60601()){
          stat = (image_par(ccd_u,"unusable") == 0) && (image_par(ccd_u,"device_id") !="?") && (!image_par(ccd_u,"disable"))
        }
        else{
          stat = (image_par(ccd_u,"device_id") !="?") && (!image_par(ccd_u,"disable"))
        }

        if (stat) {
            # printf("CCD %s OK\n", ccd_u)
            ccdresetup ccd_u
        }else if (image_par(ccd_u,"controller")=="Unconfigured"){
            CCD_ON[ccd_u] = 0
        }
        ccd_u++
    }

}'

#%UU% [ccd-unit]
#%MDESC% Reapply the current setup, ccdbin, ccdroi, soft_preset, ext_trig and preset
# Has to bep put in your spec setup to recover the camera setup after a reconfig ( or a camera reset).
def ccdresetup '{
    local rmax prev_ccd_u

    prev_ccd_u = CCD_U
    CCD_U = ($# > 0) ? $1 : CCD_U
    print "Reconfiguring the CCD camera"CCD_U" ..."

    ccdbin CCD_BIN[CCD_U]["row_bin"] CCD_BIN[CCD_U]["col_bin"]

    ccdroi ROI_ACTIVE[CCD_U] CCD_ROI[CCD_U]["row_beg"] CCD_ROI[CCD_U]["row_end"] \
                             CCD_ROI[CCD_U]["col_beg"] CCD_ROI[CCD_U]["col_end"]

        # apply the cdef()s to take images during ct/scan
        image_par(CCD_U,"auto_run",CCD_ON[CCD_U])
        # in case of fresh startup, initialize the camera to soft-preset mode
        # and suppose trig/preset are unset
        __ccd_check_soft_init(CCD_U)

    # Set autosave mode if needed
        if (image_par(CCD_U, "controller")!="SCANNER") {
      if (CCDSAVE_MODE[CCD_U]==4) {
        _ccd_autosave_mode(CCD_U, CCDSAVE[CCD_U])
      } else {
        if (image_par(CCD_U, "mode")&8) {
            _ccd_autosave_mode(CCD_U, 0)
        }
      }
        }

    CCD_U = prev_ccd_u

}'

#%IU% (ccd-unit)
#%MDESC% this macro is only called from ccdresetup and ccdon, it is
# intended to initialise the trigger mode when spec is starting from fresh
# and ccdmenu has not been used as a preliminary setup.
def __ccd_check_soft_init(ccd_u) '{
    local soft_preset ext_trig

    if(CCD_ON[ccd_u] && CCD_SOFT_PRESET[ccd_u]==0 && \
       CCD_TRIG[ccd_u]==0 &&!CCD_SOFT_INIT[ccd_u]) {
       CCD_SOFT_PRESET[ccd_u]=1
       CCD_SOFT_INIT[ccd_u]=1
    }
    soft_preset = image_par(ccd_u,"soft_preset")
    ext_trig = image_par(ccd_u,"ext_trig")
    #in case of Gate mode already configured in SPEC cash
    # e.i soft_preset=0 && ext_trig=1, , do nothing otherwise
    # spec will just set ext_trig to 1 (no cash for it) and the camera
    # will be switch to start_trig instead of gate where exposure time
    # must be set to 0 by spec. Thanks to the Taco interface !!!
    #LC # Wed 11 Sept 2013)
    if (soft_preset != 0 ||  ext_trig == 0) {
       image_par(ccd_u, "soft_preset", CCD_SOFT_PRESET[ccd_u])
       image_par(ccd_u, "ext_trig", CCD_TRIG[ccd_u])
    }
    # What if CCD_PRESET[ccd_u] is undefined ??? (CG # Wed 3 Oct 2012 15:36:00)
    image_par(ccd_u, "preset", CCD_PRESET[ccd_u])
}'


def ccd_pisetup '{
  local slowadc preopen extshut
    if ($#) {
            preopen = $1
            slowadc = $2
            extshut = $3
    } else {
        if (image_par(CCD_U,"ext_trig"))
        preopen = yesno("Preopen the shutter",\
                     image_par(CCD_U,"pre_open"))
        slowadc = yesno("Use the slower adc in the controller",\
        image_par(CCD_U,"slow_adc"))
        extshut = yesno("Control camera shutter externally",\
        image_par(CCD_U,"ext_shutter"))
    }
    image_par(CCD_U,"slow_adc",slowadc)
    image_par(CCD_U,"pre_open",preopen)
    image_par(CCD_U,"ext_shutter",extshut)
}'


def ccd_pisetup_temp '{
    local slowadc extshut
    if ($# == 2 ) {
        slowadc = $1
        extshut = $2
    } else {
        slowadc = yesno("Use the slower adc in the controller",\
                        image_par(CCD_U,"slow_adc"))
        extshut = yesno("Control camera shutter externally",\
                        image_par(CCD_U,"ext_shutter"))
    }
    image_par(CCD_U,"slow_adc",slowadc)
    image_par(CCD_U,"ext_shutter",extshut)
}'


def ccd_frelonsetup '{
    global FRELON2000
    local subset chsel soft_roi ext_trigger
    subset[1]=1 ; subset[2]=2 ; subset[4]=3; subset[8]=4

    if ($#) {
        ext_trigger=$1
        chsel = $2
        soft_roi = $3
        #one_quarter = $4
    } else {
        ext_trigger=yesno("Use External Trigger",ext_trigger)
        chsel   = getval("Use channel 1,2,3,4,12,13,24,34 (0 == all)",\
                subset[image_par(CCD_U,"input_channel")])
        soft_roi   = yesno("Simulates ROIs by Software?",\
                        image_par(CCD_U,"soft_roi"))
        # one_quarter = yesno("Read only one quarter ?",\
        #image_par(CCD_U,"one_quarter"))
    }
    image_par(CCD_U, "ext_trig",ext_trigger)
    CCD_INCH[CCD_U] = chsel
    if (chsel<10) {
                image_par(CCD_U,"input_channel",(chsel == 0)?15:pow(2,chsel-1))
    } else {
        if (chsel==12)
                image_par(CCD_U,"input_channel",3)
        if (chsel==13)
                image_par(CCD_U,"input_channel",5)
        if (chsel==24)
                image_par(CCD_U,"input_channel",10)
        if (chsel==34)
                        image_par(CCD_U,"input_channel",12)
    }

    image_par(CCD_U,"soft_roi",soft_roi)

    #image_par(CCD_U,"one_quarter",one_quarter)
    #if (one_quarter) ccdbin 2 2
    #   else ccdbin 1 1

    ccd_frelon_info
    ccd_general_info
}'

def ccd_photomsetup '
'

def ccd_photonic_setup '{
  local blacklvl gain

  if ($#) {
    gain = $1
    blacklvl = $2
  } else {
    gain = getval("Select Gain (1,2,4,8)",\
    image_par(CCD_U,"gain"))
 #   blacklvl = getval("Select Black level",\
 #    image_par(CCD_U,"blacklvl"))
 }
 #  image_par(CCD_U,"blacklvl",blacklvl)
  if (gain==1 || gain==2 || gain==4 || gain==8) {
     image_par(CCD_U,"gain",gain)
  } else {
     printf("\nINVALID GAIN !!!\n\n")
  }

}'

def sensi_setup '{
    global CCD_SENSI
    if ($1) {
        ROI_GRAIN[CCD_U]=$1
    } else {
        ROI_GRAIN[CCD_U]=32
            ROI_GRAIN[CCD_U]= \
            getval("    Use RoI granularity )",ROI_GRAIN[CCD_U])
    }
    CCD_SENSI=CCD_U
}'
def ccd_pc_ccd_setup '{

    ROI_GRAIN[CCD_U]=0

    CCD_DS[CCD_U]=image_par(CCD_U,"device_id")
    _guess_camera(CCD_U)
    if ( CCD_DS_CONTR[CCD_U] == 0 ) {
        CCD_DS_CONTR[CCD_U]=getval("Name of camera used",CCD_DS_CONTR[CCD_U])
    }
    if (CCD_DS_CONTR[CCD_U]=="FRELON")  {
        _ccd_frelon_ds_private_setup $*
    }else if (CCD_DS_CONTR[CCD_U]=="PCPRINCE") {
        ccd_pisetup_temp $*
    }else if (CCD_DS_CONTR[CCD_U]=="SENSI") {
        sensi_setup $*
    }
  if (CCD_DS_CONTR[CCD_U]=="METEOR" || \
    CCD_DS_CONTR[CCD_U]=="SENSI" || \
    CCD_DS_CONTR[CCD_U]=="FRELON" || \
        CCD_DS_CONTR[CCD_U]=="PROSILICA" ) ccdbpm_private_setup
    ccd_other_setup
}'

def ccd_frelon_info '{
# magic number for FRELON2000 = 16 (0x10)
#   "    "         EXT SERIAL LINE = 1
#   "    "         SDV = 2
#   "    "         PDV = 8
   p "\nYou are using ....."
   tty_cntl("md")
   if (image_par(CCD_U,"type")&0x10)  {
         FRELON2000=1
   } else {
         FRELON2000=0
   }
   tty_cntl("me")
   printf("  Using Channels %d\n", chsel? chsel:1234)
   printf("  ROIs generated by %s, if defined \n",\
    image_par(CCD_U,"soft_roi")? "software (SPEC)":"hardware (Frelon)");
}'
def ccd_general_info '{
   printf("  Camera triggered by %s \n",\
        image_par(CCD_U,"ext_trig")?"Hardware (TTL). Change with \"ccdoff\"":\
                               "Software (SPEC). Change with \"ccdon\"");
   printf("  When hardware trigger, exposure time controlled by %s\n",\
        image_par(CCD_U,"soft_preset")? "the camera (\"I\" register)":\
                                        "SPEC (I=0 & external pulse)")
   if (image_par(CCD_U,"soft_preset")) {
      printf("  Shutter open time =%d\n",image_par(CCD_U,"preset"))
      printf("  Exposure time (=shutter_time + add_time) =%d \n",\
           image_par(CCD_U,"preset")+image_par(CCD_U,"add_time"));
   } else {
      printf("  Exposure time =%d\n",image_par(CCD_U,"preset"))
   }
}'

def ccd_prince_info '
   p "\nYou are using ....."
   tty_cntl("md")
   printf("  PRINCETON  \n")
   tty_cntl("me")
   image_par(CCD_U,"go_nuts")
'
def ccd_photom_info '
   p "\nYou are using ....."
   tty_cntl("md")
   printf("  PHOTOMETRICS  \n")
   tty_cntl("me")

'
def ccd_photonic_info '
   p "\nYou are using ....."
   tty_cntl("md")
   printf("  PHOTONIC SCIENCE \n")
   tty_cntl("me")
   image_par(CCD_U,"go_nuts")
'

def ccd_pc_devinfo '
   p "\nYou are using ....."
   tty_cntl("md")
   printf("%s CCD DEVICE SERVER  %s \n", CCD_U, image_par(CCD_U, "device_id") )
   tty_cntl("me")
'

#%UU%
#%MDESC% Sets a new file prefix and initialises the run number. The
# file name will be: DIRPREFIXnnnnSUFFIX. It is possible to change this default
# file name with special keywords. See internal macro ccdfilename for more
# information how to do that.
# Decides if images are saved after counting (see ccdsave_)
def ccdnewfile '{
    ccdnewfile_function("$*")
}'

def ccdnewfile_function(arg_str) '{
    # args :
    # -save on/off
    # -mode :
    #  { 0:spec ; 1:dserver ; 2:spec concat ;
    #    3:dserver multiframe ; 4:dserver autosave }
    # -directory
    # -prefix
    # -suffix
    # -index

    local prev_mode new_mode fdir fprefix fsuffix fidx args[] nargs

    prev_mode = CCDSAVE_MODE[CCD_U]

    nargs = split(arg_str, args)
    if (nargs >= 6) {
        CCDSAVE[CCD_U] = int(args[0])
        new_mode       = int(args[1])
        fdir           = args[2]
        fprefix        = args[3]
        fsuffix        = args[4]
        fidx           = int(args[5])
        if ((new_mode==0) || (new_mode==2)) {
            _ccdnewfile fdir fprefix fsuffix fidx
        }
        else {
            _ccd_remote_file_setup CCD_U fdir fprefix fsuffix fidx
        }
    }
    else {
        CCDSAVE[CCD_U] = yesno("Save the image after counting (auto)",  \
                               CCDSAVE[CCD_U])

        printf("Saving modes:\n")
        printf("\t0.- Spec\n")
        printf("\t1.- DServer\n")
        printf("\t2.- Spec concatenates (scans)\n")
        printf("\t3.- DServer ALL in 1 file (multiframe)\n")
        printf("\t4.- DServer auto-save mode\n")
        new_mode = getval("Option:", prev_mode)

        if ((new_mode==0) || (new_mode==2)) {
            _ccdnewfile
        }
        else {
            _ccd_remote_file_setup
        }
    }

    if ((prev_mode==4) || (new_mode==4))
        _ccd_autosave_mode(CCD_U, CCDSAVE[CCD_U])

    CCDSAVE_MODE[CCD_U]= new_mode
}'

def _ccd_autosave_mode(unit, flag) '{
    local _mode
    _mode= image_par(unit, "mode")
    if (flag) {
        _mode |= 8
    } else {
        _mode &= ~8
    }
    image_par(unit, "mode", _mode)
}'

def _ccdnewfile '{
    local tmpfile line tmpidx

    if ($#==4) {
        CCD_DIR[CCD_U] = $1
        CCD_PREFIX[CCD_U] = $2
        CCD_SUFFIX[CCD_U] = $3
        CCD_N[CCD_U] = $4
    } else {
        CCD_DIR[CCD_U] = getval("CCD Directory",CCD_DIR[CCD_U])
        CCD_PREFIX[CCD_U] = getval("CCD File Prefix",CCD_PREFIX[CCD_U])
        CCD_SUFFIX[CCD_U] = getval("CCD File Suffix",CCD_SUFFIX[CCD_U])
        CCD_N[CCD_U] = 0
    }
    if (CCD_PREFIX[CCD_U] == "0")    CCD_PREFIX[CCD_U]=""
    if (CCD_PREFIX[CCD_U] == "null") CCD_PREFIX[CCD_U]="/dev/null"

    if (CCD_PREFIX[CCD_U] == "tty")  CCD_PREFIX[CCD_U]="/dev/tty"


    if (($# < 3) && (CCD_PREFIX[CCD_U] != "") && \
            (CCD_PREFIX[CCD_U] != "/dev/null") && \
                (CCD_PREFIX[CCD_U] != "/dev/tty") ) {

        if (CCD_DIR[CCD_U]=="" && !index(CCD_PREFIX[CCD_U], "/") \
                && !unix(sprintf("test -d %s",DATA_DIR)))
                CCD_DIR[CCD_U] = DATA_DIR

        tmpfile = sprintf("/tmp/ccdtmp_%s_%s",SPEC,USER)
        unix(sprintf("/bin/ls -r %s/%s????%s 2>/dev/null | head -1 > %s",\
                CCD_DIR[CCD_U], CCD_PREFIX[CCD_U], \
                        CCD_SUFFIX[CCD_U],tmpfile))
        if ((line=getline(tmpfile))!=-1) {
            tmpidx= index(line, CCD_SUFFIX[CCD_U])
            if (tmpidx) {
            sscanf(substr(line, tmpidx-4, 4), "%d", CCD_N[CCD_U])
            }
                getline(tmpfile,"close")
        }
        unix(sprintf("/bin/rm -f %s",tmpfile))

        CCD_N[CCD_U] = getval("Next run number",++CCD_N[CCD_U])
    }

    printf("Using prefix: \"%s\". Next run number is %d.(-> file \"%s\")\n",\
        CCD_PREFIX[CCD_U],CCD_N[CCD_U],\
        ccdfilename(CCD_DIR[CCD_U],CCD_PREFIX[CCD_U],CCD_N[CCD_U],CCD_SUFFIX[CCD_U]))
}'

#%IU% (prefix, number, suffix)
#%MDESC% Returns filename created from prefix number and suffix. The standard
# format will be <prefix>nnnn<suffix>. This format can be
# changed by adding keywords to the filename.
# %DL%
#  %DT% #n[digits] %DD% This sequence will be replaced by the current scan
#                       number. [digits] is optional and specifies the number
#                       of digits to put. (example #n4 will be replaced by
#                       0011.)
#  %DT% #p[digits] %DD% This sequence will be replaced by the current scan
#                   point number.
#  %DT% #r[digits] %DD% This sequence will be replaced by the current run
#                       number.
# %XDL%
# If a keyword is present in either the prefix or the suffix, the filename
# will be <prefix><suffix> without the run number. (with all occurences of
# the keywords mention above replaced by the actual values of the run
# number, scan number or point number )
# This macro function uses the global variables: SCAN_N NPTS
def ccdfilename (dir, prefix, number, suffix) '{
    local ch dig fname fmt ix

    fname = prefix suffix

    if (index(fname,"#") == 0) {
        fname = sprintf("%s/%s%04d%s",dir, prefix, number, suffix)
        return (fname)
    }

    while (ix = index(fname,"#")) {
        sscanf(fname,"%*[^#]#%1s%1d",ch,dig)
        if (dig == 0)
            fmt = substr (fname,1,ix-1) "%03d" substr (fname,ix+2)
        else
            fmt = substr (fname,1,ix-1) sprintf("%%0%dd",dig) substr (fname,ix+3)

        if (ch == "p")
            fname = sprintf(fmt,NPTS)
        else if (ch == "n")
            fname = sprintf(fmt,SCAN_N)
        else if (ch == "r")
            fname = sprintf(fmt,number)
        else
            fname = substr (fname,1,ix-1) substr (fname,ix+1)
    }

    fname = sprintf("%s/%s",dir, fname)

    return (fname)
}'

#%IU%
#%MDESC% Saves the global image array image_data? to the file defined
# by ccdnewfile. Only if "save after each scan point".
# change either with "ccdsetup" or "ccdnewfile". Used in ccdon and ccdoff
def _ccdsave '{
    local __ccd_u
    if ($#) __ccd_u=$1
    else __ccd_u=CCD_U
    if (CCDSAVE[__ccd_u] == 1) {
        __ccdsave
    }
}'
def ccd_presave ''
def ccd_postsave ''
#%IU%
#%MDESC% Used by _ccdsave and ccdsave
def __ccdsave '{
    local arrayname

    ccd_presave

        if (CCDSAVE_MODE[__ccd_u] == 0) {
                arrayname=sprintf("image_data%d",__ccd_u)
                ccd_save(ccdfilename(CCD_DIR[__ccd_u],CCD_PREFIX[__ccd_u],CCD_N[__ccd_u],CCD_SUFFIX[__ccd_u]),@arrayname)
                CCD_N[__ccd_u]++
        } else if (CCDSAVE_MODE[__ccd_u] == 1) {
        esrf_io(CCD_DS[__ccd_u], "DevCcdHeader", _ccd_remote_headerinfo())
                image_par(__ccd_u,"write_file")
    } else if (CCDSAVE_MODE[__ccd_u] == 2) {
                arrayname=sprintf("image_data%d",__ccd_u)

                if (CCD_INSCAN) {
                  arrayname_concat=sprintf("image_data_concat%d",__ccd_u)

                  if (NPTS == 0) {
                    shared ushort array @arrayname_concat[_n1*array_op("rows", @arrayname)][array_op("cols", @arrayname)]
                  }

                  __from = NPTS%_n1 * array_op("rows", @arrayname)
                  __to   = (NPTS+1)%_n1 * array_op("rows", @arrayname)
                  @arrayname_concat[__from:__to-1][] = @arrayname

                  if ((NPTS%_n1) == (_n1 - 1)) {
                    ccd_save(ccdfilename(CCD_DIR[__ccd_u],CCD_PREFIX[__ccd_u],CCD_N[__ccd_u],CCD_SUFFIX[__ccd_u]),@arrayname_concat)
                    CCD_N[__ccd_u]++
                  }
                } else {
                  ccd_save(ccdfilename(CCD_DIR[__ccd_u],CCD_PREFIX[__ccd_u],CCD_N[__ccd_u],CCD_SUFFIX[__ccd_u]),@arrayname)
                  CCD_N[__ccd_u]++
                }
    } else if (CCDSAVE_MODE[__ccd_u] == 3) {

            esrf_io(CCD_DS[__ccd_u],"DevCcdWriteAll")
    }
        ccd_postsave
}'
#%UU%
#%MDESC% Saves the global image array image_data? (ACTIVE) to the file defined
# by ccdnewfile.
def ccdsave '{
    local __ccd_u
    __ccd_u=CCD_U
    __ccdsave
}'


#%IU% ( file, image , flag)
#%MDESC% Saves an image array to the file. The information for the header
# is taken from the current global variables with the function
# _ccd_headerinfo. If bit 1 of flag is set, there will be no test if the file
# already exists. The old file will be overwritten.
def ccd_save (file, image, flag) '{

    local header

    if (file != "0") {
        if ((flag & 1) || !file_info(file)) {
            _ccd_headerinfo

            # Removes the function adding "number of cycles" to the header in case of ccdsum.
            cdef ("_user_ccd_header_info", "", "_ccdsumkey", "delete")

            if (fmt_write(file, "ESRF", image, header)) {
                printf("Error writing file \"%s\"\n", file)
                exit
            }
            printf("Image Saved to File \"%s\"\n", file)
        } else {
            printf("File \"%s\" already exists, cannot overwrite, exit !!",  \
                   file)
            exit
        }
    }
}'


# To add information to the standard header:
# cdef ("_user_ccd_header_info" , "\n ma_fonction_a_moi() \n" , "maclef")
# cdef ("_user_ccd_header_info" , "" , "maclef", "delete")
cdef( "_user_ccd_header_info", "", "__ccd")


#%IU%
#%MDESC% Puts information about the last image taken into the array header.
# This macro uses the global variables:
# SCAN_N  NPTS    COUNT_TIME  CCD_OFFSET_SUBS
# CCD_U   CCD_N   CCD_DIR     CCD_PREFIX
# MOTORS  COUNTERS
def _ccd_headerinfo  '{
    local _pname _pval ii

    if (CCD_EXT_HEADER) {
        header = MY_EXT_HEADER
    }
    else {
        header["title"]  = "CCD Image"
        header["run"]    = CCD_N[CCD_U]
        header["dir"]    = CCD_DIR[CCD_U]
        header["prefix"] = CCD_PREFIX[CCD_U]
        header["suffix"] = CCD_SUFFIX[CCD_U]

        for (ii = 0; ii < MOTORS; ii++) {
            header["motor_mne"] = sprintf("%s%s%s", header["motor_mne"], \
                                          ii ? " " : "", motor_mne(ii))
            header["motor_pos"] = sprintf("%s%s%g", header["motor_pos"], \
                                          ii ? " " : "", A[ii])
        }

        if (CCD_SAVE_COUNTERS){
            for (ii = 0; ii < COUNTERS; ii++) {
                header["counter_mne"] = sprintf("%s%s%s",header["counter_mne"],\
                                                ii ? " " : "", cnt_mne(ii))
                header["counter_pos"] = sprintf("%s%s%g",header["counter_pos"],\
                                                ii ? " " : "", S[ii])
            }
        }
        header["row_beg"] = image_par(CCD_U, "row_beg")
        header["row_end"] = image_par(CCD_U, "row_end")
        header["col_beg"] = image_par(CCD_U, "col_beg")
        header["col_end"] = image_par(CCD_U, "col_end")

        header["preset"]  = image_par(CCD_U, "preset")

        header["scan_no"]    = SCAN_N
        header["point_no"]   = NPTS
        header["count_time"] = COUNT_TIME
        header["offset"]     = CCD_OFFSET_SUBS[CCD_U]

        # CCD_SUP_HEADER[] is a stlist containing additional
        # informations to add to the image header.
        for ( ii=0 ; ii < list_n(CCD_SUP_HEADER) ; ii++ ) {
            _pname = CCD_SUP_HEADER[ii+1]
            _pval  = CCD_SUP_HEADER[CCD_SUP_HEADER[ii+1]]["value"]

            header[_pname] = _pval
        }
    }

    _user_ccd_header_info

}'


#%UU% (<param name>, <param value>, [<param description>])
#%MDESC%
#    Adds a parameter and the corresponding value in CCD_SUP_HEADER
# stlist. CCD_SUP_HEADER is used to build a CCD header of edf file.
# A description of the parameter can be added.
# *examples :
#   ccd_add_header_param("couleur", "rouge", "couleur du detecteur.")
#   ccd_add_header_param("age", "2", "age du detecteur (in years).")
def ccd_add_header_param(pname, pvalue, pdesc) '{

    list_add(CCD_SUP_HEADER, pname)

    list_setpar(CCD_SUP_HEADER, pname, "value", pvalue)

    if (pdesc){
        list_setpar(CCD_SUP_HEADER, pname, "desc", pdesc)
    }

}'

#%UU% [desc]
#%MDESC%
#    Displays, in a readable manner, the CCD_SUP_HEADER list.
#example :
# > ccd_show_sup_header 1
# /-- CCD supplementary header informations (CCD_SUP_HEADER stlist) --\
# * couleur = rouge
#    desc : couleur du detecteur.
# * age = 2
#    desc : age du detecteur (in years).
# \-------------------------------------------------------------------/
#
def ccd_show_sup_header '{
    local _pname _pval _pdesc

    print "/-- CCD supplementary header informations (CCD_SUP_HEADER stlist) --\\"
    for (i=0; i<list_n(CCD_SUP_HEADER); i++) {
        _pname = CCD_SUP_HEADER[i+1]
        _pval  = CCD_SUP_HEADER[CCD_SUP_HEADER[i+1]]["value"]
        printf("* %s = %s \n" , _pname, _pval)
        if ($1){
            _pdesc = CCD_SUP_HEADER[CCD_SUP_HEADER[i+1]]["desc"]
            printf ("   desc : %s \n", _pdesc)
        }
    }
    print "\\-------------------------------------------------------------------/"
}'



cdef("user_waitacq","\n{}\n","__ccd")
def waitacq '{
    if (image_par(CCD_U,"images")>1) {
        waitacq_nowait
    }
    else {
        wait(4)
    }
    user_waitacq
}'

def waitacq2 '{
    while (wait(0x24)) {
        sleep(COUNTERSPOLLTIME)
            if (image_par(CCD_U,"controller") == "SCANNER" )
            printf("Scanner in progress (%d%%)\r",\
                        image_par(CCD_U,"progress"))
        user_waitacq
    }
}'

def waitacq_nowait '{
    while (wait(0x24)) {
        sleep(COUNTERSPOLLTIME)
            if (image_par(CCD_U,"controller") == "CCD_PC" )
            printf("Frame no %d  \r",\
                    image_par(CCD_U,"get_current"))
    }
}'

def ccd_prestart 'user_prestart;'
cdef("user_prestart","\n{}\n","__ccd")

def ccd_poststart 'user_poststart;'
cdef("user_poststart","\n{}\n","__ccd")

#%UU%
#%MDESC%
#    Takes one image with the camera. The result is not automatically
# saved to disk.
def ccdtake '{
    local _ext_trig cln_up
    ccd_display_start(CCD_U)
    _ext_trig = image_par(CCD_U, "ext_trig")
    image_par(CCD_U, "ext_trig", 0)
    cln_up = sprintf("image_par(%d, \"ext_trig\", %d); ", CCD_U, _ext_trig)
    cdef("cleanup_once", cln_up, "ccdtake")
    ccdstart $*
    ccdread
    cdef("cleanup_once", "", "ccdtake", "delete")
    image_par(CCD_U, "ext_trig", _ext_trig)
}'

def ccdtakeM ' _ccdtakemenu '
def _ccdtakemenu '{
   global CCDFRAMES CCDFRAMES
   local _time _frames _ccd_menu controller

   clscreen()
   while(1) {

    controller=image_par(CCD_U,"controller")
    if (controller==-1) {
            printf("\n\n CCD DEVICE %d NOT CONFIGURED!!  \n",_ccd_u)
            _ccd_u=0
        exit
        }
    tty_cntl("md")
    printf("\n\n  CCD device %d : ",CCD_U)
    tty_cntl("me")
    printf("([0..%d] )\t", CCDS-1)
    tty_cntl("md")
    printf("%s...\n",controller)
    tty_cntl("md"); tty_cntl("us")
        printf("                                                      \t\t\t\n")
    tty_cntl("me"); tty_cntl("ue")
    tty_cntl("me")
    printf("   1 - Exposure time (sec) . . . . . . . . . . . . .:")
    tty_cntl("md");printf("%g\n",image_par(CCD_U,"preset"))
    tty_cntl("me")
    printf("   2 - Number of images. . . . . . . . . . . . . . .:")
    tty_cntl("md");printf("%d\n",CCDFRAMES)
    tty_cntl("me")
    printf("   3 - Save current image\n")
    printf("   4 - Film\n")
    printf("   5 - Open a new IMAGE DISPLAY\n\n")
    printf("   6 - SETUP (_ccdmenu)\n\n")
    tty_cntl("md"); tty_cntl("us")
        printf("   9 - OK (Start Exposure)     0 - Exit (^C ABORT)\t\t\t")
    tty_cntl("me"); tty_cntl("ue")
        option = getval("\n\n     Option?  ",9)
    clscreen()

        if (option == 1 ) {
        _time=getval("Exposure time (secs)",image_par(CCD_U,"preset"))
        image_par(CCD_U,"preset",_time)
    }
        if (option == 2 ) {
        CCDFRAMES=getval("Number of frames",1)
        image_par(CCD_U,"images",CCDFRAMES)
    }
        if (option == 3 ) {
        ccdsave
        }
        if (option == 4 ) {
        ccdfilm
        }
        if (option == 5 ) {
        CCD_GUI[CCD_U]["pid"]=0
        camera_online
        }
        if (option == 6 ) {
        _ccdmenu
        }
        if (option == 9) {
        _time=getval("Exposure time (secs)",image_par(CCD_U,"preset"))
        CCDFRAMES=getval("Number of frames",1)
        if (CCDFRAMES>1 || OLDFRAMES>1) {
            OLDFRAMES=CCDFRAMES
            ccdstart _time CCDFRAMES
        } else
            ccdstart _time

        ACQUIRING =1
                tty_cntl("mr")
        printf(". . . . . . .  ACQUISITION IN PROGRESS. . . . . .\n\n")
                tty_cntl("me")
        waitacq; ccdread
                tty_cntl("mr")
        printf(". . . . . . .     F I N I S H E D     . . . . . .\n\n")
                tty_cntl("me")
    }
        if (option == 0) {
        break
    }
   }
}'


#%UU%  [<exposure_time> [<no_images>]]
#%MDESC%
#    Starts the active (default) camera.
# Sets "preset" and "images" parameters : exposure time and number of images.
def ccdstart '{
    local _nb_param

    _nb_param = $#

    if (_nb_param >= 1){
        image_par(CCD_U,"preset",$1)
        # Saves the current preset time to be restored on a ccdresetup.
        CCD_PRESET[CCD_U] = $1
    }

    if (_nb_param >= 2){
        image_par(CCD_U,"images",$2)
    }
    else {
        # No params.
        image_par(CCD_U,"images",1)
        if (image_par(CCD_U, "preset") <= 0){
            printf("Invalid or no exposure time (ccd preset) defined.\n")
            printf("Please define one (ex: ccdtake <exposure_time>).\n\n\n")
        }
    }

    ccd_prestart
    image_par(CCD_U,"run")
    ccd_poststart
}'


#%UU%  [<ccd_unit>]
#%MDESC% reads an image into spec shared memory. If no argument uses the
# default camera
def ccdread '{
  local __ccd_u

  if ($#){
     __ccd_u=$1
  }
    else  {
     __ccd_u=CCD_U
   }
  if (image_par(__ccd_u,"controller")=="SCANNER") waitacq2
  else waitacq

   __ccdread
}'

#%IU%  [<ccd_unit>]
#%MDESC% reads an image into spec shared memory. If no argument uses the
# default camera. %BR%
# Do not read the image if the read-mode is set to "no-read" (1)
def _ccdread '{
  local __ccd_u

  if ($#){
     __ccd_u=$1
  }
    else  {
     __ccd_u=CCD_U
   }

  if (image_par(__ccd_u,"controller")=="SCANNER") waitacq2
  else waitacq
  if (CCDREAD_MODE[__ccd_u]==0) {
     __ccdread
  }

}'

def __ccdread '{
  local arrayname

  arrayname=sprintf("image_data%d",__ccd_u)
  image_get(__ccd_u,@arrayname)
}'



#%UU%
#%MDESC% Setup the display GUI
def ccdgui '{
    local blissadm path resp
    local was_on was_conf vers version
    was_on = CCD_GUI[CCD_U]["on"]
    was_conf = CCD_GUI[CCD_U]["guiconf"]

    if ($#) {
            CCD_GUI[CCD_U]["on"] = $1
            if ($1) CCD_GUI[CCD_U]["guiconf"] = $2
    } else {
            CCD_GUI[CCD_U]["on"] = yesno ("Use a display GUI",1)
            if (CCD_GUI[CCD_U]["on"]) {
              CCD_GUI[CCD_U]["guiconf"] = getval("\t0-Onze , 1-Oxidis", CCD_GUI[CCD_U]["guiconf"])
              #check if oxidis is installed
              if (CCD_GUI[CCD_U]["guiconf"]==1) {
                unix("echo \$BLISSADM",resp)
                split(resp,blissadm,"\n")
                path= blissadm[0]"/bin/oxidis"
                if (file_info(path)==0){
                  tty_cntl("md")
                  print "\tSorry but oxidis is not installed on this computer !"
                  print "\tPlease ask your BLISS contact person to install oxidis"
                  tty_cntl("me")
                  print("Hint any key to continue:")
                  # wait until user hits a key
                  letter = input(-1); while (asc(letter) == 0) letter = input(-1) ; input(1)
                  CCD_GUI[CCD_U]["guiconf"]=0
                }
                #check for the oxidis version, upper than 2.11 is better
                #for the user
                unix("rpm --dbpath \$BLISSADM/admin/RPM -qa |grep -i oxidis",resp)
                split(resp, vers,"Oxidis-src-")
                split(vers[1],version,".")
                if (!((version[0]+0>2)||((version[0]+0==2 && version[1]+0>10)))) {
                  tty_cntl("md")
                  print "\tYour are using Oxidis version <= 2.10,"
                  print "\tPlease, ask your BLISS contact person "
                  print "\tto install a new version to get better features!"
                  tty_cntl("me")
                  print("Hint any key to continue:")
                  # wait until user hits a key
                  letter = input(-1); while (asc(letter) == 0) letter = input(-1) ; input(1)
                }
              }
            }
    }
    if (was_on && !CCD_GUI[CCD_U]["on"]) {
       #ccd gui switched OFF
       ccd_display_stop(CCD_U)
    }

    if (was_conf != CCD_GUI[CCD_U]["guiconf"]) {
      #ccd gui has changed, stop and start the new one
      ccd_display_stop(CCD_U)
    }
    if (CCD_GUI[CCD_U]["on"])
      ccd_display_start(CCD_U)
}'

#%IU%
#%MDESC% Starts the online display application for the active
#camera. Tests first if not already running.
# OBSOLETE, but kept for backward compatibility with local macros
def camera_online '{
    local __ccd_u

    if ($#) __ccd_u = $1
    else  __ccd_u = CCD_U
    ccd_display_start(__ccd_u)
}'

#%IU%
#%MDESC% Starts the online display application for the active
#camera. Tests first if not already running.
def ccd_display_start(__ccd_u) '{
    global CCD_GUI
    if (!(CCD_GUI[__ccd_u]["pid"] && file_info(CCD_GUI[__ccd_u]["pid"], "alive"))) {
        CCD_GUI[__ccd_u]["pid"] = ccd_display(__ccd_u)
    }
}'

#%IU% ()
#%MDESC% Stops the online display application.
def ccd_display_stop(__ccd_u) '{
    local cmd

    # make sure, we`re not killing X11 (-1)
    if (CCD_GUI[__ccd_u]["pid"] > 0) {
        cmd=sprintf("kill -1 %d 2>/dev/null",CCD_GUI[__ccd_u]["pid"])
        unix(cmd)
    }
    CCD_GUI[__ccd_u]["pid"]= 0
}'


#%IU% ()
#%MDESC% Starts the online display application (onze) and returns its pid.
def ccd_display (__ccd_u) '{
    local pid file guicmd arrayname line

    # the file doesn`t seem to be used.
    file      = sprintf("/tmp/disgui_%s_%s.pid", USER, SPEC)
    arrayname = sprintf("image_data%d", __ccd_u)
    if (CCD_GUI[__ccd_u]["guiconf"] == 1) {
        guicmd    = sprintf("oxidis -f %s:%s", SPEC, arrayname)
    } else {
        guicmd    = sprintf("onze -ver %s -shm %s -scale 50", SPEC, arrayname)
    }
    unix(sprintf("/bin/rm -f %s", file))
    #~ unix(sprintf("%s >/dev/null 2>&1 & echo $\!", guicmd), PID)
    unix(sprintf("%s >/dev/null 2>&1 & echo $\!", guicmd), PID)
    fprintf(file, "%d", PID)
    close(file)
    return (PID)+0
}'


#%UU%
#%MDESC% The camera will be started automatically at every scan point.
#
def ccdon '{
    local __ccd_u

    # permanent cdefs
    _ccd_cdef()

    if ($#) __ccd_u=$1
        else  __ccd_u=CCD_U
    CCD_ON[__ccd_u] = 1
    image_par(__ccd_u,"auto_run",1)
    __ccd_check_soft_init(__ccd_u)
}'


def _ccd_version_after_60601() '{
    # treat version 6.06.01 and younger differently in image_par():
    # from this release on image_par(x, "controller") yields an error,
    # use image_par(x, "unusable") instead !

    local version[] release

    # Examples of VERSIONS:
    #
    # 1770.EH_NA> p VERSION
    # 6.11.02+5              oh... a "+" :)
    #
    # 23.CYRIL> p VERSION
    # 6.07.01

    if (spec_version_newer_than(6, 6, 1)) {
        return 1
    }

    print "Warning: OLD SPEC VERSION =", VERSION
    return 0
}'

#%UU%
#%MDESC% The camera will not longer be started at every scan point.
def ccdoff '{
    local __ccd_u

    # permanent cdefs
    _ccd_cdef()

    if ($#) __ccd_u=$1
        else  __ccd_u=CCD_U
    CCD_ON[__ccd_u] = 0

    if (_ccd_version_after_60601()){
        if(image_par(__ccd_u,"unusable") == 0){
            # ?????
            image_par(__ccd_u,"auto_run",0)
        }
    }else{
        if (image_par(__ccd_u,"device_id") !="?" && !image_par(__ccd_u,"disable")){
            image_par(__ccd_u,"auto_run",0)
        }
    }
}'

#%IU%
#%MDESC%
def _ccd_cdef() '{

    cdef("user_getcounts","_ccd_getcounts()\n","__ccd__",0x10)

    #Chain saving at the bottom level after counting for both ct and scans
    #That garanties first to save valid counter values after image reading +
    #in case of checkbeam (or autof) to not save an image if the count is redo.

    cdef("user_scan_loop","_ccd_savecounts()\n","__ccd__")
    cdef("user_handlecounts","_ccd_savecounts()\n","__ccd__")

    cdef("measure0", "_ccd_set_concat(1)\n", "__ccd__")
    cdef("measure2", "_ccd_set_concat(0)\n", "__ccd__")
    cdef("cleanup_always", "_ccd_cleanup_concat\n", "__ccd__")

}'

#%IU%
#%MDESC%
def _ccd_uncdef() '{

    cdef("","","__ccd__","delete")
}'

#%IU%
#%MDESC%
def _ccd_getcounts() '{
    local  ccd_u

    for (ccd_u=0;ccd_u != CCDS; ccd_u++) {
        #read/save the image only if the ccd device is active and enabled

        if (ccd_is_ok_and_on(ccd_u)) {
            # read and save the image first
            if (image_par(ccd_u,"controller")=="SCANNER") image_par(ccd_u,"run")
            _ccdread ccd_u

            # calculate statistic
            _ccd_stat_counters(ccd_u)
        }
    }
}'
#%IU%
#%MDESC%
def _ccd_savecounts() '{
    local  ccd_u
    for (ccd_u=0;ccd_u!= CCDS; ccd_u++) {
        if (CCD_ON[ccd_u] && image_par(ccd_u,"device_id")!="?" \
                          && image_par(ccd_u,"disable")==0 ) {
            CCD_SAVE_COUNTERS=1
        _ccdsave ccd_u
        CCD_SAVE_COUNTERS=0
        }
    }
}'


#%UU%
#%MDESC%
#   Goes through buffer of multi-image and wait between each image
def ccdfilm '{
    local ii pstime _save _images

    cdef("cleanup_once","_resetfilmframe","_ccdfilm")
    if (!$#) {
            pstime = getval("Pause time between images",1)
            _save = yesno("Save to disk",0)
        _images=image_par(CCD_U,"images")
    } else {
            pstime = $1
            _save  = $2
            _images= $3
    }


    for (ii=0;ii<_images;ii++) {
            printf("<CCDFILM> Frame %d\n",ii)
            image_par(CCD_U,"get_offset",ii)
        if (!CCDSAVE_MODE[CCD_U] || !_save)
                ccdread
        if (_save) ccdsave
            sleep(pstime)
    }
    _resetfilmframe

}'
def _resetfilmframe '{
        image_par(CCD_U,"get_offset",0)

}'


#%UU%
#%MDESC% Takes images continiously and displays some statistical data
# You can finish image taking by typing "~". (^c also ends image taking
# but aborts the current image).
def ccdlive ' {
    local lasttime starttime exptime ct

    if ($#)
        exptime = $1
    else
        exptime = 0
    image_par(CCD_U,"images",1)
    starttime = time()
    for ( ct=1 ; ; ct++ ) {
        if ( (ch = input(-1) ) != "")
            if (ch == "\33")
            break
        lasttime = time()
        ccdtake exptime
        printf("\r(Hit \"Esc\" to stop) Images/sec: Last %5.2f Av %5.2f",\
            1/(time()-lasttime),ct/(time()-starttime))
    }
}'

#%UU% [use_roi xmin xmax ymin ymax]
#%MDESC% Defines a new region of interest for the camera.
def ccdroi '{
    local xsize ysize  rbeg rend cbeg cend
    short array _roi[4]
    if ($#) {
            ROI_ACTIVE[CCD_U] = $1
            rbeg = $2 ; rend = $3 ; cbeg = $4 ; cend = $5
    } else {
            ROI_ACTIVE[CCD_U] = yesno ("Use a Region of interest (ROI)",1)
            if (ROI_ACTIVE[CCD_U]) {
                rbeg = getval("ROI: from row (Y)",\
                        CCD_ROI[CCD_U]["row_beg"])
                rend = getval("ROI: to   row (Y)",\
                        CCD_ROI[CCD_U]["row_end"])
                cbeg = getval("ROI: from column (X)",\
                        CCD_ROI[CCD_U]["col_beg"])
                cend = getval("ROI: to   column (X)",\
                        CCD_ROI[CCD_U]["col_end"])
            }
    }
    # this is used by sensicam
    if (ROI_GRAIN[CCD_U] &&  ROI_ACTIVE[CCD_U]){
        _roi[0] = int(rbeg/ROI_GRAIN[CCD_U])
        _roi[1] = int(rend/ROI_GRAIN[CCD_U]) + 1
        _roi[2] = int(cbeg/ROI_GRAIN[CCD_U])
        _roi[3] = int(cend/ROI_GRAIN[CCD_U]) + 1

        rbeg= _roi[0]*ROI_GRAIN[CCD_U]
        rend= _roi[1]*ROI_GRAIN[CCD_U] -1
        cbeg= _roi[2]*ROI_GRAIN[CCD_U]
        cend= _roi[3]*ROI_GRAIN[CCD_U] -1

        printf("Using Grain=%d. RoI(row,col) from (%d,%d) to (%d,%d)",\
            ROI_GRAIN[CCD_U], rbeg, cbeg, rend, cend);
        }

    if (image_par(CCD_U,"controller")=="PRINCE" || \
                    CCD_DS_CONTR[CCD_U]=="PRINCE") {
        if ( (rend-rbeg+1)%2 ) #rows have to be even for princeton
            rend=rend+1
    }

    if (ROI_ACTIVE[CCD_U]) {
            image_par(CCD_U,"row_beg",rbeg)
            image_par(CCD_U,"row_end",rend)
            image_par(CCD_U,"col_beg",cbeg)
            image_par(CCD_U,"col_end",cend)
        CCD_ROI[CCD_U]["row_beg"] = rbeg
        CCD_ROI[CCD_U]["row_end"] = rend
        CCD_ROI[CCD_U]["col_beg"] = cbeg
        CCD_ROI[CCD_U]["col_end"] = cend

    } else {
            xsize = image_par(CCD_U, "rows")
            ysize = image_par(CCD_U, "cols")
            image_par(CCD_U,"row_beg",0)
            image_par(CCD_U,"row_end",xsize-1)
            image_par(CCD_U,"col_beg",0)
            image_par(CCD_U,"col_end",ysize-1)
    }

    ccd_createarray
}'

#%UU% [CCD_no 1=integrate/0=no 0=integration/1=avg/2=std mne1 mne2
#       1=cntRoI/0=noRoI <roistr>]
#%MDESC% Defines counter options for statistics on the camera
def ccdintegr '{
    local __ccd_u arrayname roiarr[] roistr

    if ($#>=1)
         __ccd_u=$1
     else
         __ccd_u=CCD_U

    if ($#>=2) {
        CCD_INTEG[__ccd_u] = $2
    } else {
        CCD_INTEG[__ccd_u] = \
            yesno("\n\t  Integrate ccd pixel values in a counter",\
                                CCD_INTEG[__ccd_u])
    }

    arrayname=sprintf("image_data%d",__ccd_u)

    if (CCD_INTEG[__ccd_u]) {
            if ($#>=3)
                CCD_NORM[__ccd_u] = $3
            else  {
                CCD_NORM[__ccd_u]= getval( \
                "\t\t0 = Integ, 1 = avg 2 = Avg&Std ",\
                            CCD_NORM[__ccd_u])
            }


        if (CCD_NORM[__ccd_u] == 2) {
            if ($#>=5) {
                CCD_MNE[__ccd_u] = "$4"
                CCD_MNE2[__ccd_u] = "$5"
            }else {
                    CCD_MNE[__ccd_u] = \
                    getval("\t\tAvg counter mnemonic",\
                             CCD_MNE[__ccd_u])
                    CCD_MNE2[__ccd_u] = \
                    getval("\t\tStd counter mnemonic",\
                             CCD_MNE2[__ccd_u])
            }
        } else  {
            if ($#>=4)
                CCD_MNE[__ccd_u] = "$4"
            else {
                    CCD_MNE[__ccd_u] = \
                    getval("\t\tCounter mnemonic", \
                             CCD_MNE[__ccd_u])
            }
        }

        if ($# >= 6)
            CCD_CNTROI[__ccd_u]["active"] = $6
        else
            CCD_CNTROI[__ccd_u]["active"] = \
                    yesno("\t\tCounter apply on a RoI", \
                        CCD_CNTROI[__ccd_u]["active"])

        if (CCD_CNTROI[__ccd_u]["active"]) {
            if ($# >= 7) {
                roistr = "$7"
                if (split(roistr, roiarr, ",") != 4) {
                    roistr = $7
                    if (split(roistr, roiarr, ",") != 4) {
                        print "Invalid argument: \"$7\""
                        exit
                    }
                }
                CCD_CNTROI[__ccd_u]["col_beg"] = roiarr[0] + 0
                CCD_CNTROI[__ccd_u]["row_beg"] = roiarr[1] + 0
                CCD_CNTROI[__ccd_u]["col_end"] = roiarr[2] + 0
                CCD_CNTROI[__ccd_u]["row_end"] = roiarr[3] + 0
            } else {
                CCD_CNTROI[__ccd_u]["col_beg"] = \
                    getval("\t\tCounter RoI first col", \
                        CCD_CNTROI[__ccd_u]["col_beg"])
                CCD_CNTROI[__ccd_u]["row_beg"] = \
                    getval("\t\tCounter RoI first row", \
                        CCD_CNTROI[__ccd_u]["row_beg"])
                CCD_CNTROI[__ccd_u]["col_end"] = \
                    getval("\t\tCounter RoI last col", \
                        CCD_CNTROI[__ccd_u]["col_end"])
                CCD_CNTROI[__ccd_u]["row_end"] = \
                    getval("\t\tCounter RoI last row", \
                        CCD_CNTROI[__ccd_u]["row_end"])
            }
        }
        _ccdintegron(__ccd_u)

    } else {
        _ccdintegroff(__ccd_u)
    }
}'
def ccdintegron '{
    local __ccd_u
    if ($#>=1)
         __ccd_u=$1
     else
         __ccd_u=CCD_U
    _ccdintegron(__ccd_u)
}'
def _ccdintegron(__ccd_u)'{
    CCD_INTEG[__ccd_u] = 1

    if (cnt_num(CCD_MNE[__ccd_u])==-1 || cnt_num(CCD_MNE[__ccd_u])== 0) {
        tty_cntl("md")
            printf("Counter %s does not exist!!.",CCD_MNE[__ccd_u])
            printf(" Use config to create it.\n")
            tty_cntl("me")
        exit
    }
    if (cnt_num(CCD_MNE2[__ccd_u])==-1 && CCD_NORM[__ccd_u] == 2) {
        tty_cntl("md")
            printf("Counter %s for Std does not exist!!.",\
                CCD_MNE2[__ccd_u])
            printf(" Use config to create it.\n")
            tty_cntl("me")
        exit
        }

}'
def ccdintegroff '{
    local __ccd_u
    if ($#>=1)
         __ccd_u=$1
     else
         __ccd_u=CCD_U
    _ccdintegroff(__ccd_u)
}'
def _ccdintegroff(__ccd_u)'{
    CCD_INTEG[__ccd_u] = 0

    if ((CCD_MNE[__ccd_u]!="") && (cnt_num(CCD_MNE[__ccd_u])!=-1)){
        S[cnt_num(CCD_MNE[__ccd_u])]=0
    }
    if ((CCD_MNE2[__ccd_u]!="")&&(cnt_num(CCD_MNE2[__ccd_u])!=-1)){
        S[cnt_num(CCD_MNE2[__ccd_u])]=0
    }
}'

def _ccd_stat_counters(_ccd_u) '{
    local arrayname _scam _scam2 _sum _avg _scale _std
    local roiarrayname _rb _re _cb _ce

    # this is to avoid doing it when the camera is off
    if (!CCD_ON[_ccd_u])
        return 0

    #do nothing if data have not been updated
    if (!CCD_INTEG[_ccd_u] || CCDREAD_MODE[_ccd_u]==1)
        return 0

    _scam = cnt_num(CCD_MNE[_ccd_u])
    if (_scam == -1)
        return 0

    arrayname=sprintf("image_data%d",_ccd_u)
    if (CCD_CNTROI[_ccd_u]["active"]) {
        _rb = CCD_CNTROI[_ccd_u]["row_beg"]
        _re = CCD_CNTROI[_ccd_u]["row_end"]
        _cb = CCD_CNTROI[_ccd_u]["col_beg"]
        _ce = CCD_CNTROI[_ccd_u]["col_end"]

        # this is done to optimise when not used
        roiarrayname = sprintf("image_data%d_roi", _ccd_u)
        long array @roiarrayname[_re-_rb+1][_ce-_cb+1]
        @roiarrayname = @arrayname[_rb:_re][_cb:_ce]

        arrayname = roiarrayname
    }

    _sum = array_op("sum",@arrayname)
    _scale = array_op("rows",@arrayname) * array_op("cols",@arrayname)
    _avg = _sum / _scale

    S[_scam] = CCD_NORM[_ccd_u] ? _avg : _sum

    _scam2 = cnt_num(CCD_MNE2[_ccd_u])
    if (CCD_NORM[_ccd_u]==2 && _scam2 != -1) {
        _std=sqrt(array_op("sumsq",@arrayname - _avg ) / _scale)
        S[_scam2] = _std
    }
}'

def ccdplot '{_ccdplot($1)}'

def _ccdplot(what) '{
    local p_size i

    if (what == 0)  return    # we should not be here anyway

    prows = array_op("rows",@ARRAYNAME)
    pcols = array_op("cols",@ARRAYNAME)

    if (what == 1) {
            shared ushort array image_int[prows][2]
            array_op("fill",image_int[][0])
            for (i=0;i<prows;i++) {
                image_int[i][1] = array_op("sum",@ARRAYNAME[i][])
            }
    }

    if (what == 2) {
            shared ushort array image_int[pcols][2]
            array_op("fill",image_int[][0])
            for (i=0;i<pcols;i++) {
                  image_int[i][1] = array_op("sum",@ARRAYNAME[][i])
            }
    }

    ccd_plotit()
}'

def ccd_plotit() '{
        plot_cntl("filter2")
        plot_cntl("open")
        plot_cntl("erase")
        array_plot(image_int)
        plot_cntl("filter1")
}'


#%UU% [x-bin y-bin]
#%MDESC%
# Sets a binning ratio for the camera. The binning is done in
# hardware on the camera. Not all cameras provide this feature.
def ccdbin '{
    local rbi cbi

    if ($#) {
            rbi = $1
            cbi = $2
    } else {
            rbi = getval("Y binning",   CCD_BIN[CCD_U]["row_bin"])
            cbi = getval("X binning",   CCD_BIN[CCD_U]["col_bin"])
    }

    image_par(CCD_U,"row_bin",rbi)
    image_par(CCD_U,"col_bin",cbi)

        CCD_BIN[CCD_U]["row_bin"] = rbi
        CCD_BIN[CCD_U]["col_bin"] = cbi

    ccd_createarray
}'
#def ccd_pre_createarray ''
#def ccd_post_createarray ''
cdef("ccd_pre_createarray","\n{}\n","__ccd")
cdef("ccd_post_createarray","\n{}\n","__ccd")

#%IU% [<ccd_unit>]
#%MDESC% Defines or redefines the shared array image_data?.  If no argument
# is given, it uses the active CCD unit to create the image_data? name.
def ccd_createarray '{
    global ARRAYNAME
    local xsize ysize oldx oldy depth
    local __ccd_u

    if ($#) __ccd_u=$1
        else  __ccd_u=CCD_U

    ccd_pre_createarray

    xsize = image_par(__ccd_u,"row_end") - image_par(__ccd_u,"row_beg") +1
    ysize = image_par(__ccd_u,"col_end") - image_par(__ccd_u,"col_beg") +1
    depth = image_par(__ccd_u,"bytes_pixel")

    # Ask if image_data is global. If I use array_op on image_data it will
    # create a local symbol image_data and whatis will not work.

    ARRAYNAME=sprintf("image_data%d",__ccd_u)
    if (whatis(ARRAYNAME) & 0x4000000) {
        oldx = array_op("rows",@ARRAYNAME)
        oldy = array_op("cols",@ARRAYNAME)
    }
    if ( oldx != xsize || oldy != ysize || CCD_DEPTH[__ccd_u] != depth) {
        CCD_DEPTH[__ccd_u] = depth
        if (CCD_DEPTH[__ccd_u]==1)
            shared ubyte array @ARRAYNAME[xsize][ysize]
        else if (CCD_DEPTH[__ccd_u]==4)
            shared long array @ARRAYNAME[xsize][ysize]
        else
            shared ushort array @ARRAYNAME[xsize][ysize]
            p "Shared array created : " ARRAYNAME
    }
    ccd_post_createarray
}'

#%IU%
#%MDESC% Creates as many image_data arrays as CCD devices configured.
# image_data1 image_data2 image_data3 .... etc
def ccd_createarrays '{
    for (i=0;i< CCDS;i++) {
            ccd_createarray  i
    }
}'

#%IU%
#%MDESC% Takes (Starts polls and waits and reads) an image with
# all ccd configured
def ccdtakeall '{
    local __ccd_u

    for (__ccd_u=0;__ccd_u< CCDS;__ccd_u++) {
        camera_online
        if ($1)
            image_par(__ccd_u,"preset",$1)
        if ($2)
            image_par(__ccd_u,"images",$2)
        ccd_prestart
        image_par(__ccd_u,"run")
        ccd_poststart
    }
    waitacq
    for (i=0;i< CCDS;i++) {
        ccdread i
    }
}'

#%IU%
#%MDESC% Changes the current CCD device active (by default when using macros
# for just one ccd (i.e. ccdtake)
# all ccd configured
def ccddefault '{
        local new_ccd
        if ($#)
            new_ccd= $1
        else
            new_ccd = getval("New default ccd (number)",CCD_U)
    printf("Before it was %d (%s)\n",CCD_U,image_par(CCD_U,"controller"))
        CCD_U=new_ccd
    printf("NOW it is %d (%s)\n",CCD_U,image_par(CCD_U,"controller"))
        ARRAYNAME=sprintf("image_data%d",CCD_U)
}'

#%UU% <exp_time> <no of cycles>
#%MDESC% Macro takes <no of cycles> images and adds them up in another
# array. The sum array is shared and can therefore be watched life
# with the online display. The shared array is of type unsigned long (Max
# number of counts per pixel : 2^32). The sum array is saved to disk
# after the measurement.
def ccdsum '{
    local xsize ysize _noc _exp_time
    local _cmd

    if ($# != 2 ) {
        p "usage: $0 <exp_time> <no of cycles>"
        exit
    }

    _exp_time=$1
    _noc=$2
    xsize = array_op("rows",@ARRAYNAME)
    ysize = array_op("cols",@ARRAYNAME)
    shared ulong array sum_image[xsize][ysize]

    for (ii=1; ii<=_noc; ii++) {
        printf("\rTaking image %4d", ii)
        ccdtake _exp_time
        sum_image += @ARRAYNAME
    }

    # Adds a supplementary header info : the number of images summed.
    _cmd = sprintf("\n header[\"no_summed\"]=%d \n", _noc)
    cdef ("_user_ccd_header_info", _cmd, "_ccdsumkey")

    printf("\nDone\n")

    ccd_save(ccdfilename(CCD_DIR[CCD_U],CCD_PREFIX[CCD_U],CCD_N[CCD_U],CCD_SUFFIX[CCD_U]),  \
             sum_image)
    CCD_N[CCD_U]++
}'

#%UU%  <file_name>
#%MDESC%  Reads an image file into image_data* array (ushort)
def ccd_open_file '{
    local _file _header _xsize _ysize _type

    if ($# > 4 || $# < 1) {
        p "usage: $0 <file_name> [<xsize> <ysize> <0 ushort, 1 byte, 2 long, 3 float, 4 double> ]"
        exit
    }
    _file="$1"

    if ($# > 1) {
        _xsize=$2
        _ysize=$3
        _type=$4
        if (_type ==0)
                shared ushort array @ARRAYNAME[_ysize][_xsize]
        if (_type ==1)
                shared byte array @ARRAYNAME[_ysize][_xsize]
        if (_type ==2)
                shared ulong array @ARRAYNAME[_ysize][_xsize]
        if (_type ==3)
                shared float array @ARRAYNAME[_ysize][_xsize]
        if (_type ==4)
                shared double array @ARRAYNAME[_ysize][_xsize]
        p "Caution: Array" ARRAYNAME" resized!!!. "

    } else {
        ccd_createarray
    }
    p "Reading file " _file " in array " ARRAYNAME
    fmt_read(_file, "ESRF", @ARRAYNAME, _header)

}'
def ccdload 'ccd_open_file $*'
def ccdreadfile 'ccd_open_file $*'

def ccd_kin_setup '{
    local _kinetics _kinwinsize _kin_trigger

    if ($#==3) {
        image_par(CCD_U,"kinwinsize",$2)
        image_par(CCD_U,"kinetics",$1) #frl needs to do it after size
        image_par(CCD_U,"ext_trig",$3)
    } else {

        _kinetics =  image_par(CCD_U,"kinetics")

        _kinetics = \
             getval ("Use Kinetics [ 0 No | 1 Kinetics | 2 Pipeline]",\
                                _kinetics)


        if (_kinetics) {
            _kinwinsize =  image_par(CCD_U,"kinwinsize")

            image_par(CCD_U,"kinwinsize", \
                getval ("Kinetics Window Size (power of 2)",\
                                _kinwinsize))

            _kin_trigger =  image_par(CCD_U,"ext_trig")

            image_par(CCD_U,"ext_trig", \
                getval (\
                "Kinetics Trigger 0:none 1:single 2:multiple",\
                                _kin_trigger))
        }
        _kinetics = image_par(CCD_U,"kinetics", _kinetics)
        #input()
    }

}'
def ccd_kin_show '{
    tty_cntl("me")
    if (!image_par(_ccd_u,"kinetics")) {
            printf("       KINETICS  . . . . . . . . . . . . . . . . . .:")
            tty_cntl("md")
        printf("<OFF>")
        tty_cntl("me")
    } else {
        printf("       KINETICS:. . .size: ")
            tty_cntl("md")
        printf("%s ", image_par(_ccd_u,"kinwinsize"))
        tty_cntl("me")
        printf("| Trigger: ")
            tty_cntl("md")
        printf("%s ", image_par(_ccd_u,"ext_trig")?"ON":"NONE")
        tty_cntl("me")
    }
    printf("\n")
}'
def ccd_kin_on '{
    cdef("ccd_other_setup","ccd_kin_setup\n","kin","0x20")
    cdef("ccd_other_show","ccd_kin_show\n","kin","0x20")

}'
# by default we want the kinetics menu to appear
#ccd_kin_on
def ccd_kin_off '{
    cdef("ccd_other_setup","","kin","delete")
    cdef("ccd_other_show","","kin","delete")
}'

#------------------Section for particular cameras---------------------

#         ------------------  MAR Scanner  ---------------------

#we keep the following mar* macros for backward compatibility with the died
# mar345.mac macro set !!

def marscan 'ccdtake $*'
def marerase 'ccderase $*'
def marmode 'ccdmode $*'
def marviewfactor 'ccdviewfactor $*'

#%UU% [ccd device number]
#%MDESC Start erasure of the image plate %BR%
# MAR SCANNER only.
def ccderase '{
    local __ccd_u

    if ($#)
         __ccd_u=$1
    else
         __ccd_u=CCD_U

    if (image_par(__ccd_u,"controller") != "SCANNER" ) {
        print "CCD Device "__ccd_u" is not a MAR SCANNER"
        print "Please, check with ccdmenu or set \"CCD_U\" to the correct device number !"
        exit
    }
    image_par(__ccd_u,"erase")
    waitacq2
}'

#%UU% [image mode] [ccd device number]
#%MDESC change image SIZE mode possible values are: %BR%
#[1800,1200,2400,1600,3000,2000,3450,2300] %BR%
# MAR SCANNER only.
def ccdmode '{
    local  __mode  __ccd_u  __modeS __oldmode

    __modeS[1800]= 1; __modeS[1200]= 1; __modeS[2400]= 1; __modeS[1600]= 1
    __modeS[3000]= 1; __modeS[2000]= 1; __modeS[3450]= 1; __modeS[2300]= 1

    if ($#==2)
        __ccd_u=$2
    else
        __ccd_u=CCD_U
    if (image_par(__ccd_u,"controller") != "SCANNER" ) {
        print "CCD Device "__ccd_u" is not a MAR SCANNER"
        print "Please, check with ccdmenu or set \"CCD_U\" to the correct device number !"
        exit
    }
    __oldmode = image_par(__ccd_u,"mode")
    if($#)
        __mode = $1
    else{
        print "       Pixelsize   Diameter      SIZE       File name extension"
        print "         [mm]        [mm]"
        print "         0.15       345.0     2300 * 2300   .mar2300"
        print "                    300.0     2000 * 2000   .mar2000"
        print "                    240.0     1600 * 1600   .mar1600"
        print "                    180.0     1200 * 1200   .mar1200"
        print "         0.10       345.0     3450 * 3450   .mar3450"
        print "                    300.0     3000 * 3000   .mar3000"
        print "                    240.0     2400 * 2400   .mar2400"
        print "                    180.0     1800 * 1800   .mar1800\n"

        __mode = getval("Mode [2300,2000,1600,1200,3450,3000,2400,1800]",\
                        __oldmode)
    }
    if (__mode in __modeS) {
        if (__mode != __oldmode){
            image_par(__ccd_u,"mode",__mode)
            waitacq2
        }
    } else printf("Invalid mode %d\n",__mode)
    #resize the image array
    ccd_createarray __ccd_u
    #reread the image (a blank image !)
    sleep(1)
    ccdread
}'

#%UU% [view factor] [ccd device number]
#%MDESC change the view factor (1/xth of image seen) %BR%
# MAR Scanner only.
def ccdviewfactor '{
    local __ccd_u _view_factor
    if ($#==2)
        __ccd_u=$2
    else
        __ccd_u=CCD_U
    if (image_par(__ccd_u,"controller") != "SCANNER" ) {
        print "CCD Device "__ccd_u" is not a MAR SCANNER"
        print "Please, check with ccdmenu or set \"CCD_U\" to the correct device number !"
        exit
    }
    if($#)
        _view_factor = $1
    else
        _view_factor=getval("View Factor (1/xth of the image you want to see in Spec)",\
                    image_par(__ccd_u,"view_factor"))

    if (_view_factor>0 && _view_factor<=10)
        image_par(__ccd_u,"view_factor",_view_factor)
    else
        printf("Wrong view factor %d\n",_view_factor);
    #resize the image array
    ccd_createarray __ccd_u
    #reread the image
    sleep(1)
    ccdread
}'


#         ------------------ Frelon Camera ---------------------

#%IU%  [<command>]
#%MDESC% Sends a command directly to the camera.  Only for Frelon
def f4send '{
        if ($#)
            cmd = "$1"
        else
            cmd = getval("Command to send","")

        if (cmd != "") {
            image_par(CCD_U,"talk",sprintf("%s\r\n",cmd))
            f3_dump
        }
}'
#%IU%  [<command>]
#%MDESC% Sends a command directly to the camera.  Only for Frelon
#        Working on frelon device server
def f5send '{
        if ($#)
            cmd = "$1"
        else
            cmd = getval("Command to send","")

        if (cmd != "") {
            image_par(CCD_U,"talk",sprintf("%s\r\n",cmd))
        sleep(1.5)
            p image_par(CCD_U,"talk")
        }

}'


#%IU%  [<command>]
#%MDESC% Sends a command directly to the camera.  Only for Frelon 2k
#        Working on frelon/espia device server
def f3send '{
    if ($#){
        cmd = "$1"
    }
    else {
        cmd = getval("Command to send","")
    }

    if (cmd != "") {
        p image_par(CCD_U,"talk",sprintf("%s\r\n",cmd))
    }

}'


#%IU%
#%MDESC% Reads directly the output from the camera controller and writes
# it to the screen. Only for Frelon
def f3_dump ' {
    global TIMEOUT_READ
    TIMEOUT_READ = 0
        for (;;) {
                sleep (.05)
                if ((res = image_par(CCD_U,"talk")) == "") {
                    sleep (.1)
                    if ((res = image_par(CCD_U,"talk")) == "")
                        break
                }
                if (image_par(CCD_U,"talk") == 0) {
            if (TIMEOUT_READ++ > 20 ) {
                p
                p "Check the Device Server is running!"
                p
                p "Looks like your Frelon is not connected !!"
                p "Check that the camera is POWERED ON !!"
                p "the MUX is also ON and the fibers are"
                p "connected as they should"
                p
                p
                break
            }
                }
        }
}'
#%UU%
#%MDESC% Frelon Menu to talk directly to the camera controller.
#A lot of parameters can be configured this way.
def f3menu '{
    for (;;) {
            if ((ch = input(-1)) != "") {
                if (ch == "\n") {
                    image_par(CCD_U,"talk", "\r\n")
                } else if  (ch == "~") {
                    ccdlive
                    image_par(CCD_U,"talk", "\r\n")
                } else {
                    image_par(CCD_U,"talk", ch)
                }
            }
            printf(image_par(CCD_U,"talk"))
    }
}'

#%UU% [filename]
#%MDESC% Sets the camera up using a special configuration file. The
# file consists of a list of the commands to send. Only for Frelon
def f3sendfile '{
    global F3_PNAME
    local line

    if ($#)
            F3_PNAME = "$1"
    else
        F3_PNAME = getval("Enter config filename",F3_PNAME)

    if (getline (F3_PNAME,"open") == "-1") {
            printf("Could not open your file: %s\n",F3_PNAME)
            exit
    }

    for (;(line = getline (F3_PNAME)) != "-1";) {
            line = substr(line,1,length(line)-1)
            image_par(CCD_U,"talk",sprintf("%s\r\n",line))
            printf("*********%s***********\n",line)
            sleep(1)
            f3_dump
    }

    getline (F3_PNAME,"close")
}'

#%UU%
#%MDESC% Creates an image with a big letter R. This can be used to
# define the camera orientation for other programs to be read in.
def ccdcreateR '{
  local maxr maxc radius start
  maxr = array_op("rows",@ARRAYNAME) ; maxc = array_op("cols",@ARRAYNAME)
  radius = maxr / 4 ; start = maxc / 10
  @ARRAYNAME = 300
  @ARRAYNAME[][start:start+40]=30000
  for (i=-PI/2;i<PI/2;i+=0.005) {
    cx = (1+sin(i)) * radius
    cy = cos(i) * radius + start
    @ARRAYNAME[cx:cx+30][cy:cy+30] = 30000
  }
  for (i=0;i<maxr-2*radius-31;i++) {
    cx = 2*radius + i
    cy = start + i
    @ARRAYNAME[cx:cx+30][cy:cy+30] = 30000
  }
}'

def _ccd_set_concat(val) '{
  global CCD_INSCAN

  if (val == 1)
     CCD_INSCAN = 1

  if ((val == 0) && (NPTS == (_n1-1)))
    CCD_INSCAN = 0
}'

def _ccd_cleanup_concat '{
  CCD_INSCAN = 0
}'

def ccds_check_test '{
    # Print various parameters to help you to understand what is the state of your CCDs.

    local  ccd_u

    printf("CCDU   CCD_ON     %30s   i_par(disable)   i_par(controller)      OK?   OK_and_ON? \n", "image_par(ccd_u,device_id)")
    for (ccd_u=0;ccd_u < CCDS; ccd_u++) {
        printf(" %s     %s          %30s   %s                %15s        %s     %s\n", \
               ccd_u, CCD_ON[ccd_u], image_par(ccd_u,"device_id"), image_par(ccd_u,"disable"), \
               image_par(ccd_u, "controller"), ccd_is_ok(ccd_u), ccd_is_ok_and_on(ccd_u))
    }
}'

def ccd_is_ok(ccd_config_index, verbose) '{
    # ??? does not take VERSION into account ???

    if (image_par(ccd_config_index, "controller") ==  "Unconfigured") {
        if(verbose) {
            printf("CCD %d is not configured. (OFF in config)\n", ccd_config_index)
        }
        return 0
    }

    if (image_par(ccd_config_index, "device_id") ==  "?") {
        if(verbose) {
            printf("CCD %d is not working. (DS not running ?)\n", ccd_config_index)
        }
        return 0
    }

    if (image_par(ccd_config_index, "device_id") ==  "-1") {
        if(verbose) {
            printf("CCD %d is not working. (???)\n", ccd_config_index)
        }
        return 0
    }

    if(verbose) {
        printf("CCD %d ok\n", ccd_config_index)
    }

    return 1
}'

def ccd_is_ok_and_on(ccd_config_index, verbose) '{
    # Return 1 if CCD <ccd_config_index> is OK and ON

    if (ccd_is_ok(ccd_config_index, verbose)  && (CCD_ON[ccd_config_index] == 1)) {
        if(verbose) {
            printf("CCD %d is ok and ON\n", ccd_config_index)
        }
        return 1
    }
    else{
        if(verbose) {
            printf("CCD %d is not OK or not ON \n", ccd_config_index)
        }
        return 0
    }
}'


# force loading dependent macros.
jdo ccdbpm.mac

#%MACROS%
#%IMACROS%
#%AUTHOR%
#  CCD.MAC - BLISS modified 3/9/96 JK, 03/6/01 DFC
#%TOC%