esrf

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

#%TITLE% mccd.mac
#%NAME% 
#  Macros to work with Mar CCD on a Linux System
#
#%CATEGORY% Detection, Ccd
#
#%DESCRIPTION% These macros replace the standard ccd macros for the
# Mar CCD. They send commands to the device server which has been spawned
# by the Michael Blum Motif Software.
#
#%LOG%
#
#$Log: mccd.mac,v $
#Revision 2.27  2012/09/13 07:36:41  claustre
#slow mode is no longer working with new marccd application(>0.18) so added support
#for EDF format in fast-mode. On can remove support for slow mode, but now we should switch
#to LIMA instead.
#
#Revision 2.26  2012/06/07 11:37:45  claustre
#increase delay of 2sec in mccd_getimage with workaround with multiple write command bug
#
#Revision 2.25  2010/09/29 06:49:41  homsrego
#* mccdfilename: cloned from ccdfilename to include the custom format
#
#Revision 2.24  2010/07/20 13:35:48  witsch
#in macro mccdread added file type edf to the conditions that will transfer
#the data into spec.
#
#added chained macros user_mccdon and user_mccdoff
#Hook macro to trigger action at execution of mccdon or off
#could allow to cdef macros to i.e. open/close shutter
#
#
#in macro mccdsave2 added user_mccd_header to the case that the file type is edf.
#
#Revision 2.24  2010/07/19 15:06:50  witsch
#in macro mccdread added file type edf to the conditions that will transfer
#the data into spec.
#
#added chained macros user_mccdon and user_mccdoff
#Hook macro to trigger action at execution of mccdon or off
#could allow to cdef macros to i.e. open/close shutter
#
#Revision 2.23  2010/07/16 05:41:31  perez
#Fix bug in mccdcorrect
#
#Revision 2.22  2010/04/22 12:24:21  guilloud
#add an unsetup command to clean after an mccd removal.
#
#Revision 2.21  2010/03/26 16:26:23  spruce
#add option to mccdsave to save the image as an edf if the user specifies .edf as the file suffix.
#
#Revision 2.20  2009/09/11 12:49:55  sever
#Added DARK_LEVEL_OPTION global variable to allow other than default(=10) value
#
#Revision 2.19  2008/08/12 13:32:45  rey
#documentation changes
#
#Revision 2.18  2007/10/11 07:59:00  guijarro
#added missing { } in _mccdacq
#
#Revision 2.17  2007/09/12 18:53:50  claustre
#added brackets to mccdsetup, otherwise arch can be overwritten
#
#Revision 2.16  2007/09/10 08:50:36  claustre
#cleanup the mccdsetup about saving mode and added more comment about the
#fastmode.
#
#Revision 2.15  2007/03/28 12:08:19  claustre
#work-around to be able to read image from spec just after a image saving
#
#Revision 2.14  2007/03/09 12:27:59  guilloud
#add a touch of the shared memory in mccd_getimage.
#
#Revision 2.13  2006/09/12 13:06:12  guijarro
#added support for jpeg thumbnails (needs latest Mar software)
#
#Revision 2.12  2005/09/21 12:38:01  pepellin
#Use clscreen()
#
#Revision 2.11  2005/04/11 15:58:34  claustre
#Hoops, still a syntax bug !!
#
#Revision 2.10  2005/03/04 16:51:38  claustre
#change mccdread macro to only get the image if MCCD_ON& MCCD_INTEGR || MCCD_DIS
#
#Revision 2.9  2004/09/29 08:32:52  papillon
#add hook user_mccd_header
#
#Revision 2.8  2004/09/28 14:17:16  claustre
#Finished to put compatible all the macros with the fast/slow mode feature of the marccd application.
#Added two new macros mccdenable/mccddisable to set the detector as a integration counter.
#
#Revision 2.7  2004/09/03 14:12:19  papillon
#Correct filename generation in fast read mode
#
#Revision 2.6  2004/09/03 13:03:00  claustre
#Add fast readout mode only compatible with marccd 0.9.30f and upper and with MarCCDds 2.45 and upper
#
#Revision 2.5  2004/06/28 11:08:53  claustre
#added chainable macros into mccdtake for custom us on bl
#
#Revision 2.4  2003/12/03 17:09:43  claustre
#Dezinger correction added + fix on mccdtake_bkg.
#
#Revision 2.3  2003/08/25 13:09:03  claustre
#remove ccd* definitions + special mccdsave2.
#
#Revision 2.2  2003/07/15 15:08:26  claustre
#fixed bug with arch detection + added specgui printout of message
#
#Revision 2.1  2003/06/26 08:42:46  claustre
#Version compatible with MarCCDds dserver 2.3 and newer
#
#Revision 2.0  2003/06/23 15:07:59  claustre
#only working with MarCCDds version 2.2 and newer
#
#%END%

global MCCD_ON MCCD_DIS MCCD_AUTOSAV MCCD_FILEPAR 
global MCCD_ROI MCCD_INTEGR MCCD_NORM MCCD_MNE[]
global MCCD_FILENAME MCCD_HEADER MCCD_CORR
global MCCD_DEVICE MCCD_SWAP MCCD_SERVERMODE
global MCCD_STATE MCCD_PSTATE MCCD_DEZINGER
global MCCD_DARK_LEVEL

global MAR_TASK MAR_STATE
global MAR_ACQUIRE MAR_READ MAR_CORRECT MAR_WRITE MAR_DEZINGER
global MAR_IDLE MAR_QUEUED MAR_EXEC MAR_ERROR MAR_RESERVED

global MCCD_THUMBNAIL1 MCCD_THUMBNAIL2 MCCD_STOP_WITH_FILE

MAR_READ     = 1
MAR_CORRECT  = 2
MAR_WRITE    = 3
MAR_DEZINGER = 4

MAR_IDLE     = 0
MAR_QUEUED   = 1
MAR_EXEC     = 2
MAR_ERROR    = 4
MAR_RESERVED = 8

MAR_TASK[MAR_ACQUIRE]  = "Acquiring"
MAR_TASK[MAR_READ]     = "Reading"
MAR_TASK[MAR_CORRECT]  = "Correcting"
MAR_TASK[MAR_WRITE]    = "Writing"
MAR_TASK[MAR_DEZINGER] = "Dezingering"

MAR_STATE[MAR_IDLE]     = "Idle"
MAR_STATE[MAR_QUEUED]   = "Queued"
MAR_STATE[MAR_EXEC]     = "Exec"
MAR_STATE[MAR_ERROR]    = "Error"
MAR_STATE[MAR_RESERVED] = "Reserved"

#%UU% [device-name 0|1 0|1]
#%MDESC% Sets the parameters for the Mar CCD camera. Parameter 2 specifies
# what to save to disk : 0 save only raw images, 1 save only corrected
# images. %BR%
#The third parameter defines whether or not the marccd software is configured
# in fast mode. Check into the ~marccd/configuration/marccd_server_IDXX.conf 
#if the flag called "remote_mode_version" is set to 0 (slow) or 1 (fast).  %BR%
# In fast mode the marccd software can aquire and correct/save an image in
# parallel, which allows to speed up when collecting several images. %BR%
# Device name has has the form "ID9/marccd/1" on beamline ID9.
def mccdsetup '{

    local arch

    if ((whatis("MCCD_CORR")&0x08000000)) {
        MCCD_CORR=1
    }
    if ((whatis("MCCD_DARK_LEVEL")&0x08000000)) {
        MCCD_DARK_LEVEL=10
    }
    if ((whatis("MCCD_THUMBNAIL")&0x08000000)) {
        MCCD_THUMBNAIL["enable1"]=0
        MCCD_THUMBNAIL["enable2"]=0
        MCCD_THUMBNAIL["filename1"]=""
        MCCD_THUMBNAIL["filename2"]=""
        MCCD_THUMBNAIL["format1"]="JPG"
        MCCD_THUMBNAIL["format2"]="JPG"    
        MCCD_THUMBNAIL["xsize1"]=0
        MCCD_THUMBNAIL["ysize1"]=0
        MCCD_THUMBNAIL["xsize2"]=0
        MCCD_THUMBNAIL["ysize2"]=0
    }
    if ($#) {
        MCCD_DEVICE   = "$1"
        MCCD_CORR     = $2
        MCCD_SERVERMODE = $3
    } else {
        MCCD_DEVICE = getval ("Device name for the Mar CCD detector",MCCD_DEVICE)
        for (;;) {
            type = getval ("Save (R)aw image, (C)orrected image ", (MCCD_CORR == 0) ? "R" :  "C")

            if (type == "c" || type == "C") { 
                MCCD_CORR = 1 ; break 
            } else if (type == "r" || type == "R") { 
                MCCD_CORR = 0 ; break 
            }
        }
        MCCD_SERVERMODE = getval( "Read mode (0=slow/1=fast --check if available--)", MCCD_SERVERMODE )
    }

    if ((whatis("MCCD_FILEPAR")&0x08000000)) {
        MCCD_FILEPAR["dir"]=  "/tmp"
        MCCD_FILEPAR["prefix"] = "test_"
        MCCD_FILEPAR["suffix"] = ".mccd"
        MCCD_FILEPAR["inum"] = "0"
    }

    #has to swapped image if host is not running  linux (not a PC of course)
    unix("uname",arch)
    if (index(arch,"Linu")) {
        MCCD_SWAP=0
    } else {
        MCCD_SWAP=1
    }
    # create image data array
    mccd_createarray
}
'


#%UU%
#%MDESC%
#    Removes mccd globals and cdefs.
def mccdunsetup '{

    mccdoff

    cdef("user_getcounts", "", MCCD_MNE["1"], "delete")
    cdef("user_prepcount", "", "__mccd__", "delete")
    cdef("user_getcounts", "", "__mccd__", "delete")

    undef user_mccd_header
    undef user_mccdon
    undef user_mccdoff
    undef mccd_take_user_prep
    undef mccd_take_user_start
    undef mccd_take_user_end
    undef mccd_ctscan_private_menu
    undef mccd_ctscan_private_option

    unglobal MCCD_ON MCCD_DIS MCCD_AUTOSAV MCCD_FILEPAR 
    unglobal MCCD_ROI MCCD_INTEGR MCCD_NORM MCCD_MNE[]
    unglobal MCCD_FILENAME MCCD_HEADER MCCD_CORR
    unglobal MCCD_DEVICE MCCD_SWAP MCCD_SERVERMODE
    unglobal MCCD_STATE MCCD_PSTATE MCCD_DEZINGER
    unglobal MCCD_DARK_LEVEL
    unglobal MAR_TASK MAR_STATE
    unglobal MAR_ACQUIRE MAR_READ MAR_CORRECT MAR_WRITE MAR_DEZINGER
    unglobal MAR_IDLE MAR_QUEUED MAR_EXEC MAR_ERROR MAR_RESERVED
    unglobal MCCD_THUMBNAIL1 MCCD_THUMBNAIL2 MCCD_STOP_WITH_FILE
}
'


#%IU% ( )
#%MDESC% return 0 if a new bkg image is need otherwise the current image size.
def _mccdcheck_bkg () '{
    local bkg_xsize xsize
    xsize    = esrf_io(MCCD_DEVICE,"DevCcdXSize",0)
    bkg_xsize= esrf_io(MCCD_DEVICE,"DevCcdXSize",1)
    #if binning has changed raw size if different than bkg size and at startup
    #time bkg size is 0.
    return (bkg_xsize&xsize)
}
'

# Hook macro to insert specific header parameters
cdef("user_mccd_header")

# Hook macro to trigger action at execution of mccdon or off
# could allow to cdef macros to i.e. open/close shutter 
cdef("user_mccdon")
cdef("user_mccdoff")

#%UU% (filename[,header])
#%MDESC% Saves the acquired image. Use this macros after "mccdstop"
# and "mccdwait"%BR%
# The filename is interpreted on the computer controlling the CCD detector,
# not the local machine. %BR%
# Optional information to be written in the file header can be passed in
# the associative array "header". Valid header keywords are:
# "detector_distance", "rotation_range", "start_phi", "source_wavelength",
# "exposure_time", "beam_x", "beam_y", "file_comments", "dataset_comments".

def mccdsave_f (filename, head)'{
    if ( MCCD_SERVERMODE == 0 ) {
        local inp header[] i ESRF_ERR

        user_mccd_header

        if (whatis ("head") & 0x01000000) {
            for (idx in head) {
                header[i++] = sprintf("%s=%s",idx,head[idx])
            }
            esrf_io (MCCD_DEVICE,"DevCcdHeader",header)
        }

        if (length(filename)) {
            mccdwait
            notice ("CCD saving file...")
            inp[0]=filename
            if (MCCD_CORR == 0) { # save raw image
                inp[1] = 0
            }
            if (MCCD_CORR == 1) { # save corrected image
                inp[1] = 1
            }
            esrf_io(MCCD_DEVICE,"DevCcdWriteFile",inp)
            mccdwait

            if (MCCD_STATE == 3) {
                tty_cntl("md")
                printf("Cannot write file to the disk, check permission !!\n")
                tty_cntl("me")
            }
            notice (sprintf("Image Saved to File \"%s\"", filename))   
        }
    } 

}
'

#%UU% <0|1> [filename,format,xsize,ysize]
#%MDESC% Set the parameters for the thumbnail image1 or disable the saving
def mccdthumbnail1 '{
    global MCCD_THUMBNAIL[]
    local argin
    if (!$#) {
        MCCD_THUMBNAIL["enable1"] = yesno("Do you want to enable the thumbnail image1 saving",MCCD_THUMBNAIL["enable1"])
        if (MCCD_THUMBNAIL["enable1"]) {    
            MCCD_THUMBNAIL["filename1"] = getval("Thumbnail 1 filename", MCCD_THUMBNAIL["filename1"])
            print "Supported format are PGM,RAW,TIFF,JPG,GIF,PNG,EPS,MIFF,HTML, and FITS\nIf ImageMagick (convert) is not installed, then only PGM,RAW and TIFF are supported."
            MCCD_THUMBNAIL["format1"] = getval("Thumbnail 1 format", MCCD_THUMBNAIL["format1"])
            print "Horizontal and vertical size in pixels, or maximum dimension if xsize is 0"
            MCCD_THUMBNAIL["xsize1"] = getval("Thumbnail 1 xsize", MCCD_THUMBNAIL["xsize1"])
            MCCD_THUMBNAIL["ysize1"] = getval("Thumbnail 1 ysize", MCCD_THUMBNAIL["ysize1"])    
        }
    } else {
        MCCD_THUMBNAIL["enable1"] = $1
        if (MCCD_THUMBNAIL["enable1"]) {
            MCCD_THUMBNAIL["filename1"]  = "$2"
            MCCD_THUMBNAIL["format1"]  = "$3"
            MCCD_THUMBNAIL["xsize1"]  = $4
            MCCD_THUMBNAIL["ysize1"] = $5
        }
    } 
}
'

#%UU% <0|1> [filename,format,xsize,ysize]
#%MDESC% Set the parameters for the thumbnail image2 or disable the saving
def mccdthumbnail2 '{
    global MCCD_THUMBNAIL[]
    local argin
    if (!$#) {
        MCCD_THUMBNAIL["enable2"] = yesno("Do you want to enable the thumbnail image1 saving",MCCD_THUMBNAIL["enable2"])
        if (MCCD_THUMBNAIL["enable2"]) {
            MCCD_THUMBNAIL["filename2"] = getval("Thumbnail 2 filename", MCCD_THUMBNAIL["filename2"])
            printf("Supported format are PGM,RAW,TIFF,JPG,GIF,PNG,EPS,MIFF,HTML, and FITS\nIf ImageMagick (convert) is not installed, then only PGM,RAW and TIFF are supported.")
            MCCD_THUMBNAIL["format2"] = getval("Thumbnail 2 format", MCCD_THUMBNAIL["format2"])
            print "Horizontal and vertical size in pixels, or maximum dimension if xsize is 0"
            MCCD_THUMBNAIL["xsize2"] = getval("Thumbnail 2 xsize", MCCD_THUMBNAIL["xsize2"])
            MCCD_THUMBNAIL["ysize2"] = getval("Thumbnail 2 ysize", MCCD_THUMBNAIL["ysize2"]) 
        }  
    } else {
        MCCD_THUMBNAIL["enable2"] = $1
        if (MCCD_THUMBNAIL["enable2"]) {
            MCCD_THUMBNAIL["filename2"]  = "$2"
            MCCD_THUMBNAIL["format2"]  = "$3"
            MCCD_THUMBNAIL["xsize2"]  = $4
            MCCD_THUMBNAIL["ysize2"] = $5
        }
    }
}
' 

#%IU%
#%MDESC% 
def mccd_sendthumbnail1() '{
    local argin

    argin[0] = MCCD_THUMBNAIL["format1"]
    argin[1] = MCCD_THUMBNAIL["xsize1"]
    argin[2] = MCCD_THUMBNAIL["ysize1"]
    esrf_io(MCCD_DEVICE,"DevCcdSetThumbnail1",argin)
}
'

#%IU%
#%MDESC% 
def mccd_sendthumbnail2() '{
    local argin

    argin[0] = MCCD_THUMBNAIL["format2"]
    argin[1] = MCCD_THUMBNAIL["xsize2"]
    argin[2] = MCCD_THUMBNAIL["ysize2"]
    esrf_io(MCCD_DEVICE,"DevCcdSetThumbnail2",argin)
}
'

#%UU%
#%MDESC% save the current image as the thumbnail image1
def mccdsave_thumbnail1 '{
    local argin
    if (MCCD_THUMBNAIL["enable1"]) {
        argin[0] = MCCD_THUMBNAIL["filename1"]
        argin[1] = MCCD_CORR
        mccd_sendthumbnail1()
        esrf_io(MCCD_DEVICE, "DevCcdWriteThumbnail1",argin)
    }
}
'

#%MDESC% save the current image as the thumbnail image1
def mccdsave_thumbnail2 '{
    local argin
    if (MCCD_THUMBNAIL["enable2"]) {
        argin[0] = MCCD_THUMBNAIL["filename2"]
        argin[1] = MCCD_CORR
        mccd_sendthumbnail2()
        esrf_io(MCCD_DEVICE, "DevCcdWriteThumbnail2",argin)
    }
}
'

#%UU%
#%MDESC% Stops the data taking and starts the CCD readout
def mccdstop '{
    local argin 

    argin[2]=""
    argin[3]=""

    if (MCCD_THUMBNAIL["enable1"]) {
        argin[2] = MCCD_THUMBNAIL["filename1"]
        mccd_sendthumbnail1()
    }
    if (MCCD_THUMBNAIL["enable2"]) {
        argin[3] = MCCD_THUMBNAIL["filename2"]
        mccd_sendthumbnail2()
    }

    if ( MCCD_SERVERMODE == 1 ) {
        argin[0] = 0
        argin[1] = MCCD_FILENAME
        # That statement set a variable to inform mccd_getimage
        # about a file writing and to take care of a bug in mccd appli.
        # L.Claustre 28/03/2007
        if (MCCD_FILENAME !="") {
            MCCD_STOP_WITH_FILE = 1
        }
        else {
            MCCD_STOP_WITH_FILE = 0
        }

        marwait(MAR_READ,   MAR_IDLE)
        
        
        if (MCCD_FILENAME !="") {
            mccd_sendheader()
        }
        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)
        marwait(MAR_READ,   MAR_EXEC)
        notice (sprintf("Image being saved to File \"%s\"", MCCD_FILENAME)) 
    } else {
        _mccd_state()
        if (MCCD_STATE != 2) {
            mccdwait
        }

        argin[0] = 0
        argin[1] = ""

        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)
        notice ("CCD readout...") 
    }
}
'

#%IU%
#%MDESC% 
def mccdabort '{
    local argin
    argin[0] = 0
    argin[1] = ""
    argin[2] = ""
    argin[3] = ""
    marwait(MAR_READ,   MAR_IDLE)
    esrf_io(MCCD_DEVICE, "DevCcdStop", argin)
}
'

#%IU%
#%MDESC% 
def mccd_sendheader() '{
    local i idx header[]
    MCCD_HEADER["file_comment"]=MCCD_FILENAME
    i=0
    for (idx in MCCD_HEADER) {
        header[i++] = sprintf("%s=%s",idx,MCCD_HEADER[idx])
    }
    esrf_io(MCCD_DEVICE,"DevCcdHeader",header)
}
'

#%UU%
#%MDESC% Stops the data taking and starts the CCD readout The image will be
#put in the SCRATCH image buffer.
def mccdstop_dezinger '{
    local argin 

    if ( MCCD_SERVERMODE == 1 ) {
        argin[0] = 2
        argin[1] = "" 
        argin[2] = ""
        argin[3] = ""

        marwait(MAR_READ,   MAR_IDLE)
        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)

    } else {
        _mccd_state()
        if (MCCD_STATE != 2) {
            mccdwait
        }
        argin[0] = 2
        argin[1] = ""
        argin[2] = ""
        argin[3] = ""
        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)

    }

    notice ("CCD readout...") 
}
'

#%UU%
#%MDESC% Stops the data taking and starts the CCD readout. The image will be
#put in the background image buffer.
def mccdstop_bkg '{
    local argin 

    if ( MCCD_SERVERMODE == 1 ) {

        argin[0] = 1
        argin[1] = ""
        argin[2] = ""
        argin[3] = ""

        marwait(MAR_READ,   MAR_IDLE)
        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)

    } else {
        _mccd_state()
        if (MCCD_STATE != 2) {
            mccdwait
        }
        argin[0] = 1
        argin[1] = ""  
        argin[2] = ""
        argin[3] = ""

        esrf_io(MCCD_DEVICE,"DevCcdStop",argin)
    } 

    notice ("CCD readout...")
}
'


#%UU%
#%MDESC% Starts correcting the image. You have to collect a background image
# first
def mccdcorrect '{

    if ( MCCD_SERVERMODE == 0 ) {
        mccdwait
        notice ("CCD correction...")
        esrf_io (MCCD_DEVICE,"DevCcdCorrect")
        mccdwait


        if (MCCD_STATE == 3) {
            notice ("CCD background image required")
            mccdtake_bkg

            notice ("CCD correction...")
            esrf_io (MCCD_DEVICE,"DevCcdCorrect")
        }
    }

}
'

#%UU%
#%MDESC% Starts dezingering of the image. You have to collect a reference image
# first using mccdstop_dezinger. Of course exposure condition for both images have to be the same
# otherwise you will get a wrong correction. See the mccdtake_dezinger test macro as an example.
def mccd_dezinger '{

    mccdwait
    notice ("CCD dezinger...")
    esrf_io (MCCD_DEVICE,"DevCcdDezinger",0)
    mccdwait


    if (MCCD_STATE == 3) {   
        notice ("CCD scratch image required")
    }   
}
'

#%UU%
#%MDESC% Starts image taking on the mar system after having made sure that
#the detector is in IDLE state (which happens to be 0).
def mccdstart '{
    local t
    global ESRF_ERR

    esrf_io (MCCD_DEVICE,"tcp") # Use TCP/IP protocol
    ESRF_ERR = -1; esrf_io(MCCD_DEVICE,"DevState")

    mccd_checkconnect()
    cdef("cleanup_once", "mccdabort\n", "mccd")

    if ( MCCD_SERVERMODE == 1) {
        if (_mccdcheck_bkg() == 0) {
            mccdtake_bkg
        }

        marwait(MAR_READ,   MAR_IDLE)

        esrf_io(MCCD_DEVICE,"DevCcdStart")
        marwait(MAR_ACQUIRE,MAR_EXEC)

    } else {
        _mccd_state()
        if (MCCD_STATE == 2) {mccdstop; mccdwait}
        mccdwait

        if (_mccdcheck_bkg() == 0) {
            mccdtake_bkg
        }

        esrf_io (MCCD_DEVICE,"DevCcdStart")
        # wait for state ACQUIRING
        _mccdwait(2)

    }
    notice ("CCD integrating...")
}
'


#%IU% ()
#%MDESC% check if the device server is alive
def mccd_checkconnect() '{

    while (ESRF_ERR == 2 || ESRF_ERR == 3) {
        # 2 = RPC client call timeout, 3 = RPC client call failed 
        # these are transient errors
        notice (t="MAR CCD: lost connection ("ESRF_ERR") - retrying...")
        sleep (0.25)
        ESRF_ERR = -1; esrf_io (MCCD_DEVICE,"DevState") 
    }

    if (ESRF_ERR) {
        esrf_io (MCCD_DEVICE,"DevState")
        print "Make sure that the \"marccd\" program is started and running in remote mode"
        print "(see menu Acquire/Remote Control)."
        exit
    }

}
'

#%UU% <time>
#%MDESC% Expose the CCD for <time> seconds. Dezinger correction is applied.
# The image is not saved automatically.
# This is a good example of how to proceed a dezingered image
def mccdtake_dezinger '{

    if (MCCD_DEZINGER) {
        mccd_take_user_prep $1
        mccdstart
        mccd_take_user_start $1

        # Do something here
        sleep($1)
        mccd_take_user_end $1
        mccdstop_dezinger
    }
    mccd_take_user_prep $1
    mccdstart
    mccd_take_user_start $1
    sleep($1)
    mccd_take_user_end $1
    MCCD_FILENAME=""
    mccdread_dezinger
}
'


#%IU% %MDESC% hook macro to prepare the image acquisition, e.g. closing a shutter
cdef ("mccd_take_user_prep","_1=$1;","_mccdtake_")
#%IU% %MDESC% hook macro to start the imatge acquisition, e.g pulsing a shutter
cdef ("mccd_take_user_start","_1=$1;","_mccdtake_")
#%IU%
#%MDESC% hook macro to prepare the image acquisition, e.g. waiting 
# for the shutter is closed.
cdef ("mccd_take_user_end","_1=$1;","_mccdtake_")

#%UU% <time>
#%MDESC% Expose the CCD for <time> seconds. The image is not saved automatically except in fast-mode
# even for edf format

def mccdtake '{

    mccd_take_user_prep $1
    mccdstart
    mccd_take_user_start $1
    # Do something here
    sleep($1)
    mccd_take_user_end $1

    if (MCCD_SERVERMODE==1)  {
        #if fastmode and edf format request, do not allow automatic
        #saving but make a manual saving with SPEC using mccdsave like for
        # the slow-mode
        if (MCCD_FILEPAR["suffix"]==".edf") { 
            MCCD_FILENAME=""
        } else {
            mccd_genfilename()
        }
    }

    mccdread

    if (MCCD_SERVERMODE==1 && MCCD_FILEPAR["suffix"]==".edf")  {
        mccdwait; sleep(1)
        mccd_genfilename()
        mccdsave2
    }

}
'


#%UU%
#%MDESC% Taking a background image.Don't need to acquiring on ccd, just readout
#the detector, Zinger correction is applied all the time.
def mccdtake_bkg '{
    _mccd_state()

    if (MCCD_STATE == 2) {
        notice ("CCD Clearing before background image ...")
        mccdstop
    }
    mccdwait

    notice ("CCD Scratch image (Reading)...")
    mccdstop_dezinger

    notice ("CCD background image (Reading)...")
    mccdstop_bkg

    mccdwait

    notice ("CCD Zinger  Correction...")
    esrf_io (MCCD_DEVICE,"DevCcdDezinger",1)       
    mccdwait
}
'

#%MDESC%  Readout the detector, applies Dezinger correction and correct the image
def mccdread_dezinger '{
    mccdstop
    notice("CCD reading ...")
    if (MCCD_SERVERMODE==0) {
        mccdwait
    }

    mccd_dezinger

    if (MCCD_SERVERMODE==0) {
        if (MCCD_CORR) {
            mccdcorrect
            mccdwait
        }
    }
    if (MCCD_ON || MCCD_DIS) {
        mccd_getimage MCCD_CORR
    }
}
'

#%UU%  
#%MDESC%  Readout the detector and correct the image
def mccdread '{

    mccdstop
    notice("CCD reading ...")

    if ( MCCD_SERVERMODE == 0 ) {
        mccdwait

        if (MCCD_CORR) {
            mccdcorrect
            mccdwait
        }
    }
    if ((MCCD_ON&&MCCD_INTEGR) || MCCD_DIS || (MCCD_FILEPAR["suffix"]==".edf")) {
        mccd_getimage MCCD_CORR
    }
}
'


#%IU%
#%MDESC% Starts the online display for the active camera. Tests first if not already running
def mccdmenu  '{
    local option bin[] roi[]

    option=1
    while (option!=0) {
        clscreen()
        printf("\n\n\n   MAR CCD Devices Configured :    ")
        tty_cntl("md"); printf ("<%s>\n\n", MCCD_DEVICE)
        tty_cntl("me")
        ################################################################## 
        printf ("    1 - Take image during ct/scans . . . . . . . . . . .:")
        tty_cntl("md");printf("%s\n",MCCD_ON?"<YES>":"<NO>")
        tty_cntl("me")
        if (MCCD_ON) {
            printf("\n")
            printf ("        11 - Save image after counting . . . . . . . . .:")
            tty_cntl("md");printf("%s\n",MCCD_AUTOSAV?"<YES>":"<NO>")
            tty_cntl("me")

            printf ("        12 - Integrate pixel values in counter . . . . .:")
            tty_cntl("md");printf("%s\n",MCCD_INTEGR?"<YES>":"<NO>")
            tty_cntl("me")
            if (MCCD_INTEGR) {
                printf("            Option: ")     
                tty_cntl("md");printf("<%s>",MCCD_NORM?((MCCD_NORM)==2?"Std":"Avg"):"Intgr")
                tty_cntl("me")             
                printf(" Mnemonic: ")
                tty_cntl("md")
                printf("<%s %s>\n",(MCCD_NORM==2)?MCCD_MNE["2"]:"",MCCD_MNE["1"])
                tty_cntl("me")
            }

            printf ("        13 - Dark level  . . . . . . . . . . . . . . . .:")
            tty_cntl("md"); printf("<%d>\n",MCCD_DARK_LEVEL)
            tty_cntl("me")

            mccd_ctscan_private_menu
        }
        printf("\n")
        ##################################################################
        printf ("    2 - File parameters  . . . . . . . . . . . . . . . .:\n")
        printf("         file ->    ")
        printf("<%s>\n",mccdfilename(MCCD_FILEPAR["dir"],MCCD_FILEPAR["prefix"],MCCD_FILEPAR["inum"],MCCD_FILEPAR["suffix"]))

        printf("         dir ->     ")
        tty_cntl("md"); printf(" %s\n", MCCD_FILEPAR["dir"])
        tty_cntl("me")
        printf("         prefix ->  ")
        tty_cntl("md"); printf(" %s\n", MCCD_FILEPAR["prefix"])
        tty_cntl("me")
        printf("         suffix ->  ")
        tty_cntl("md"); printf(" %s\n", MCCD_FILEPAR["suffix"])
        tty_cntl("me")
        printf("         next run ->")
        tty_cntl("md"); printf(" %s\n", MCCD_FILEPAR["inum"])
        tty_cntl("me")

        printf("\n")
        printf ("    3 - Do Dezinger correction . . . . . . . . . . . .:")
        tty_cntl("md");printf("%s\n",MCCD_DEZINGER?"<YES>":"<NO>")
        tty_cntl("me")   
        printf ("\n")

        printf ("    4 - Display image online. . . . . .  . . . . . . . .:")
        tty_cntl("md");printf("%s\n",MCCD_DIS?"<YES>":"<NO>")
        tty_cntl("me")
        printf("\n")

        printf ("    5 - Region Of Interest (ROI) . . . . . . . . . . . .:")
        tty_cntl("md");printf("%s\n",MCCD_ROI?"<YES>":"<NO>")
        tty_cntl("me")
        if (MCCD_ROI) {
            esrf_io(MCCD_DEVICE,"DevCcdGetRoI",roi)
            tty_cntl("me")
            printf ("        X -> ")
            tty_cntl("md");printf("%d, %d\n",roi[0],roi[2])
            tty_cntl("me")
            printf ("        Y -> ")
            tty_cntl("md");printf("%d, %d\n",roi[1],roi[3])
            tty_cntl("me")      
        }
        printf("\n")

        printf ("    6 - Binning (BIN). . . . . . . . . . . . . . . . . .:")
        esrf_io (MCCD_DEVICE,"DevCcdGetBin",bin)
        tty_cntl("md"); printf("<%d>\n",bin[0])
        tty_cntl("me")
        printf("\n")    
        printf("    0 - Exit")
        option = getval("\n\t\t     Option?  ",0) 

        if (option == 1 ) {
            if (MCCD_ON) {
                mccdoff
            }
            else {
                mccdon
            }
        }
        if (option == 11 ) {
            MCCD_AUTOSAV =\! MCCD_AUTOSAV
        }
        if (option == 12 ) {
            MCCD_INTEGR = \!MCCD_INTEGR
            if (MCCD_INTEGR) {
                mccdintegr 1
            }
            else {
                mccdintegr 0
            }
        }
        if (option == 13 ) {
            MCCD_DARK_LEVEL = getval("\t\tDark level per pixel ",MCCD_DARK_LEVEL)
        }
        if (option == 2) {
            mccdnewfile  
        }
        if (option == 3) {
            MCCD_DEZINGER = \!MCCD_DEZINGER
        }
        if (option == 4 ) {
            MCCD_DIS = \! MCCD_DIS
            if (MCCD_DIS) {
                mccd_online
            }
        }
        if (option == 5 ) {
            mccdroi
        }
        if (option == 6 ) {
            MCCD_BIN = \! MCCD_BIN
            mccdbin
        }
        mccd_ctscan_private_option
    }
}
'

#%IU% %MDESC% hook macro for private mccd menu
cdef ("mccd_ctscan_private_menu")
#%IU% %MDESC% hook macro for private mccd setup
cdef ("mccd_ctscan_private_option")

#%IU%
#%MDESC% 
def mccdintegr '{
    local _integr _oldcnt1 _oldcnt2
    if( !$# ) {
        _integr = yesno("Integrate pixel values in counter",1)
    } else {
        _integr = $1
    }
    MCCD_INTEGR = _integr

    if (_integr) {
        _oldcnt1 = MCCD_MNE["1"]; _oldcnt2 = MCCD_MNE["2"]
        MCCD_NORM = getval("\t\t0 = Integ, 1 = avg 2 = Avg&Std ",MCCD_NORM)
        if (MCCD_NORM!=2) {
            MCCD_MNE["1"] = getval("Counter mnemonic", MCCD_MNE["1"])
            MCCD_MNE["2"]=""
        } else {
            MCCD_MNE["1"] = getval("Avg counter mnemonic", MCCD_MNE["1"])
            MCCD_MNE["2"] = getval("Std counter mnemonic", MCCD_MNE["2"])
            if (cnt_num(MCCD_MNE["2"])==-1) {    
                tty_cntl("md")
                printf("Counter %s does not exist!!.",MCCD_MNE["2"])
                printf(" Use config to create it.\n")
                tty_cntl("me")
                input("(Hint \"Return\" to continue: )")
                MCCD_MNE["2"]=""
                MCCD_INTEGR=0
            } else {
                if (_oldcnt2!=MCCD_MNE["2"] && cnt_num(_oldcnt2)!=-1) {
                    S[_oldcnt2]=0
                }
            }
        }
        if (cnt_num(MCCD_MNE["1"])==-1) {
            tty_cntl("md")
            printf("Counter %s does not exist!!.",MCCD_MNE["1"])
            printf(" Use config to create it.\n")
            tty_cntl("me")
            input("(Hint \"Return\" to continue: )")
            MCCD_MNE["1"]=""
            MCCD_INTEGR=0
        } else {
            cdef("user_getcounts","mccdgetcounts()\n",MCCD_MNE["1"],0x22)
            if (_oldcnt1!=MCCD_MNE["1"] && cnt_num(_oldcnt1)!=-1) {
                S[_oldcnt1]=0
            }
        }
    } else {
        cdef ("","",MCCD_MNE["1"], "delete")
    }

}
'

#%IU#
#%MDESC%
def mccdgetcounts() '{
    local _cnt1 _cnt2 _std _avg _scale
    _cnt1 = cnt_num(MCCD_MNE["1"])
    _cnt2 = cnt_num(MCCD_MNE["2"])

    #do nothing if ct/scans is off
    if(MCCD_ON && _cnt1!=-1) {
        _scale= array_op("cols",mccd_image_data)*array_op("rows",mccd_image_data)
        if (MCCD_NORM) { 
            _avg=array_op("sum", mccd_image_data)/_scale
            _std=sqrt(array_op("sumsq",mccd_image_data - _avg )/_scale)
            if (MCCD_NORM==2 && _cnt2 !=-1) {
                _std=sqrt(array_op("sumsq",mccd_image_data - _avg )/_scale)
                S[_cnt2]=_std
            }
            S[_cnt1]= _avg - MCCD_DARK_LEVEL
        } else {
            S[_cnt1] = array_op("sum", mccd_image_data) - MCCD_DARK_LEVEL*_scale
        } 
    } else if (!MCCD_ON && _cnt1!=-1) {
        S[_cnt1]=0
        if (MCCD_NORM==2 && _cnt2!=-1) {
            S[_cnt2]=0
        }
    }
}
'
#%UU%
#%MDESC% short cut to enable/disable counters (if defined) and set on  for ct/scan +
#binning of 4.
def mccdenable ' _mccdenable();'
def _mccdenable ()'{
    local _cnt1 _cnt2
    _cnt1 = cnt_num(MCCD_MNE["1"])
    _cnt2 = cnt_num(MCCD_MNE["2"])

    if (MCCD_NORM==1 && _cnt2!=-1) {
        _enable(MCCD_MNE["2"])
    }
    if (_cnt1 != -1) {
        _enable(MCCD_MNE["1"])
    }
    mccdon; mccdbin 4; sleep(1);mccdwait
}
'

def mccddisable ' _mccddisable();'
def _mccddisable ()'{
    local _cnt1 _cnt2
    _cnt1 = cnt_num(MCCD_MNE["1"])
    _cnt2 = cnt_num(MCCD_MNE["2"])

    if (MCCD_NORM==1 && _cnt2!=-1) {
        _disable(MCCD_MNE["2"])
    }
    if (_cnt1 != -1) {
        _disable(MCCD_MNE["1"])
    }
    mccdoff; mccdbin 1; sleep(1);mccdwait
}
'

#%UU% [<dir> <prefix> <suffix> <run-number>]
#%MDESC% Sets a new file prefix and initialises the run number
def mccdnewfile '{
    local retry

    if ((whatis("MCCD_FILEPAR")&0x08000000)) {
        MCCD_FILEPAR["dir"]=  "/tmp"
        MCCD_FILEPAR["prefix"] = "test_"
        MCCD_FILEPAR["suffix"] = ".mccd"
        MCCD_FILEPAR["inum"] = "0"
    }  
    if ($#==4) {
        MCCD_FILEPAR["dir"]=  "$1"
        MCCD_FILEPAR["prefix"] = "$2"
        MCCD_FILEPAR["suffix"] = "$3"
        MCCD_FILEPAR["inum"] = "$4"
    } else {  
        retry=1
        while (retry) {
            MCCD_FILEPAR["dir"]=  getval("Data Directory:", MCCD_FILEPAR["dir"])
            if (!file_info(MCCD_FILEPAR["dir"],"-e")) {
                printf ("This directory doesn\'t exit, retry !\n")
                retry=1
            } else if (!file_info(MCCD_FILEPAR["dir"],"isdir")) {
                printf ("This is not a directory, retry !\n")
                retry=1
            } else if (!file_info(MCCD_FILEPAR["dir"],"-w")) {
                printf ("This is directory is not writable, retry !\n")
                retry=1
            } else {
                retry=0
            }
        }
        MCCD_FILEPAR["prefix"] = getval("File prefix:", MCCD_FILEPAR["prefix"])
        MCCD_FILEPAR["suffix"] = getval("File suffix:", MCCD_FILEPAR["suffix"])
        MCCD_FILEPAR["inum"] = getval("image number:", MCCD_FILEPAR["inum"])
    } 
}
'

def mccd_online '{
    global MCCD_DIS_PID
    if (\!(MCCD_DIS_PID && file_info(MCCD_DIS_PID,"alive"))) {
        MCCD_DIS_PID =  mccd_display()
    }
}
'

#%IU% ()
#%MDESC% Starts the online display and returns its pid.
def mccd_display () '{
    local pid file guicmd arrayname
    file = sprintf("/tmp/disgui_%s_%s.pid",USER,SPEC)
    arrayname="mccd_image_data"
    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 \$! > %s",guicmd,file))
    pid = getline(file)
    getline(file,"close")  
    return (pid)
}
'

#%UU% corrected
#%MDESC% Dumps the last image and to the local array "mccd_image_data" is 1 is
def mccd_getimage '{
    if (MCCD_SERVERMODE==1) {
        mccdwait
        # There is no MAR_WRITE substate updated by the marccd appli.
        # We need this work-around: sleep a bit before sending a new write command !
        # mccdstop set a flag to know if the file writing has been started
        if (MCCD_STOP_WITH_FILE) {
            sleep(2)
            MCCD_STOP_WITH_FILE = 0
        }
    }
    esrf_io(MCCD_DEVICE,"DevCcdRead", $1, mccd_image_data)

    # Touch the shared memory to indicate a refresh.
    mccd_image_data[0] = mccd_image_data[0]

    if (MCCD_SWAP) {
        array_op("swap", mccd_image_data)
    }
}
'

#%UU% 
#%MDESC% Print the integrated pixel values result
# passed the corrected image is get otherwise the raw image.
def mccd_int '{
    printf("Integrale value of the MarCCD image (%dX%d) is %.4f\n",\
        array_op("cols",mccd_image_data), \
        array_op("rows",mccd_image_data), mccd_int_f())

}
'

#%IU%
#%MDESC%
def mccd_int_f () '{
    local _scale
    _scale= array_op("cols",mccd_image_data)*array_op("rows",mccd_image_data)
    return array_op("sum", mccd_image_data) - MCCD_DARK_LEVEL*_scale
}
'

#%UU% 
#%MDESC% Print the standard deviation pixel values result
def mccd_std '{
    printf("Standard deviation of the MarCCD image (%dX%d) is %.4f\n",\
        array_op("cols",mccd_image_data), \
        array_op("rows",mccd_image_data), mccd_std_f())
}
'

def mccd_std_f () '{
    local _scale _avg _std

    _scale= array_op("cols",mccd_image_data)*array_op("rows",mccd_image_data)
    _avg=array_op("sum", mccd_image_data)/_scale
    _std=sqrt(array_op("sumsq",mccd_image_data - _avg )/_scale)
    return _std
}
'

#%IU%
#%MDESC%
def _mccdacq '{
    if (MCCD_SERVERMODE==1)  {
        if (MCCD_AUTOSAV==0 || MCCD_FILEPAR["suffix"]==".edf") { 
            MCCD_FILENAME=""
        } else {
            mccd_genfilename()
        }
    }

    mccdread

    if (MCCD_SERVERMODE==0 || (MCCD_SERVERMODE==1 && MCCD_FILEPAR["suffix"]==".edf"))  {
        mccdwait; sleep(1)
        if (MCCD_AUTOSAV) {
            mccdsave
        }
    }
}
'

#%UU%
#%MDESC% The camera will be started automatically at every scan point. 
#
def mccdon '{
    MCCD_ON=1
    cdef ("user_prepcount", "mccdstart;","__mccd__")
    cdef ("user_getcounts", "_mccdacq\n","__mccd__",0x10)
    user_mccdon
}
'

#%UU%
#%MDESC% The camera will not longer be started at every scan point.
#
def mccdoff '{
    user_mccdoff
    MCCD_ON=0
    cdef("","","__mccd__","delete")
}
'

#%UU%  
#%MDESC%  Saves the image to disk (remote) if CCD_FILENAME is not empty.
def mccdsave '{
    mccd_genfilename()
    mccdsave2
}
'

def mccd_genfilename() '{
    MCCD_FILENAME = mccdfilename(MCCD_FILEPAR["dir"], MCCD_FILEPAR["prefix"], \
        MCCD_FILEPAR["inum"], MCCD_FILEPAR["suffix"])
    MCCD_FILEPAR["inum"]++
}
'


#%UU%
#%MDESC% special save macro, uses default parameters stored into MCCD_FILENAME
# and MCCD_HEADER
def mccdsave2 '{
    if (MCCD_FILENAME != "") {
        mccdwait
        if (MCCD_FILEPAR["suffix"]==".edf") {
            user_mccd_header
            fmt_write(MCCD_FILENAME,"ESRF",mccd_image_data,MCCD_HEADER)
            notice (sprintf("Image Saved to File \"%s\"", MCCD_FILENAME))   
        } else {
            mccdsave_f (MCCD_FILENAME,MCCD_HEADER)
        }
    }
}
'


#%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 mccdfilename (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%d",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% read the state and update state and previous-state globals
def _mccd_state() '{
    local state
    state = esrf_io (MCCD_DEVICE,"DevState")
    MCCD_STATE = state
}
'

#%UU%
#%MDESC% For slow mode: waits until the Mar reaches IDLE state (1) or INTEGRATING state (2).
# A state ==3 indicates an error and the macro will just return back. %BR%
# For fast mode: waits until reading, correction and writing tasks are idle.
def mccdwait '{

    if ( MCCD_SERVERMODE == 1) {
        notice ("CCD clearing ...")
        if (esrf_io(MCCD_DEVICE,"DevSubState", MAR_ACQUIRE)!=MAR_IDLE) {
            notice ("CCD Integrating...")
        }
        if (esrf_io(MCCD_DEVICE,"DevSubState",MAR_READ)!=MAR_IDLE) {
            notice( "CCD Reading out...")
            marwait(MAR_READ,    MAR_IDLE)
            notice( "CCD Reading done.")
        }
        if (esrf_io(MCCD_DEVICE,"DevSubState",MAR_CORRECT)!=MAR_IDLE) {
            notice( "CCD Correcting...")
            marwait(MAR_CORRECT,    MAR_IDLE)
            notice( "CCD Correction done.")
        }
        # That statement is no longer needed, the marccd appli. does not
        # manage the writing state (it supposes it is so fast !!)
        # But I keep it for logical reason, L.Claustre 28/03/2007
        if (esrf_io(MCCD_DEVICE,"DevSubState",MAR_WRITE)!=MAR_IDLE) {
            notice( "CCD writing file ...")
            marwait(MAR_WRITE,    MAR_IDLE)
            notice( "CCD Correction done.")
        }
    } else {
        _mccdwait(1);
    }
}
'

#%IU%
#%MDESC% wait function to be use in slow-mode ONLY (MCCD_SERVERMODE==0)
def _mccdwait(stat)  '{

    local  ESRF_ERR t 


    _mccd_state()
    if (MCCD_STATE == 1) notice ("CCD clearing ...")
    if (MCCD_STATE == 2) notice ("CCD integrating ...")
    if (MCCD_STATE == 7) notice ("CCD readout...")
    if (MCCD_STATE == 8) notice ("CCD correction...")
    if (MCCD_STATE == 4) notice ("Saving image file...")
    if (MCCD_STATE == 10) notice ("CCD abort...")

    if (MCCD_STATE == 11) notice ("Please enable CCD remote control (see \"Acquire\" menu).")
    if (MCCD_STATE == 3) notice ("CCD error (state = 3), directory not found or not writable?")
    if (MCCD_STATE == 9) notice ("CCD busy...")

    while ( stat != MCCD_STATE && MCCD_STATE != 3)
    {
        if (escape) break

        if (MCCD_STATE == 1) notice ("CCD clearing ...")
        if (MCCD_STATE == 2) notice ("CCD integrating ...")
        if (MCCD_STATE == 7) notice ("CCD readout...")
        if (MCCD_STATE == 8) notice ("CCD correction...")
        if (MCCD_STATE == 4) notice ("CCD saving image file...")
        if (MCCD_STATE == 10) notice ("CCD abort...")

        if (MCCD_STATE == 11) notice ("Please enable CCD remote control (see \"Acquire\" menu).")
        if (MCCD_STATE == 3) notice ("CCD error (state = 3), directory not found or not writable?")
        if (MCCD_STATE == 9) notice ("CCD busy...")
        #not so urgent !!!
        sleep(0.05)
        _mccd_state()
    }
}
'

#%IU% (task,status)
#%MDESC% wait until the substate "task" has reached the state "status"
def marwait ( task, done ) '{
    while( _marwait(task,done)) {
        sleep(0.05)
    }
}
'

#%IU% (task,status)
#%MDESC% return 0 if the "task" substate is equal to "status"
# otherwise return 1.
def _marwait(task,status) '{
    ret = 1
    taskstate = esrf_io(MCCD_DEVICE,"DevSubState",task)
    if (taskstate == status) {
        ret = 0
    }
    return ret
}
'


#%UU% [binning]
#MDESC% Sets the binning for the Mar detector.
def mccdbin '{
    local outp inp

    mccdwait 
    esrf_io (MCCD_DEVICE,"DevCcdGetBin",outp)

    if ($#) {
        inp[0] = $1
        inp[1] = inp[0]
    } else {
        inp[0] = getval("Binning value ",   outp[0])
        inp[1] = inp[0]
    }
    if (inp[0]!=outp[1]) {
        esrf_io (MCCD_DEVICE,"DevCcdSetBin",inp)
        mccdwait
        notice ("Need to take a new background image now !!")
        mccdtake_bkg
        mccd_createarray
    }
}
'

#%UU% [use_roi] [xmin xmax ymin ymax]
#%MDESC% Defines a new region of interest for the camera. 
def mccdroi '{
    local xsize ysize xstart xend ystart yend roi_active
    local mccd_roi[]

    if ($1 && $#==5) {
        roi_active = $1
        rbeg = $2 ; rend = $3 ; cbeg = $4 ; cend = $5
    } else if ($# && !$1) {
        roi_active=0
    }
    else {
        if (!$#) {
            roi_active = yesno ("Use a Region of interest (ROI)",1)
        } else {
            roi_active = $1
        }
        if (roi_active) {
            esrf_io(MCCD_DEVICE,"DevCcdGetRoI",mccd_roi)
            cbeg = getval("ROI: from column (X)",\
                mccd_roi[0])
            cend = getval("ROI: to   column (X)",\
                mccd_roi[2])      
            rbeg = getval("ROI: from row (Y)",\
                mccd_roi[1])
            rend = getval("ROI: to   row (Y)",\
                mccd_roi[3])
        }
    }
    if (roi_active) {
        mccd_roi[0]=cbeg; mccd_roi[1]=rbeg; mccd_roi[2]=cend; mccd_roi[3]=rend
    } else {
        xsize = esrf_io(MCCD_DEVICE,"DevCcdXSize",0)
        ysize = esrf_io(MCCD_DEVICE,"DevCcdYSize",0)
        mccd_roi[0]=0; mccd_roi[1]=0; mccd_roi[2]=xsize-1; mccd_roi[3]=ysize-1
    }
    esrf_io(MCCD_DEVICE,"DevCcdSetRoI",mccd_roi)
    MCCD_ROI=roi_active
    mccd_createarray
}
'

def mccd_createarray '{
    local oldx oldy xsize ysize
    local mccd_roi[]

    esrf_io(MCCD_DEVICE,"DevCcdGetRoI",mccd_roi)
    xsize=mccd_roi[2]-mccd_roi[0]+1
    ysize=mccd_roi[3]-mccd_roi[1]+1
    if (whatis("mccd_image_data") & 0x4000000) {
        oldy = array_op("rows",mccd_image_data)
        oldx = array_op("cols",mccd_image_data)
    }
    if(oldx!=xsize ||oldy!=ysize) {
        shared ushort array mccd_image_data[ysize][xsize]
        notice ("Shared array created for mccd")
    }
}
'

#%UU%
#%MDESC% needed for compatibility with "oscillation.mac","laue.mac"
# - Schotte, 14 Feb 2000
def image_filename(name) '{
    if (!(whatis("name") & 0x08000000)) {
        global MCCD_FILENAME; MCCD_FILENAME = name
    }
    return MCCD_FILENAME
}
'


#%UU% filename
#%MDESC% writes the currently display "Detector" image of the "marCCD" application
# to the hard disk. If "filename" deos not start with a "/" it is save to
# the current working directory if SPEC.
def save_image '{
    local filename s
    filename = "$1"
    if (substr(filename,1,1) != "/") {
        filename = CWD"/"filename
    }
    if (file_info(filename)==0 || yesno("\"$1\" exists, overwrite?",0)) {
        mccdsave_f(filename)
    }
}
'


def mccdloop '{
    local marimgct
    marimgct = 0

    while(1) {
        marimgct++
        aaa = time()
        mccdtake 3
        if (MCCD_SERVERMODE == 0) {
            mccdsave
            print
            sleep(2)
            printf(" % 5d image saved ( time: %3.2f )\n", marimgct, time()-aaa-2)
        } else {
            printf(" % 5d image saved ( time: %3.2f )\n", marimgct, time()-aaa)
        }
    }
}
'


#%IU% %MDESC%
def gui_detmsg(message) '{
    print "mccd:gui_detmsg() "message
}
'

#%IU% %MDESC% print progress report message. %BR%
#%This macro might be redefined by the data colletion macro
def notice (message) '{
    if(SPECGUI) {
        gui_detmsg(message)
    } else { 
        tty_cntl ("ce") # clear to end of line
        tty_move (1000,1000,message) # print message starting from current position
        tty_move (-1000-length(message),1000) # move cursor back to starting position
    }
}
'

#%IU% used to implement a "soft interrupt" using ESC rather than Control-C
def escape 'check_escape()'

#%IU% used by "escape"
def check_escape() '{
    if (ESCAPE) {
        return 1
    }
    if (input(-1) == "\033") {
        global ESCAPE; ESCAPE = 1
    }
    if (ESCAPE) {
        local reset
        reset = "unglobal ESCAPE; cdef (\"\",\"\",\"escape\",\"delete\")\n"
        cdef ("prompt_mac",reset,"escape")
    }
    return ESCAPE
}
'

#%MACROS%
#%IMACROS%
#%AUTHOR% Andy Gotz, Michael Blum and Jorg Klora (V.0.01 20.10.97) %BR%
#Modified D. Bourgeois (20.10.97), Friedrich Schotte (Mar 2000) %BR%
#Last modified 10/2002 on ID09 to get MarCCD detector working L.Claustre %BR%
#Modified L.Claustre M.Blum (13/05/2003), new MarCCD and MarCCDds programmes %BR%
#Modified L.Claustre (17/06/2004) new server cmds + ROI + pseudo counters. %BR%