esrf

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

#%TITLE% xia2x.mac
#%NAME%
#   Macros to work with XIA-2X
#$Revision: 2.61 $
#%DESCRIPTION%
# Macros to handle XIA DXP electronics to control multi-element detectors
#%BR% This macro set can be used with two differents XIA models:
#%BR% * %B%DXP2X%B% boards: CAMAC boards controlled by a Jorway on SCSI
#%BR% * %B%XMAP%B% boards: PXI boards controlled by a NI MXI bus coupler
#%BR% A windows device server exists for these 2 boards: xiads (dxp2x boards) and xmapds (xmap boards)
#%SETUP%
#In SPEC, minimal setup needed is:
#%BR% %B%xiasetup%B% <taco_device_name>
#%BR% This setup macro need to be executed at each reconfig since it sets the taco TCP mode and timeout.
#%END%
#
#
#
#
#
#$Log: xia2x.mac,v $
#Revision 2.61  2018/02/06 13:53:43  guilloud
#added falconX
#+ debug messages
#
#Revision 2.60  2017/08/18 08:13:30  guilloud
#hg.mac dependency
#
#Revision 2.59  2017/03/09 15:45:21  guilloud
#fix path check
#
#Revision 2.58  2017/02/07 17:15:56  guilloud
#changed getval for check version to avoid bad filenames (cf RH oncall intervention)
#
#Revision 2.57  2017/02/06 15:09:30  berruyer
#Declare local variables when missing.
#
#Revision 2.56  2017/02/03 14:57:28  papillon
#* Implement HWSCA mode for mercury models
#
#Revision 2.55  2017/02/01 09:52:18  guilloud
#debug messages
#
#Revision 2.54  2016/11/23 16:28:58  guilloud
#*debug messages
#*_g2 counter usage fix for SPEC version >= 6.04
#
#Revision 2.53  2016/10/26 14:34:23  guilloud
#added debug functions
#xiaroiload and xiaroisave changed to have indexed lists
#
#Revision 2.52  2016/06/21 14:40:57  guilloud
#+test to reduce verbosity
#
#Revision 2.51  2015/11/04 12:22:42  guilloud
#xiaacq in GATE mode : if no time, use 1
#
#Revision 2.50  2015/06/04 14:18:06  guilloud
#new version of xiaroiload to list available files.
#
#Revision 2.49  2014/06/11 19:36:38  ahoms
#* Added missing t1 local variable in xiastart_wait (conflicting with motor)
#
#Revision 2.48  2014/06/02 14:56:39  papillon
#* add statistics reading when using map mode
#
#Revision 2.47  2013/02/20 12:30:49  guilloud
#*removed ESRF_ERR test (M.P. fix) in xiasetup
#*add tip in roi management questions
#
#Revision 2.46  2013/01/15 15:40:03  beteva
#check for error at setup and do not continue, if server not running
#
#Revision 2.45  2012/12/05 09:21:54  guilloud
#* added a macro to check validity of defined ROIs.
#
#Revision 2.44  2012/11/23 12:06:40  guilloud
#*Added 2 hookable cdef macros user_xia_on user_xia_off
#
#Revision 2.43  2012/10/25 08:39:28  guilloud
#*msg print change.
#*_xia_prepcount and _xia_getcounts called only if XIA_ON
#*2l of doc
#
#Revision 2.42  2011/11/04 10:25:33  guilloud
#*added xiaguion to be a little bit more coherent with multimca (but not totally?)
#
#Revision 2.41  2011/05/20 08:54:17  papillon
#* mercury model read from server
#* needs DS version >= 0.31
#
#Revision 2.39  2011/04/11 15:21:41  guilloud
#*DS version check
#*comments
#*colored _xia_print
#
#Revision 2.38  2010/07/29 08:59:34  papillon
#* Save files on scan abort
#
#Revision 2.37  2010/05/17 14:10:07  guilloud
#xiaroimenu :  changed default detector number from1 to 0.
#
#Revision 2.36  2010/01/12 17:00:59  guilloud
#bug
#
#Revision 2.35  2010/01/12 16:13:23  guilloud
#Add error message if loading of roi failed due to detector number.
#
#Revision 2.34  2009/12/23 14:28:56  guilloud
#* unglobal in unsetup.
#* some comments/indentation.
#* bug in _xia_getfilename in MODEMCA or MODEMAP.
#
#Revision 2.33  2009/11/25 16:16:46  papillon
#* add spectrum correction
#* option to save raw or corrected spectrums
#* roi headers also in xiaacq/ct files
#
#Revision 2.32  2009/07/16 14:15:45  guilloud
#*Add small message in setup.
#
#Revision 2.31  2009/07/16 12:58:14  guilloud
#*New roi managment.
#*More comments.
#*Polling to wait for end of saving before starting.
#*Test if bix/buffer is null to avoid crash of DS.
#*_xia_getfilename function.
#*SUM Roi.
#
#Revision 2.30  2009/04/27 07:41:33  guilloud
#XIA_SCADEF[0:isca-1]   ->  XIA_SCADEF[0:isca-1][:]    to prevent bug in case of single detector and single SCA.
#
#Revision 2.29  2008/03/13 14:21:46  guilloud
#*do not pass -display option to PyMca, it does not support it.
#
#Revision 2.28  2008/03/12 17:06:06  guilloud
#*move call to _xia_scan_abort from user_scan_abort to cleanup_once
#*add comments for LVT DT NORM correction
#
#Revision 2.27  2008/02/07 14:46:46  papillon
#* added user hook macros for edf header
#- user_xia_header (standard mode)
#- user_xia_map_header (mapping mode)
#
#Revision 2.26  2008/02/01 12:48:49  guilloud
#correction for parameter of xiaroiload and xiaroisave calls.
#
#Revision 2.25  2008/01/14 09:52:55  guilloud
#use _xia_print in xiaon/xiaoff messages
#
#Revision 2.23  2007/08/23 13:12:37  papillon
#* Fix errors in _xia_roitosca when we have multiple roi / detector
#
#Revision 2.22  2007/02/09 10:08:05  papillon
#* Better check roi limits
#* Added list of config files in xiaconfigure
#
#Revision 2.21  2006/11/20 17:03:17  papillon
#* Increment save number on scan abort
#
#Revision 2.20  2006/09/01 15:08:28  papillon
#* Correct xiamapstatus
#
#Revision 2.19  2006/08/03 10:33:54  papillon
#* bug in _xia_readstat
#
#Revision 2.18  2006/06/27 12:42:41  papillon
#* xiamapstatus added
#* xiaread can read any pixel in mca map mode
#* bidirect flag in file options for mca map mode
#
#Revision 2.17  2006/06/05 10:33:16  papillon
#* Support for MCAMAP mode on XMAP boards
#- set/getacqpar updated
#- newfile/savesetup updated
#* Change xiarange to use length in case of XMAP
#
#Revision 2.16  2006/03/10 14:13:15  papillon
#* Correct XIA_DATA_SAVE init for mesh
#
#Revision 2.15  2006/01/24 11:19:08  papillon
#* ROI headers in specfile
#* Save/Load for detector sums
#* Begin doc cleaning
#
#Revision 2.14  2005/10/20 15:26:11  papillon
#* Correct header in sum files
#* Add xiacntenable/xiacntdisable
#
#Revision 2.13  2005/09/21 12:54:49  pepellin
#Use clscreen()
#
#Revision 2.12  2005/09/01 09:22:14  papillon
#* Bug in _xia_savescanfile
#* SCAMAP mode works with xiaon/off
#* SCAMAP data saved in standard specfile
#
#Revision 2.11  2005/08/04 09:07:55  papillon
#* Average in sums as an option
#
#Revision 2.10  2005/08/02 11:28:00  papillon
#* Roi menu: correct average roi options
#* Edf header: xdata flag for data type
#* Dxp2x: fix wrong realtime in OCR
#
#Revision 2.9  2005/07/21 13:34:52  papillon
#* Bug in _xia_roitosca
#
#Revision 2.8  2005/07/19 14:24:19  papillon
#* Faster read stat for dxp2x
#* Saving / Plotting in user_handlecounts
#* Save detector sums
#* Saving works in mesh scans
#
#Revision 2.7  2005/07/07 17:09:18  papillon
#* Correct preset mode for xmap
#* Added detector sum as shared arrays
#
#Revision 2.6  2005/06/27 16:07:28  papillon
#* auto external gate for xmap
#
#Revision 2.5  2005/06/27 16:04:07  papillon
#* xia counter set on 2 digits
#* generic counter map to one detector or average
#
#Revision 2.4  2005/06/07 08:51:27  papillon
#* Correct LiveTime/RealTime in print/file for map mode
#* Avoid resetting hard scas on setpar if not needed
#
#Revision 2.3  2005/06/06 12:15:24  papillon
#* Force place in prepcounts, getcounts
#
#Revision 2.2  2005/05/13 14:48:09  papillon
#* Roi Saving/Loading to file
#* Spectrum saving in EDF format compatible with mca/zap
#
#Revision 2.1  2005/04/28 15:03:03  papillon
#* Add xiaclear for non auto-clear mode
#* Correct bug in _xia_test for new acquisition mode added
#* add board type XMAP
#
#Revision 2.0  2005/04/07 10:07:30  papillon
#Macros version works only with device server > 2.0
#* Upgrade set/get hard scas
#* Add support for scamap mode
#
#Revision 1.9  2004/10/25 14:02:47  papillon
#* Set acquisition test parameters in XIA_CONF
#
#Revision 1.8  2004/10/25 13:28:44  papillon
#* Improve configuration test acquisition
#* Add xiaguiopen/close for PyMca
#
#Revision 1.7  2004/04/21 07:50:00  papillon
#works with device server version 1.5 or greater
#* SCA acquisition mode added
#* BASELINE reading/plotting added
#* Set/Get DSP parameters improved
#
#Revision 1.5  2004/02/12 11:36:28  blissadm
#Add xiadspparam to update DSP parameter
#Bug corrected when only one detector is configured
#
#Revision 1.4  2004/02/10 11:29:35  papillon
#Small bug in _xia_test
#
#Revision 1.3  2004/02/10 11:02:24  papillon
#Added readout functions.
#Lineup macros used on id15.
#Add acquisition test after configure.
#


# needs spec_utils >= 1.58 for list_dir function.
# needs spec_utils >= 1.73 for getval_check()
need spec_utils

# needs hg for debug/error messages
need hg
hg_generate("xia")

global XIA_MSG[]
XIA_MSG["preset"][0]= "None"
XIA_MSG["preset"][1]= "RealTime"
XIA_MSG["preset"][2]= "LiveTime"
XIA_MSG["preset"][3]= "OutputCnts"
XIA_MSG["preset"][4]= "InputCnts"

XIA_MSG["type"][0]= "DXP4C"
XIA_MSG["type"][1]= "DXP2X"
XIA_MSG["type"][2]= "XMAP"
XIA_MSG["type"][3]= "MERCURY"
XIA_MSG["type"][4]= "FALCONX"

XIA_MSG["mode"][0]= "Unknown"
XIA_MSG["mode"][1]= "MCA"
XIA_MSG["mode"][2]= "SCA"
XIA_MSG["mode"][5]= "MCAMAP"
XIA_MSG["mode"][6]= "SCAMAP"
XIA_MSG["mode"][8]= "HWSCA"

XIA_MSG["gate"][0]= "NO"
XIA_MSG["gate"][1]= "YES"
XIA_MSG["gate"][2]= "AUTO"

XIA_MSG["hwsca"][0]= "Black #1"
XIA_MSG["hwsca"][1]= "Black #2"
XIA_MSG["hwsca"][2]= "Black #3"
XIA_MSG["hwsca"][3]= "Black #4"
XIA_MSG["hwsca"][4]= "Black #5"
XIA_MSG["hwsca"][5]= "Black #6"
XIA_MSG["hwsca"][6]= "Black #7"
XIA_MSG["hwsca"][7]= "Black #8"
XIA_MSG["hwsca"][8]= "Gray #1"
XIA_MSG["hwsca"][9]= "Gray #2"
XIA_MSG["hwsca"][10]= "Gray #3"
XIA_MSG["hwsca"][11]= "Gray #4"
XIA_MSG["hwsca"][12]= "Gray #5"
XIA_MSG["hwsca"][13]= "Gray #6"

global XIA_MODEMCA XIA_MODESCA XIA_MODEMAP XIA_MODEHWSCA
XIA_MODEMCA = 1
XIA_MODESCA = 2
XIA_MODEMAP = 4
XIA_MODEHWSCA = 8


global XIA_CONF[]
XIA_CONF["minocr"]  = 50
XIA_CONF["timeout"] = 15


#%UU% (<message>, <default>)
#%MDESC%
#    Prompts for a single letter until a unique one is entered.
def getval_one_char(message, default) '{
    local _entry

    _entry = getval(message, default)

    while (  (length(_entry) < 1) ||  (length(_entry) > 1) ){
        _entry = getval(message, default)
    }

    return (_entry)
}'



# -----------------------------------------------------------------------------
# SETUP
# -----------------------------------------------------------------------------

#%UU% <device_name>
#%MDESC% Global setup macro.  %BR%
# -<device_name> : Taco device server name.
def xiasetup '{
    global XIA_DEV    XIA_INIT     XIA_ON
    global XIA_GUI    XIA_GUIDPY   XIA_STATGUI
    global XIA_ROI[]  XIA_ROIVAL[] XIA_DETDISABLE[]
    global XIA_SAVE[] XIA_SUM[]    XIA_CORR[]
    global XIA_PAR[]
    global XIA_LINEUP
    global ESRF_ERR

    local _version _version_string _arr_tmp[]

    # Asks and sets the device server name.
    if ($#) {
        XIA_DEV= "$1"
    }
    else{
        XIA_DEV= getval("\nXIA device name", XIA_DEV)
    }

    _xia_print("Setup", sprintf("Taco DS name: \"%s\"", XIA_DEV), 0)

    # Switch DS to TCP mode
    if (esrf_io(XIA_DEV, "tcp")==-1) {
        _xia_print("Setup", "Failed to switch to TCP", 1)
        XIA_INIT= 0
    }
    else{
        _xia_print("Setup", "TCP mode set", 0)
    }

    if (!ESRF_ERR) {
      ESRF_ERR = -1
      # --- readout time is around 2.5 sec/13 elts
      if ( esrf_io(XIA_DEV, "timeout", 5) == -1 ) {
          _xia_print("Setup", "Failed to set timeout", 1)
          XIA_INIT= 0
      } else{
          _xia_print("Setup", "timeout set to 5s.", 0)
      }
    }

    if ((!ESRF_ERR)&&((!_xia_isinit())||(!XIA_INIT))) {
        xiainit
    }
    else {
        if (!ESRF_ERR) {
          _xia_print("Setup", "Device already initialized")
          if ((XIA_INIT=_xia_readpar())==0) {
            _xia_print("Setup", "Read device configuration FAILED", 1)
          }
        }
    }

    if (!ESRF_ERR) {
      #### DS version check.
      ESRF_ERR = -1
      _version_string = esrf_io(XIA_DEV, "DevXiaGetVersion")

      if (!ESRF_ERR){
        split(_version_string, _arr_tmp)
        _version = _arr_tmp[1]+0.0

        if ( _version >= 0.31 ){
            _xia_print("Setup", sprintf("DS version is %2.2f", _version), 0)
        }
        else{
            _xia_print("Setup", sprintf("DS version is %2.2f", _version), 2)
        }
      }
      else{
        _xia_print("Setup", "Unable to check version of the DS", 2)
      }
    }

    # to check SPEC version.
    # _g2 counter usage has changed since version 6.04
    # _g2 counter is used in _xia_savescandata
    split(VERSION, TTT, ".")
    if(TTT[0] >= 6 && TTT[1] >= 4){
        xia_dbg(sprintf("spec version >= 6.4 (%s)", VERSION))
        XIA_PAR["spec_v_sup_64"] = 1
    }
    else{
        xia_dbg(sprintf("spec version < 6.4 (%s)", VERSION))
        XIA_PAR["spec_v_sup_64"] = 0
    }

    # Removes xia stuff if unconfigured in setup.
    setup_tail("xia")
}'


#%IU%
#%MDESC% Unsetup XIA detector
#
def xiaunsetup '{
    XIA_INIT = 0
    xiaoff

    unglobal XIA_DEV    XIA_INIT    XIA_ON
    unglobal XIA_GUI    XIA_GUIDPY  XIA_STATGUI
    unglobal XIA_ROI    XIA_ROIVAL  XIA_DETDISABLE
    unglobal XIA_SAVE   XIA_SUM     XIA_CORR
    unglobal XIA_LINEUP
    unglobal XIA_PAR
}'


#%UU%
#%MDESC% Main menu which gives access to almost all needed functions
def xia '{
    local option nl str ich pause str

    option=1
    while (option) {
        nl=0
        clscreen()
        tty_move(20, nl++, "\[md\]< XIA MENU >\[me\]")
        tty_move(0,++nl, sprintf("Device: \[md\]%s\[me\]", XIA_DEV))
        tty_move(30,nl++, sprintf("BoardType: \[md\]%s\[me\]", XIA_MSG["type"][XIA_PAR["type"]]))
        tty_move(0,nl, sprintf("Nb Modules: \[md\]%d\[me\]", XIA_PAR["nbmod"]))
        tty_move(30,nl++, sprintf("Nb detectors: \[md\]%d\[me\]", XIA_PAR["nbdet"]))
        str= ""
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) str= str sprintf(" %d", XIA_DET[ich])
        tty_move(0,nl++, sprintf("Detectors: %s", str))
        str= ""
        nl+=2

        tty_move(0,nl++," 1- Acquisition setup.................:")
        tty_move(6,nl++,sprintf("- Acq. Mode       = \[md\]%s\[me\]", XIA_MSG["mode"][XIA_PAR["mode"]]))
        if (XIA_PAR["mode"]&XIA_MODEMAP) {
            if (XIA_PAR["type"]==1) {
                # --- DXP2X
                tty_move(6,nl++,sprintf("- Multimode       = \[md\]%s\[me\]", XIA_PAR["multimode"]?"YES":"NO"))
                tty_move(6,nl++,sprintf("- SinglePass      = \[md\]%s\[me\]", XIA_PAR["singlepass"]?"YES":"NO"))
                tty_move(6,nl++,sprintf("- NumberOfPoints  = \[md\]%d\[me\]", XIA_PAR["numpoints"]))
            }
            else if (XIA_PAR["type"]>=2) {
            # --- XMAP
                tty_move(6,nl++,sprintf("- PixelControl    = \[md\]%s\[me\]", \
                    XIA_PAR["pixctrl"]?sprintf("SYNC (%d pulses/pixel)", XIA_PAR["pixctrl"]):"GATE"))
                tty_move(6,nl++,sprintf("- NumberOfPixels  = \[md\]%d\[me\]", XIA_PAR["pixnb"]))
                tty_move(6,nl++,sprintf("- PixelsPerBuffer = \[md\]%s\[me\]", \
                    XIA_PAR["pixbuf"]==-1?"AUTO":sprintf("%d", XIA_PAR["pixbuf"])))
                tty_move(6,nl++,sprintf("- Spectrum Size   = \[md\]%d\[me\]", XIA_PAR["chlen"]))
            }
        } else if (XIA_PAR["mode"]==XIA_MODEHWSCA) {
            tty_move(6,nl++,sprintf("- Spectrum Size   = \[md\]%d\[me\]", XIA_PAR["chlen"]))
        } else {
            tty_move(6,nl++,sprintf("- External Gate   = \[md\]%s\[me\]", XIA_MSG["gate"][XIA_PAR["gate"]]))
            tty_move(6,nl++,sprintf("- Auto-Clear      = \[md\]%s\[me\]", XIA_PAR["clear"]?"YES":"NO"))
            tty_move(6,nl++,sprintf("- Preset Mode     = \[md\]%s\[me\]", XIA_MSG["preset"][XIA_PAR["preset"]]))
            if (XIA_PAR["type"]>=2) {
            # --- XMAP
            tty_move(6,nl++,sprintf("- Spectrum Size   = \[md\]%d\[me\]", XIA_PAR["chlen"]))
            } else {
            # --- DXP
            tty_move(6,nl++,sprintf("- Spectrum Range  = [ \[md\]%d\[me\] , \[md\]%d\[me\] ]", \
                    XIA_PAR["chmin"], XIA_PAR["chmax"]))
            }
        }

        tty_move(0,nl," 2- Configuration File................:")
        tty_move(40,nl++,sprintf("\[md\]%s\[me\]", XIA_PAR["dxp"]?XIA_PAR["dxp"]:"None"))
        nl++

        tty_move(0,nl," 3- XIA active on ct/scans............:")
        tty_move(40,nl++,sprintf("\[md\]%s\[me\]", XIA_ON?"YES":"NO"))
        nl++

        tty_move(0,nl," 4- ROIs definition...................:")
        if (list_n(XIA_ROI)<=0) str= "\[md\]None\[me\]"
        else str= sprintf("\[md\]%d\[me\]", list_n(XIA_ROI))
        tty_move(40,nl++, str)

        tty_move(0,nl," 5- Statistic Counters................:")
        if ((!XIA_PAR["cntset"])||(XIA_PAR["cntdet"]==-1)) str= "\[md\]Avg\[me\]"
        else str= sprintf("det#\[md\]%02d\[me\]", XIA_PAR["cntdet"])
        tty_move(40, nl++, str)

        tty_move(0,nl," 6- Detectors sum.....................:")
        if (list_n(XIA_SUM)<=0) str= "\[md\]None\[me\]"
        else str= sprintf("\[md\]%d\[me\]", list_n(XIA_SUM))
        tty_move(40, nl++, str)

        tty_move(0,nl," 7- Spectrum corrections......(SPEC)........:")
        str= ""
        if (XIA_CORR["lvt"]) str= str "LVT "
        if (XIA_CORR["dt"]) str= str "DT "
        if (XIA_CORR["mon"]) str= str "MON "
        if (XIA_CORR["save"]) str=str "Saved"
        if (!length(str)) str= "None"
        tty_move(40, nl++, sprintf("\[md\]%s\[me\]", str))
        nl++

        tty_move(0,nl++," 8- Saving options ...................:")
        if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
            tty_move(6,nl++,sprintf("- Autosave   = \[md\]%s\[me\]", XIA_SAVE["mapauto"]?"YES":"NO"))
            tty_move(6,nl++,sprintf("- Directory  = \[md\]%s\[me\]", XIA_SAVE["mapdir"]))
            tty_move(6,nl++,sprintf("- File radix = \[md\]%s\[me\]", XIA_SAVE["mapfile"]))
        } else {
            tty_move(6,nl++,sprintf("- Save during scans     = \[md\]%s\[me\]", XIA_SAVE["scan"]?"YES":"NO"))
            tty_move(6,nl++,sprintf("- Save after ct/xiaacq. = \[md\]%s\[me\]", XIA_SAVE["ct"]?"YES":"NO"))
            if (list_n(XIA_SUM)>0)
                tty_move(6,nl++,sprintf("- Save detector sum     = \[md\]%s\[me\]", XIA_SAVE["sum"]?"YES":"NO"))
            if (XIA_SAVE["scan"] || XIA_SAVE["ct"]) {
                tty_move(6,nl++,sprintf("- Directory  = \[md\]%s\[me\]", XIA_SAVE["dir"]))
                tty_move(6,nl++,sprintf("- File radix = \[md\]%s\[me\]", XIA_SAVE["radix"]))
            }
        }

        option= getval("\n\n\tOption ---> ", 0)
        printf("\n\n")

        pause= 1
        if (option==1) {
            xiaacqsetup
            if ((XIA_PAR["type"]<2)&&(XIA_PAR["mode"]&XIA_MODEMCA)) {
            print; xiarange
            }
        }
        else if (option==2) xiaconfigure
        else if (option==3) {
            if (XIA_ON) xiaoff
            else xiaon
            pause= 0
        }
        else if (option==4) { xiaroimenu; pause=0 }
        else if (option==5) { xiacntshow; xiacntassign; pause=0 }
        else if (option==6) { xiasummenu; pause=0 }
        else if (option==7) { xiacorrsetup }
        else if (option==8) { xiasavesetup }
        if (option&&pause) input("... Press Enter ...")
    }
}'

# -----------------------------------------------------------------------------
# HARDWARE INITIALISATION
# -----------------------------------------------------------------------------


#%UU%
#%MDESC% Initialize XIA hardware and read device parameters
#%BR% Used to reinitialize haardware with default firmwares/parameters
#
def xiainit '{
    XIA_INIT= _xia_init()

    if (XIA_INIT)
        XIA_INIT= _xia_readpar()
    if (!XIA_INIT)
        _xia_print("Init", "FAILED", 1)
    else    _xia_print("Init", "OK")
}'


#%IU% ()
#%MDESC% Initialize XIA hardware
#%BR% Return 1 on success, 0 otherwise
#
def _xia_init() '{
    ESRF_ERR=0
    _xia_print("Init", "hardware initialisation ...")

    if (esrf_io(XIA_DEV, "timeout", 50)==-1) {
        _xia_print("Init", "Cannot set timeout", 1)
        return (0)
    }

    if (esrf_io(XIA_DEV, "DevXiaInit")==-1) {
        _xia_print("Init", "Hardware initialisation FAILED", 1)
        return (0)
    }

    if (esrf_io(XIA_DEV, "timeout", 5)==-1) {
        _xia_print("WARNING", "Cannot set back timeout. Now is 50.", 1)
    }

    if (_xia_isinit()){
        return (1)
    }
    else{
        return (0)
    }
}'


#%IU% ()
#%MDESC% Return 1 if XIA hardware already initialized, 0 otherwise
#
def _xia_isinit() '{
    local state
    state= esrf_io(XIA_DEV, "DevState")
    if ((state==2)||(state==14)) return (1)
    else return (0)
}'

# -----------------------------------------------------------------------------
# READING DEVICE PARAMETERS
# -----------------------------------------------------------------------------

#%IU%
#%MDESC% Read xia parameters from device server
#%BR% Usefull when xiaconfigure ends with a timeout
#
def xiaupdate '{
    if (esrf_io(XIA_DEV, "tcp")==-1){
        _xia_print("Setup", "Failed to switch to TCP", 1)
    }

    _xia_print("XiaUpdate", "Updating parameters ...")

    if (!_xia_readpar()){
        _xia_print("XiaUpdate", "FAILED", 1)
    }
    else{
        _xia_print("XiaUpdate", "OK", 0)
    }
}'


#%IU% ()
#%MDESC% Read XIA channels and acquisition parameters
#%BR% Store parameters in ass. array %B%XIA_PAR%B%
#%BR% Store detector numbers in array %B%XIA_DET%B%
#
def _xia_readpar() '{
    global XIA_PAR[]
    if (!_xia_readchanpar()) return (0)
    if (!_xia_readacqpar(XIA_PAR["mode"])) return (0)
    if (!_xia_readconfig()) return (0)
    return (1)
}'


#%IU% ()
#%MDESC% Read acquisition parameters
#
def _xia_readacqpar(prevmode) '{
    local short array XIA_ACQPAR[4]

    if (esrf_io(XIA_DEV, "DevXiaGetAcqPar", XIA_ACQPAR)==-1) {
        _xia_print("ReadPar", "Cannot get acquisition parameters", 1)
        return (0)
    }

    xia_dbg(sprintf("_xia_readacqpar : %s %s %s %s", XIA_ACQPAR[0], XIA_ACQPAR[1], XIA_ACQPAR[2], XIA_ACQPAR[3]))

    XIA_PAR["mode"]= XIA_ACQPAR[0]
    if ((prevmode==XIA_MODEHWSCA)&&(XIA_PAR["mode"]==XIA_MODEMCA)) {
        XIA_PAR["mode"]= XIA_MODEHWSCA
    }

    if (XIA_PAR["mode"]&XIA_MODEMAP) {
        if (XIA_PAR["type"]>=2) {
        # --- XMAP
        XIA_PAR["pixctrl"] = XIA_ACQPAR[1]
        XIA_PAR["pixnb"]   = XIA_ACQPAR[2]
        XIA_PAR["pixbuf"]  = XIA_ACQPAR[3]
        }
        else {
        # --- DXP
        XIA_PAR["multimode"]  = XIA_ACQPAR[1]
        XIA_PAR["singlepass"] = XIA_ACQPAR[2]
        XIA_PAR["numpoints"]  = XIA_ACQPAR[3]
        }
    } else {
        XIA_PAR["gate"]= XIA_ACQPAR[1]
        XIA_PAR["clear"]= XIA_ACQPAR[2]
        XIA_PAR["preset"]= XIA_ACQPAR[3]
    }
    return (1)
}'


#%IU% ()
#%MDESC% Read last DSP configuration file
#
def _xia_readconfig() '{
    if ((XIA_PAR["dxp"]=esrf_io(XIA_DEV, "DevXiaGetConfig"))==-1) {
        _xia_print("ReadPar", "Cannot get last dxp config filename", 1)
        return (0)
    }
    return (1)
}'


#%IU% ()
#%MDESC% Read channel definition
#
def _xia_readchanpar() '{
    local long array XIA_CHANPAR[7]

    if (esrf_io(XIA_DEV, "DevXiaGetChanPar", XIA_CHANPAR)==-1) {
        _xia_print("ReadChanPar", "Cannot get channels parameters", 1)
        return (0)
    }

    XIA_PAR["type"]= XIA_CHANPAR[0]
    XIA_PAR["nbmod"]= XIA_CHANPAR[1]
    XIA_PAR["nbdet"]= XIA_CHANPAR[2]
    XIA_PAR["chlen"]= XIA_CHANPAR[3]
    XIA_PAR["chmin"]= XIA_CHANPAR[4]
    XIA_PAR["chmax"]= XIA_CHANPAR[5]
    XIA_PAR["baselen"]= XIA_CHANPAR[6]

    if (XIA_PAR["nbdet"]) {

        # Checks validity of defined ROIs.
        _xia_check_ROIs()

        if (XIA_PAR["nbdet"]==1){
            shared short array XIA_DET[2]
        }
        else{
            shared short array XIA_DET[XIA_PAR["nbdet"]]
        }

        if (esrf_io(XIA_DEV, "DevXiaGetChanDef", XIA_DET)==-1) {
            _xia_print("ReadChanPar", "Cannot get detectors definition", 1)
            return (0)
        }
    }
    else{
        print "zero det ??"
    }

    if (!_xia_createarrays()) {
        _xia_print("ReadChanPar", "Cannot create shared data array", 1)
        return (0)
    }

    return (1)
}'


#%IU% ()
#%MDESC% Creates shared arrays
#%BR% %B%XIA_DATA%B% = spectrum for all detectors
#%BR% %B%XIA_STAT%B% = run statistics for all detectors (nevt, icr, ocr, lvt)
#%BR% %B%XIA_SUMDATA%B% = sum of spectrums if defined
#
def _xia_createarrays() '{
    if (!XIA_PAR["nbdet"])    return (0)

    shared ulong array XIA_DATA[XIA_PAR["nbdet"]+1][XIA_PAR["chlen"]]
    shared long array XIA_STAT[XIA_PAR["nbdet"]+1][6]

    array_op("fill", XIA_DATA[0][])
    if (XIA_PAR["chmin"]) XIA_DATA[0][]+= XIA_PAR["chmin"]

    _xia_corrcreatearray

    _xia_sumcreatearray
    if (XIA_LINEUP) _xia_lineupcreatearray
    return (1)
}'

# -----------------------------------------------------------------------------
# ACQUISITION MODE
# -----------------------------------------------------------------------------


#%IU% ()
#%MDESC%
#    Checks that defined XIA ROIs are valid (defined on an existing
# detector)
def _xia_check_ROIs() '{
    local ii _roi_name _det_number _sca_nb

    for (ii=0 ; ii < list_n(XIA_ROI) ; ii++){

        _roi_name   = XIA_ROI[ii]
        _det_number = XIA_ROI[_roi_name]["det"]
        _sca_nb     = XIA_ROI[_roi_name]["sca"]

        if (_det_number >= XIA_PAR["nbdet"]){
            print "ERROR : a XIA ROI is defined on a detector not configured:"
            printf("  roi \"%s\" (number %d) (SCA nb %d) on detector #%d.\n", \
                   _roi_name, ii, _sca_nb, _det_number)

            if (!XIA_PAR["dont_ask_remove_ROI"]){
                # (Was too verbose for ID16b...)
                if (yesno("Do you want to remove it (in both STEP and ZAP modes) ?", 1)){
                    _xia_roiremove(_roi_name)
                }
            }
        }
    }
}'


#%IU% ()
#%MDESC% Configures all defined ROIs as hard SCAs
#%BR% Returns 1 on success, 0 otherwise
#
def _xia_roitosca() '{
    local nroi iroi nsca isca idet ich corr name

    _xia_print("Sca", "Configure SCA", 0)

    if ((nroi=list_n(XIA_ROI))<0){
        list_init XIA_ROI
    }

    # 
    short array XIA_SCADET[XIA_PAR["nbdet"]]
    XIA_SCADET= 0

    if (!nroi) {
        nsca= 0
        if (esrf_io(XIA_DEV, "DevXiaResetScas")==-1) {
            _xia_print("Sca", "Cannot reset SCAs", 1)
            return (0)
        }
    }
    else {
        global long array XIA_SCADEF[nroi][4]
        # { {detnum, min, max, corr }, ...}

        isca= 0

        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            idet= XIA_DET[ich]
            for (iroi=1; iroi<=nroi; iroi++) {
                if (list_getpar(XIA_ROI,iroi,"det")==idet) {
                    name= list_item(XIA_ROI, iroi)
                    XIA_SCADEF[isca][0]= idet
                    XIA_SCADEF[isca][1]= XIA_ROI[name]["min"]
                    XIA_SCADEF[isca][2]= XIA_ROI[name]["max"]
                    corr= 0
                    if (XIA_ROI[name]["dt"]==1) {
                        corr |= 1
                    }
                    if (XIA_ROI[name]["lvt"]==1) {
                        corr |= 2
                    }
                    XIA_SCADEF[isca][3]= corr

                    list_setpar(XIA_ROI, iroi, "sca", isca)
                    XIA_SCADET[ich]++
                    isca++
                }
            }
        }

        esrf_io(XIA_DEV, "timeout", 5+nroi)

        # [:] is to force to pass an array even if there is only one SCA.
        if ((nsca= esrf_io(XIA_DEV, "DevXiaSetScas", XIA_SCADEF[0:isca-1][:]))==-1) {
            _xia_print("Sca", "Failed to set SCAs", 1)
            return (0)
        }

        esrf_io(XIA_DEV, "timeout", 5)

        if (nsca!=isca) {
            _xia_print("WARNING", "Number of SCAs <> Number of ROIs", 1)
        }
    }

    XIA_PAR["nbsca"]= nsca

    if (nsca) {
        _xia_scaarray()
    }

    return (1)
}'


#%IU% [parma]
#%MDESC%
#    Allocates arrays for SCAS.
#    Here is the source of the message :
# "Must have have at least one row for array "XIA_SCAS".
# This function is called:
#  -after a roi definition.
#  -at zap initialization.
def _xia_scaarray() '{
    local scalen

    # _xia_print("_xia_scaarray()", "allocate XIA_SCAS array")

    if (XIA_PAR["mode"]&XIA_MODEMAP) {

        if (XIA_PAR["mode"]&XIA_MODESCA) {
            scalen= XIA_PAR["numpoints"]*((XIA_PAR["nbdet"]*4) + XIA_PAR["nbsca"])
            ulong array XIA_SCAS[scalen]
        } else {
            # scalen not used ???
            scalen= XIA_PAR["pixnb"] * XIA_PAR["nbsca"]

            if (XIA_PAR["pixnb"]==0){
                # why 10 ? why not ? why not 1? should it be mandatory initialized ?
                ulong array XIA_SCAS[10][XIA_PAR["nbsca"]]
            }
            else{
                ulong array XIA_SCAS[XIA_PAR["pixnb"]][XIA_PAR["nbsca"]]
            }
        }
    }
    return (1)
}'



# apres 
# 651.CYRIL> p XIA_PAR
# XIA_PAR["baselen"] = 1024
# XIA_PAR["chlen"] = 2048
# XIA_PAR["chmax"] = 2047
# XIA_PAR["chmin"] = 0
# XIA_PAR["clear"] = 1
# XIA_PAR["dxp"] = "xmap.ini"
# XIA_PAR["gate"] = 0
# XIA_PAR["mode"] = 5
# XIA_PAR["nbdet"] = 1
# XIA_PAR["nbmod"] = 1
# XIA_PAR["nbsca"] = 1
# XIA_PAR["pixbuf"] = 12
# XIA_PAR["pixctrl"] = 0
# XIA_PAR["pixnb"] = 41
# XIA_PAR["preset"] = 0
# XIA_PAR["type"] = 2



# -----------------------------------------------------------------------------
# DSP CONFIGURATION FILE
# -----------------------------------------------------------------------------

#%UU%
#%MDESC% Load a DSP configuration file
#%BR%For DXP2X boards: file created with MESA (*.sav)
#%BR%For XMAP boards: file created with xManager
#
def xiaconfigure '{
    local cfg nb icfg cfglist[]
    if ($# != 1) {
        nb= esrf_io(XIA_DEV, "DevXiaGetConfigList", cfglist)
        if (nb>0) {
            print "List of configuration files found:"
            for (icfg=0; icfg<nb; icfg++)
                print cfglist[icfg]
            print
        }
        cfg= XIA_PAR["dxp"]=="NONE"?0:XIA_PAR["dxp"]
        if (XIA_PAR["type"]==2) {
                cfg= getval("xManager configuration file", cfg)
        } else if (XIA_PAR["type"]==3) {
            cfg= getval("ProSpect configuration file", cfg)
        } else {
            cfg= getval("Mesa DSP configuration file", cfg)
        }
        print
    }
    else {
        cfg= "$1"
    }
    if (cfg) {
        if (_xia_setconfig(cfg)) {
            if (XIA_PAR["type"]<2) _xia_test
        }
    }
}'


#%IU% [<ocr_min>] [<timeout>]
#%MDESC% Test acquisition done after configure
#
def _xia_test '{
    local gate clear preset
    local tt ii st ocr tps

    ocr= ($#>=1)?int($1):XIA_CONF["minocr"]
    tps= ($#>=2)?$2:XIA_CONF["timeout"]

    gate= XIA_PAR["gate"]
    clear= XIA_PAR["clear"]
    preset= XIA_PAR["preset"]

    if (gate!=0 || clear!=1 || preset!=0) {
        _xia_print("Test", "Setting no gate, auto-clear, no preset", 0)
        _xia_setacqpar(XIA_MODEMCA, 0, 1, 0)
    }

    _xia_print("Test", "Acquisition Test ...")
    tt= time()
    xiastart

    st= 1
    while (st>0) {
        sleep(.5)
        printf("Time= %.1f sec\r", time()-tt)
        _xia_readstat(0)
        st= 0
        for (ii=0; ii<XIA_PAR["nbdet"]; ii++)
            st += (XIA_STAT[ii][3]<ocr)
        if (time()-tt>tps) st= -1
    }
    xiastop
    xiatimes
    if (st==-1) {
        _xia_print("Test", sprintf("OCR still lower than %d after %.1f seconds", ocr, time()-tt), 1)
        _xia_print("Test", "Acquisition test FAILED", 1)
    }
    else    _xia_print("Test", "finished.")
    xiastatus

    if (gate!=XIA_PAR["gate"] || clear!=XIA_PAR["clear"] || preset!=XIA_PAR["preset"]) {
        _xia_setacqpar(XIA_MODEMCA, gate, clear, preset)
        _xia_print("Test", "Resetting original gate/clear/preset mode")
    }
}'


#%IU%
#%MDESC% Download DSP configuration file
#%BR% Return 1 on success, 0 otherwise
#    Called by xiaconfigure.
def _xia_setconfig(cfg) '{
    ESRF_ERR=0
    _xia_print("ReadConfig", sprintf("Downloading %s", cfg), 0)

    if (esrf_io(XIA_DEV, "timeout", 80)==-1) {
        _xia_print("ReadConfig", "Cannot set timeout", 1)
        return (0)
    }
    _xia_print("ReadConfig", "Please wait ...", 0)

    if (esrf_io(XIA_DEV, "DevXiaSetConfig", cfg)==-1) {
        _xia_print("ReadConfig", "FAILED", 1)
        return (0)
    }
    if (esrf_io(XIA_DEV, "timeout", 5)==-1) {
        _xia_print("WARNING", "Cannot set back timeout. Now is 30.", 1)
    }
    _xia_print("ReadConfig", "OK", 0)
    _xia_print("ReadConfig", "Updating parameters ...", 0)
    if (!_xia_readpar()) {
        _xia_print("ReadConfig", "Reading parameters FAILED", 1)
        return (0)
    }
    _xia_print("ReadConfig", "OK", 0)
  
    if (XIA_PAR["type"]==3) {
        _xia_roitosca()
    }
    return (1)
}'

# -----------------------------------------------------------------------------
# READING DATA
# -----------------------------------------------------------------------------

#%IU% [<pixel_number>]
#%MDESC%
# Read spectrum, run statistics, computes or read ROIs, computes SUMs
#%BR% Update shared arrays and counters
#%BR% In MCAMAP mode:
#%BR% if <pixel_number> is specified, read spectrum, sums, stats for that pixel
#%BR% otherwise, read the last pixel available in device server buffer
#
def xiaread '{
    local _nb_param pix
    _nb_param = $#

    if (XIA_PAR["mode"]&XIA_MODEMAP) {
        if (XIA_PAR["mode"]&XIA_MODEMCA) {
            pix= (_nb_param == 1) ? int($1) : -1
            _xia_readdata(pix)
            _xia_readstat(pix)
            _xia_corrdata
            _xia_readsum
        }
        else {
            _xia_readscas(0)
        }
    }
    else {
        if (XIA_PAR["mode"]&XIA_MODESCA){
            _xia_readscas(0)
        }
        else{
            _xia_readdata(0)
        }

        if ((XIA_PAR["type"]==1)&&(XIA_PAR["mode"]&XIA_MODEMCA)){
            _xia_readstat(1)
        }
        else{
            _xia_readstat(0)
        }

        _xia_corrdata
        _xia_readcnts
        _xia_readrois
        _xia_readsum
    }
}'


#%IU%
#%MDESC% Start readout thread on server
#
def _xia_readout '{
    if (esrf_io(XIA_DEV, "DevXiaReadout")==-1) {
        _xia_print("Readout", "Start readout failed.", 1)
    }
}'


#%IU% ()
#%MDESC% Wait until readout is finished
#%BR% Return 1 if readout finished successfully
#%BR% Return 0 if readout finished with errors
#
def _xia_readoutwait() '{
    local state
    while (state!=43) {
        if ((state= esrf_io(XIA_DEV, "DevXiaReadoutState"))==-1) {
            _xia_print("WaitReadout", "FAILED,", 1)
            return(0)
        }
        sleep(.1)
    }
        return (1)
}'


#%IU% (<frombuffer>)
#%MDESC% Read spectrum
#%BR% if <frombuffer> is set to 1,
# get spectrums from server buffer: no readout performed.
#
def _xia_readdata(frombuffer) '{
    if (esrf_io(XIA_DEV, "DevXiaReadData", frombuffer, XIA_DATA[1:XIA_PAR["nbdet"]])==-1) {
        _xia_print("ReadData", "Failed to read spectrums", 1)
    }
    # --- to set shared array updated flag
    XIA_DATA[0][0]= XIA_DATA[0][0]
}'


#%IU% (<frombuffer>)
#%MDESC% Read SCAs
#%BR% if <frombuffer> is set to 1,
# get SCAs from server buffer: no readout performed.
#
def _xia_readscas(frombuffer) '{
    if (XIA_PAR["mode"]&XIA_MODEMAP) {
        local frompt
        frompt= (frombuffer<0) ? 0 : frombuffer
        if (esrf_io(XIA_DEV, "DevXiaReadScas", frompt, XIA_SCAS[frompt:][:])==-1) {
            _xia_print("ReadScas", sprintf("Failed to read SCAs from pt.%d", frompt), 1)
        }
    }
    if (esrf_io(XIA_DEV, "DevXiaReadScas", frombuffer, XIA_SCAS)==-1) {
        _xia_print("ReadScas", "Failed to read SCAs", 1)
    }
}'


#%IU%
#%MDESC%
#    Reads run statistics
#%BR% if <frombuffer> is set to 1,
# get statistics from server buffer: no readout performed.
#
def _xia_readstat(frombuffer) '{
    local ich
    if (esrf_io(XIA_DEV, "DevXiaReadStat", frombuffer, XIA_STAT)==-1) {
        _xia_print("ReadStat", "Failed to read statistics", 1)
    }

    # --- FIX for wrong REALTIME in DXP2X when using external gate
    if ((XIA_PAR["type"]==1) && (XIA_PAR["gate"]==1)) {
        if (S[sec]>0) {
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++)
                    XIA_STAT[ich][3]= XIA_STAT[ich][1]/S[sec]
        }
        }
    # --- end of FIX

    ich= XIA_PAR["nbdet"]
    XIA_STAT[ich][0]= -1
    if (ich>1) {
        XIA_STAT[ich][0]= -1
        XIA_STAT[ich][1]= array_op("sum", XIA_STAT[0:ich-1][1])/ich
        XIA_STAT[ich][2]= array_op("sum", XIA_STAT[0:ich-1][2])/ich
        XIA_STAT[ich][3]= array_op("sum", XIA_STAT[0:ich-1][3])/ich
        XIA_STAT[ich][4]= array_op("sum", XIA_STAT[0:ich-1][4])/ich
        XIA_STAT[ich][5]= array_op("sum", XIA_STAT[0:ich-1][5])/ich
    }
    else {
        XIA_STAT[ich][0]= -1
        XIA_STAT[ich][1]= XIA_STAT[0][1]
        XIA_STAT[ich][2]= XIA_STAT[0][2]
        XIA_STAT[ich][3]= XIA_STAT[0][3]
        XIA_STAT[ich][4]= XIA_STAT[0][4]
        XIA_STAT[ich][5]= XIA_STAT[0][5]
    }
}'


#%IU%
#%MDESC% Read xia specific counters
#
def _xia_readcnts '{
        local ich num

        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
                if ((num=cnt_num(sprintf("xicr%02d", XIA_DET[ich])))!=-1)
                        S[num]= XIA_STAT[ich][2]
                if ((num=cnt_num(sprintf("xocr%02d", XIA_DET[ich])))!=-1)
                        S[num]= XIA_STAT[ich][3]
                if ((num=cnt_num(sprintf("xlt%02d", XIA_DET[ich])))!=-1)
                        S[num]= XIA_STAT[ich][4]/1000.
                if ((num=cnt_num(sprintf("xdt%02d", XIA_DET[ich])))!=-1)
                        S[num]= XIA_STAT[ich][5]
        }
        if (XIA_PAR["cntset"] && XIA_PAR["cntdet"]!=-1) {
            ich= XIA_PAR["cntdet"]
        }
        if ((num=cnt_num("xicr"))!=-1) S[num]= XIA_STAT[ich][2]
        if ((num=cnt_num("xocr"))!=-1) S[num]= XIA_STAT[ich][3]
        if ((num=cnt_num("xlt"))!=-1) S[num]= XIA_STAT[ich][4]/1000.
        if ((num=cnt_num("xdt"))!=-1) S[num]= XIA_STAT[ich][5]
}'

def _xia_mapstatarray() '{
    long array XIA_MAPSTAT[XIA_PAR["pixnb"]][6*XIA_PAR["nbdet"]]
}'

def _xia_readmapstat(frompt) '{
    local nread nfrom

    if (frompt < 0) {
        nfrom= 0
    } else {
        nfrom= frompt
    }
    
    nread= esrf_io(XIA_DEV, "DevXiaReadMapStat", nfrom, XIA_MAPSTAT[nfrom:][:])
    if (nread == -1) {
        _xia_print("ReadMapStat", "Failed to read map statistics", 1)
    } else {
        return (nread)
    }
}'


# -----------------------------------------------------------------------------
# ACQUISITION CONTROL
# -----------------------------------------------------------------------------


#%IU%
#%MDESC% Start acquisition
#
def xiastart '{
    if ((XIA_PAR["gate"]!=1) && XIA_PAR["preset"] && COUNT_TIME) {
        _xia_setpreset(COUNT_TIME)
    }

    if (esrf_io(XIA_DEV, "DevXiaStart")==-1){
        _xia_print("Start", "Cannot start acquisition", 1)
    }
    else{
        cdef("cleanup_once", ";_xia_cleanup;", "_xiarun_")
    }
}'


#%IU%
#%MDESC%
#    Waits forr the device server to be ready after saving and starts
#    acquisition
def xiastart_wait '{
    local started t1 ret

    if ((XIA_PAR["gate"]!=1)&&XIA_PAR["preset"]&&COUNT_TIME) {
        _xia_setpreset(COUNT_TIME)
    }

    if (esrf_io(XIA_DEV, "DevXiaStart")==-1) {
        _xia_print("Start", "Cannot start acquisition", 1)
    }
    else {
        cdef("cleanup_once", ";_xia_cleanup;", "_xiarun_")

        xia_dbg("waiting XIA to start ...")
        t1 = time()
        for (started=0 ; !started ;) {
            ret= esrf_io(XIA_DEV, "DevXiaGetMapState", ZAP_XMAP_STATE)
            if (ZAP_XMAP_STATE[0] == 1) {
                started = 1
            } else {
                started = 0
            }
        }
        xia_dbg(sprintf("done in %g(s)\n", time()-t1))
    }
}'


#%IU%
#%MDESC% Stop acquisition
#
def xiastop '{
    if (esrf_io(XIA_DEV, "DevXiaStop")==-1)
        _xia_print("Stop", "Cannot stop acquisition", 1)
    else{
        cdef("cleanup_once", "", "_xiarun_", "delete")
    }
}'


#%IU%
#%MDESC% Cleanup macro
def _xia_cleanup '{
    xiastop
    xiaread
}'


#%UU% [<time>] [<refresh_rate>]
#%MDESC% Acquisition for <time> sec. or until Ctrl-C is pressed
#%BR% default refresh_rate is set to 0.5 (real time mode), 0.1 (live time mode)
#
def xiaacq '{
    local asktime slptime ntime

    if (XIA_PAR["mode"]&XIA_MODEMAP) {
        _xia_print("ERROR", "Cannot use xiaacq while in mapping mode", 1)
        exit
    }

    asktime= $1
    ntime= 0

    if((XIA_PAR["gate"] == 1) && (asktime == 0)){
        asktime = 1
    }

    COUNT_TIME= asktime

    if (XIA_PAR["live"]){
        slptime= $2 ? $2 : 0.1
    }
    else{
        slptime= $2 ? $2 : 0.5
    }

    if (_xia_hascorr()) {
        cdef("cleanup_once", "XIA_CORR[\"inacq\"]= 0;", "_xcorr_", 0x20)
        XIA_CORR["inacq"]= 1
    }

    if ((XIA_PAR["mode"] & XIA_MODEMCA) && XIA_SAVE["ct"]){
            cdef("cleanup_once", ";xiasave;", "_xiasave_", 0x20)
    }

    # printf( "avant xiastart : COUNT_TIME=%s  asktime=%s \n", COUNT_TIME , asktime)

    xiastart

    if (asktime && (!XIA_PAR["live"]) ) {
        tcount(asktime)
    }

    _xia_plotonlineinit

    while ((!asktime) || (wait(0x22))) {
        sleep(slptime)
        xiaread
        if (asktime && XIA_PAR["live"] && (XIA_STAT[XIA_PAR["nbdet"]][4]>=(asktime*1000.))) {
            asktime= 0
        }
        else {
            xiatimes ntime
            _xia_plotonlinedata
            ntime++
        }
    }
    xiastop
    xiaread
    xiatimes ntime
    _xia_plotonlinedata
    if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_SAVE["ct"]) xiasave

    if (_xia_hascorr()) {
        XIA_CORR["inacq"]= 0
    }
}'


#%UU%
#%MDESC%
#    Hookable macros to attach user-defined actions on xia ON/OFF.
cdef ("user_xia_on",  "", "xia")
cdef ("user_xia_off", "", "xia")


#%UU%
#%MDESC% Activate xia on ct/scans
def xiaon '{
    if (!XIA_INIT) {
        _xia_print("Cannot set ON", "XIA not initialized", 1)
        XIA_ON= 0
    }
    else {
        _xia_print("xiaon", sprintf( "XIA was %s ", XIA_ON?"ON":"OFF"), 0)
        cdef("user_Fheader", "_xia_Fheader;", "xia")
        cdef("user_postscan_head", "_xia_scan_head;", "xia")
        cdef("user_scan_loop", "_xia_scan_loop;", "xia")
        cdef("user_scan_tail", ";_xia_scan_tail;", "xia")
        cdef("user_prepcount", ";_xia_prepcount;", "xia", 0x20)
        cdef("user_getcounts", ";_xia_getcounts;", "xia", 0x10)
        cdef("user_handlecounts", ";_xia_handlecounts;", "xia")
        XIA_ON= 1
        xiacntenable
        _xia_print("xiaon", "XIA is now ON", 0)
        user_xia_on
    }
}'


#%UU%
#%MDESC% Deactivate xia on ct/scans
def xiaoff '{
    _xia_print("xiaon", sprintf( "XIA was %s ", XIA_ON?"ON":"OFF") , 0)
    cdef("","","xia","delete")
    XIA_ON= 0
    if (XIA_LINEUP) xialineupoff
    xiacntdisable
    _xia_print("xiaon", "XIA is now OFF", 0)
    user_xia_off
}'



# To activate/deactivate in a loop
def xia_activate '{
    XIA_ON= 1
}'

def xia_desactivate '{
    XIA_ON= 0
}'

#%IU%
#%MDESC%
def _xia_prepcount '{
    if (XIA_ON == 1) {
        if (!(XIA_PAR["mode"]&XIA_MODEMAP)){
            xiastart
        }
    }
}'


#%IU%
#%MDESC%
def _xia_getcounts '{
    if (XIA_ON == 1) {
        if (!(XIA_PAR["mode"]&XIA_MODEMAP)) {
            xiastop
            xiaread
        }
    }
}'


#%IU%
#%MDESC%
def _xia_handlecounts '{
    if(XIA_ON == 1){
        if (XIA_PAR["mode"]&XIA_MODEMCA) {
            _xia_plotonlineinit
            _xia_plotonlinedata
            if (XIA_SAVE["ct"]) xiasave
        }
    }
}'


#%IU%
#%MDESC%
def _xia_scan_head '{
    if(XIA_ON == 1){
        cdef("cleanup_once", ";_xia_scan_abort;", "xia_scan_abort")
        _xia_plotonlineinit
        if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_SAVE["scan"]) _xia_savescaninit
        if (XIA_PAR["mode"]&XIA_MODEMAP) {
            _xia_mapsetpoints(_n1)
            xiastart
        }
    }
}'


#%IU%
#%MDESC%
def _xia_scan_loop '{
    if(XIA_ON == 1){
        _xia_plotonlinedata
        if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_SAVE["scan"]) {
            _xia_savescandata
        }
    }
}'


#%IU%
#%MDESC%
def _xia_scan_tail '{
    if(XIA_ON == 1){
        if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_SAVE["scan"]) {
            _xia_savescanfile
            unglobal XIA_HEADER
        }

        if (XIA_PAR["mode"]&XIA_MODEMAP) {
            xiastop
            xiaread
            if ((DATAFILE!="")&&(DATAFILE!="/dev/null")) {
                _xia_mapsave(DATAFILE, ++SCAN_N, HEADING, NPTS, 1)
            }
        }

        cdef("cleanup_once", "", "xia_scan_abort", "delete")
    }
}'


#%IU%
#%MDESC%
def _xia_scan_abort '{
    if (XIA_PAR["mode"]&XIA_MODEMAP)
    xiastop
    if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_SAVE["scan"]) {
    _xia_savescanfile
    unglobal XIA_HEADER
    XIA_SAVE["num"]++
    }
}'


#%IU%
#%MDESC%
def _xia_Fheader '{
    if ((XIA_SAVE["scan"]||XIA_SAVE["ct"]) && XIA_ON) {
        _xia_saveroiheader
    }
}'


# -----------------------------------------------------------------------------
# ACQUISITION SETUP
# -----------------------------------------------------------------------------

#%UU% [<acqmode> [<par1> <par2> <par3>]]
#%MDESC% Set acquisition parameters:
#%BR% * %B%standard%B% modes:
#%BR% - acqmode= XIA_MODEMCA (acquire spectrum, dxp2x and xmap)
#%BR% - acqmode= XIA_MODESCA (acquire only scas, dxp2x only)
#%BR% - par1= extgate, par2= autoclear, par3= presetmode
#%BR% * %B%mapping%B% mode:
#%BR% - XMAP boards:
#%BR% ... acqmode= XIA_MODEMAP|XIA_MODEMCA (acquire spectrum, xmap only)
#%BR% ... par1= gate/sync pixel advance, par2= nb of pixels, par3= pixels/buffer
#%BR% - DXP2X boards:
#%BR% ... acqmode= XIA_MODEMAP|XIA_MODESCA (acquire only scas, dxp2x only)
#%BR% ... par1= multimode, par2= signlepass, par3= numpoints
#
def xiaacqsetup '{
    local mode par1 par2 par3
    local imod

    if ($#<1) {
    if (XIA_PAR["type"]==2) {
        _xia_xmap_acqsetup
    } else if (XIA_PAR["type"]==3 || XIA_PAR["type"]==4) {
        _xia_mercury_acqsetup
    } else {
        _xia_dxp2x_acqsetup
    }
    if ((!(mode&XIA_MODEMAP))&&(!(mode==XIA_MODEHWSCA))) {
        par1= yesno("- Use external gate", XIA_PAR["gate"])
        par2= yesno("- Auto-clear memory", XIA_PAR["clear"])
        if (!par1) {
            print "- Preset mode"
            for (imod=0; imod<5; imod++){
               printf("\t(%d) %s\n", imod, XIA_MSG["preset"][imod])
            }

            par3= getval("    Give preset mode", XIA_PAR["preset"])
        }
        else {
           par3= 0
        }
    }
    }
    else {
        # non-interactive setup
        mode = $1
        par1 = $2
        par2 = $3
        par3 = $4
    }

    if (!_xia_setacqpar(mode, par1, par2, par3))
    _xia_print("xiaacqsetup", "Setup acquisition parameters FAILED", 1)
}'


#%IU%
#%MDESC% DXP2X specific acquisition setup
#
def _xia_dxp2x_acqsetup '{
    local modes[] askmode

    modes[1]= XIA_MODEMCA
    modes[2]= XIA_MODESCA
    modes[3]= (XIA_MODESCA|XIA_MODEMAP)

    print "- Acquisition mode:"
    print "\t(1) MCA - read full spectrum"
    print "\t(2) SCA - read only scas (rois)"
    print "\t(3) SCAMAP - sca mapping mode"
    askmode= getval("    Choose mode", XIA_PAR["mode"]==6?3:XIA_PAR["mode"])

    if ((askmode!=1)&&(askmode!=2)&&(askmode!=3)) {
        _xia_print("ERROR", "Invalid acquisition mode. Abort.", 1)
    exit
    }
    mode= modes[askmode]
    if (mode&XIA_MODEMAP) {
    if ((!XIA_PAR["multimode"])&&(!XIA_PAR["singlepass"]))
        XIA_PAR["singlepass"]= 1
    par1= yesno("- Multimode       ", XIA_PAR["multimode"])
    par2= yesno("- Single Pass     ", XIA_PAR["singlepass"])
    par3= getval_int("- Numb. of Points ", XIA_PAR["numpoints"])
    }
}'


#%IU%
#%MDESC% XMAP specific acquisition setup
#
def _xia_xmap_acqsetup '{
    local modes[] askmode ctrl

    modes[1]= XIA_MODEMCA
    modes[2]= (XIA_MODEMCA|XIA_MODEMAP)

    print "- Acquisition mode:"
    print "\t(1) MCA - read full spectrum at each scan point"
    print "\t(2) MCAMAP - mca mapping mode (zap)"
    askmode= getval("    Choose mode", XIA_PAR["mode"]==5?2:XIA_PAR["mode"])

    if ((askmode!=1)&&(askmode!=2)) {
        _xia_print("ERROR", "Invalid acquisition mode. Abort.", 1)
        exit
    }

    mode= modes[askmode]
    if (mode&XIA_MODEMAP) {
    ctrl= yesno("- Pixel advance control by GATE", XIA_PAR["pixctrl"]==0)
    if (ctrl) {
        par1= 0
    } else {
        print "==> Pixel advance will be controlled by SYNC"
        par1= getval_int("- Number of SYNC pulses per pixel", XIA_PAR["pixctrl"]?XIA_PAR["pixctrl"]:1)
    }

        # pixel/buffer == 0 => DS crashes.
        if (XIA_PAR["pixbuf"] == 0) {
            XIA_PAR["pixbuf"] = ZAP_XMAP["bufsize"]
        }

    par2= getval_int("- Total number of pixels", XIA_PAR["pixnb"])
    par3= getval_int("- Number of pixels per buffer (-1=max)", XIA_PAR["pixbuf"])
    }
}'

# mercury specific setup for hardware SCA.
def _xia_mercury_acqsetup '{
    local modes[] askmode ctrl prevmode

    modes[1]= XIA_MODEMCA
    modes[2]= (XIA_MODEMCA|XIA_MODEMAP)
    modes[3]= XIA_MODEHWSCA

    if (XIA_PAR["mode"]==XIA_MODEMCA) {
        prevmode= 1
    } else if (XIA_PAR["mode"]==XIA_MODEHWSCA) {
        prevmode= 3
    } else {
        prevmode= 2 
    }

    print "- Acquisition mode:"
    print "\t(1) MCA - read full spectrum at each scan point"
    print "\t(2) MCAMAP - mca mapping mode (zap)"
    print "\t(3) HWSCA - sca hardware output only"
   
    askmode= getval("    Choose mode", prevmode)

    if ((askmode!=1)&&(askmode!=2)&&(askmode!=3)) {
        _xia_print("ERROR", "Invalid acquisition mode. Abort.", 1)
        exit
    }

    mode= modes[askmode]
    
    if (mode&XIA_MODEMAP) {
    ctrl= yesno("- Pixel advance control by GATE", XIA_PAR["pixctrl"]==0)
    if (ctrl) {
        par1= 0
    } else {
        print "==> Pixel advance will be controlled by SYNC"
        par1= getval_int("- Number of SYNC pulses per pixel", XIA_PAR["pixctrl"]?XIA_PAR["pixctrl"]:1)
    }

        # pixel/buffer == 0 => DS crashes.
        if (XIA_PAR["pixbuf"] == 0) {
            XIA_PAR["pixbuf"] = ZAP_XMAP["bufsize"]
        }

    par2= getval_int("- Total number of pixels", XIA_PAR["pixnb"])
    par3= getval_int("- Number of pixels per buffer (-1=max)", XIA_PAR["pixbuf"])
    }
}'

#%IU% (acqmode, par1, par2, par3)
#%MDESC% Set device acquisition parameters
#%BR% See %B%xiaacqsetup%B% for description of parameters
#
# <acqmode> :
#
# IN MODE 
# <par1> : 
# <par2> : 
# <par3> : 
#
# IN MAP MODE 
# <par1> : 
# <par2> : 
# <par3> : 
def _xia_setacqpar(acqmode, par1, par2, par3) '{
    global short array XIA_ACQPAR[4]
    local setmode scalen

    xia_dbg(sprintf("_xia_setacqpar(%s %s %s %s)", acqmode, par1, par2, par3))
    XIA_ACQPAR[0]= (acqmode==XIA_MODEHWSCA) ? XIA_MODEMCA : acqmode
    XIA_ACQPAR[1]= par1
    XIA_ACQPAR[2]= par2
    XIA_ACQPAR[3]= par3

    if (acqmode != XIA_PAR["mode"]) {
        if (esrf_io(XIA_DEV, "timeout", 80)==-1) {
            _xia_print("SetAcqPar", "Failed to set device timeout", 1)
            return (0)
        }
        _xia_print("SetAcqPar", sprintf("Switching from mode <%s> to <%s>", \
                                        XIA_MSG["mode"][XIA_PAR["mode"]], XIA_MSG["mode"][acqmode]))
        _xia_print("SetAcqPar", "Please wait ...")
        setmode= 1
    }
    else {
        esrf_io(XIA_DEV, "timeout", 10)
    }

    if (esrf_io(XIA_DEV, "DevXiaSetAcqPar", XIA_ACQPAR)==-1) {
        _xia_print("SetAcqPar", "Cannot set acquisition parameters", 1)
        return (0)
    }

    esrf_io(XIA_DEV, "timeout", 5)

    if (setmode) {
        _xia_print("SetAcqPar", "OK", 0)
        if (!_xia_readchanpar()) return (0)
        if ((XIA_PAR["type"]==3)||(acqmode&XIA_MODESCA)) {
            _xia_roitosca()
        }
        if (acqmode==(XIA_MODEMCA|XIA_MODEMAP)) {
            _xia_roitosca()
            _xia_getfilepar()
        }
    }

    if (!_xia_readacqpar(acqmode)) {
        return (0)
    }

    if (XIA_PAR["mode"]&XIA_MODEMAP) {
        if (XIA_PAR["nbsca"]) {
            _xia_scaarray()
        }
        _xia_mapstatarray()
    }

    return (1)
}'


#%UU% [<chmin> <chmax> | <length>]
#%MDESC% Set spectrum range for all detectors
#%BR% * DXP2X boards: spectrum between channels <chmin> and <chmax>
#%BR% * XMAP boards : define only spectrum length. Channel range is [0:length-1]
#
def xiarange '{
    local chmin chmax chlen
    if (XIA_PAR["type"]>=2) {
        if ($#!=1) {
            chlen= getval_int_pos("- Spectrum length, max=8192", XIA_PAR["chlen"])
            chmin= 0
            chmax= chlen-1
        } else {
            chmin= 0
            chmax= int($1)-1
        }
    } else {
        if ($#!=2) {
            chmin= getval_int_pos("- First channel", XIA_PAR["chmin"])
            chmax= getval_int_pos("- Last channel, max=8192", XIA_PAR["chmax"])
        } else {
            chmin= int($1)
            chmax= int($2)
        }
    }
    if ((chmin!=XIA_PAR["chmin"])||(chmax!=XIA_PAR["chmax"])) {
        if (!_xia_setrange(chmin, chmax)) {
            _xia_print("xiarange", "Set acquisition range FAILED", 1)
        }
    }
}'


#%IU% (chmin, chmax)
#%MDESC% Set acquisition range in channels
#
def _xia_setrange(chmin, chmax) '{
    local long array chrange[2]

    if (chmin<0||chmin>8192||chmax<0||chmax>8192) {
        _xia_print("SetAcqRange", "Range should be inside [0,8192]")
        return (0)
    }
    chrange[0]= chmin<chmax?chmin:chmax
    chrange[1]= chmax>chmin?chmax:chmin

    if (esrf_io(XIA_DEV, "DevXiaSetAcqRange", chrange)==-1) {
        _xia_print("SetAcqRange", "Cannot set acquisition range", 1)
        return (0)
    }
    return (_xia_readchanpar())
}'


#%IU% [<preset_value>]
#%MDESC% Set preset value
#%BR% if preset mode is %B%Live%B% or %B%Real%B% time, preset is <preset_value> sec.
#%BR% if preset mode is %B%Input%B% or %B%Output%B%, preset is <preset_value> counts.
#
def xiapreset '{
    local preval
    if (!XIA_PAR["preset"]) {
        _xia_print("xiapreset", "No preset mode selected. Use xiaacqsetup first.")
    }
    else {
        if ($#!=1) {
            printf("Preset Mode = %s\n", XIA_MSG["preset"][XIA_PAR["preset"]])
            if (XIA_PAR["preset"]==1 || XIA_PAR["preset"]==2){
                preval= getval("Preset time in sec", 1.)
            }
            else{
                preval= getval_int("Preset counts", 5000)
            }
        }
        else {
            preval= int($1)
        }
        if (!_xia_setpreset(preval))
            _xia_print("xiapreset", "Set preset value FAILED", 1)
    }
}'


#%IU% (preset)
#%MDESC% Set preset value (in ms if real/live time preset mode set)
#
def _xia_setpreset(preset) '{
    local factor
    if (preset<0) {
        _xia_print("Preset", "Preset value should be >=0", 1)
        return (0)
    }
    if ((XIA_PAR["preset"]==1)||(XIA_PAR["preset"]==2)) factor=1000
    else factor= 1

    if (esrf_io(XIA_DEV, "DevXiaPreset", factor*preset)) {
        _xia_print("Preset", "Cannot set preset value", 1)
        return (0)
    }
    return (1)
}'


#%UU%
#%MDESC% When auto-clear mode is OFF, allow user to clear spectrum memory when needed
def xiaclear '{
    if (XIA_PAR["clear"]) {
        _xia_print("Clear", "Auto-clear is already ON.")
    }
    else {
        if (esrf_io(XIA_DEV, "DevXiaClear")==-1)
            _xia_print("Clear", "Cannot send clear command", 1)
    }
}'


# -----------------------------------------------------------------------------
# SCA MAPPING MODE (DXP2X boards)
# -----------------------------------------------------------------------------

#%UU% <detector_number>
#%MDESC% %B%dxp2x%B% boards only:
#%BR% In SCA mapping mode, report all values acquired for one detector. This
# includes livetime, realtime, input/output counts, and all scas configured.
def xiamapreport '{
    local idx idet isca nsca ipts offset npts ii ipts

    if (!$#) {
        print "$0 <detector_number>"
        exit
    }

    idet= int($1)
    idx= _xia_getdetidx(idet)
    if (idx==-1) {
        _xia_print("Detector", sprintf("Det. number <%d> undefined.", idet), 1)
        exit
    }
    _xia_print("MapReport", sprintf("Detector <%d>", idet))

    npts= XIA_PAR["numpoints"]
    nsca= XIA_SCADET[idx]
    offset= 0
    for (ii=0; ii<idx; ii++) {
        offset= npts*(4+XIA_SCADET[ii])
    }

    printf("Points  LiveTime  RealTime  In.Count  OutCount")
    for (isca=1; isca<=list_n(XIA_ROI); isca++) {
        if (list_getpar(XIA_ROI, isca, "det")==idet) {
            printf("  %8.8s", list_item(XIA_ROI, isca))
        }
    }
    printf("\n")


    for (ipts=0; ipts<npts; ipts++) {
        printf("%5d", ipts)
        for (isca=0; isca<4+nsca; isca++) {
            printf(" %9d", XIA_SCAS[offset+ipts*(4+nsca)+isca])
        }
        printf("\n")
    }

    printf("\n")
}'


#%IU%
#%MDESC%
def _xia_mapsave(file, scanno, heading, nbpts, addscand) '{
    local ndet nsca npts nspec i isca idet str ipts

    ndet= XIA_PAR["nbdet"]
    nsca= XIA_PAR["nbsca"]
    npts= nbpts>0?nbpts:XIA_PAR["numpoints"]
    if (npts>XIA_PAR["numpoints"])
    npts= XIA_PAR["numpoints"]

    fprintf(file, "\n#S %d  xia - %s\n", scanno, heading?heading:"scamap")
    fprintf(file, "#D %s\n", date())

    if (addscand) {
    nspec= PLOT_MOTS
    for (i=0; i<PLOT_CNTRS; i++)
        if (is_using_counter(i))
        nspec++
    }
    else {
    nspec= 1
    }

    fprintf(file, "#N %d\n", nspec + ndet*4 + nsca)
    str="#L"
    if (addscand) {
    for (i=0; i<PLOT_MOTS; i++)
        str= str sprintf("  %s", motor_name(_m[i]))
    for (i=0; i<PLOT_CNTRS; i++)
        if (is_using_counter(i))
        str= str sprintf("  %s", cnt_name(i))
    }
    else {
    str= str "  Points"
    }
    for (idet=0; idet<ndet; idet++) {
    str= str sprintf("  xlt%02d  xrt%02d  xic%02d  xoc%02d", XIA_DET[idet], \
            XIA_DET[idet], XIA_DET[idet], XIA_DET[idet])
    for (isca=1; isca<=list_n(XIA_ROI); isca++)
        if (list_getpar(XIA_ROI, isca, "det")==XIA_DET[idet])
        str= str sprintf("  %s", list_item(XIA_ROI, isca))
    }
    fprintf(file, "%s\n", str)

    local long array DET_OFFSET[ndet]

    DET_OFFSET[0]= 0
    for (idet=1; idet<ndet; idet++) {
    DET_OFFSET[idet]= DET_OFFSET[idet-1] + XIA_PAR["numpoints"]*(4+XIA_SCADET[idet-1])
    }

    for (ipts=0; ipts<npts; ipts++) {
    if (addscand) {
        str= ""
        for (i=0; i<PLOT_MOTS; i++)
        str= str sprintf(" %8g", SCAN_D[ipts][i])
        for (i=0; i<PLOT_CNTRS; i++)
        if (is_using_counter(i))
            str= str sprintf(" %8g", SCAN_D[ipts][PLOT_MOTS+i])
    }
    else {
        str= sprintf("%8g", ipts)
    }

    for (idet=0; idet<ndet; idet++) {
        nsca= 4 + XIA_SCADET[idet]
        offset= DET_OFFSET[idet] + ipts*nsca
        for (isca=0; isca<nsca; isca++)
        str= str sprintf(" %8g", XIA_SCAS[offset+isca])
    }
    fprintf(file, "%s\n", str)
    }
    fprintf(file, "\n")
}'


#%IU% ()
#%MDESC% In mapping mode, checks that the number of points acquired is the same as
# the number of points asked. Return 1 on success, 0 otherwise.
def _xia_mapcheck() '{
    local askpts idet
    local long array XIA_DSPPAR[XIA_PAR["nbdet"]]

    askpts= XIA_PAR["numpoints"]-1

    if (esrf_io(XIA_DEV, "DevXiaGetDspPar", "POINTNUM", XIA_DSPPAR)==-1) {
        _xia_print("MapCheck", "Cannot read DSP parameter <POINTNUM>", 1)
        return (0)
    }

    for (idet=0; idet<XIA_PAR["nbdet"]; idet++) {
        if (XIA_DSPPAR[idet]!=askpts) {
            _xia_print("MapCheck", sprintf("Wrong number of points on detector <%d>", XIA_DET[idet]), 1)
            return (0)
        }
    }

    return (1)
}'


#%IU% (numpoints)
#%MDESC% Shortcut to set SCAMAP mode with NO multimode, singlepass set and given number of points
def _xia_mapsetpoints(numpoints) '{
    return _xia_setacqpar(XIA_MODESCA|XIA_MODEMAP, 0, 1, numpoints)
}'


# -----------------------------------------------------------------------------
# MCA MAPPING MODE (XMAP boards)
# -----------------------------------------------------------------------------
#%UU%
#%MDESC%
#%B%xmap%B% boards only:
#%BR%In MCA mapping mode, gets information on current acquisition
#
def xiamapstatus '{
    local ret status
    local short array mappar[4]

    ret= esrf_io(XIA_DEV, "DevXiaGetMapState", mappar)
    if (ret!=-1) {
    if (mappar[0]==0) status= "FINISHED"
    else if (mappar[0]==1) status= "RUNNING"
    else if (mappar[0]==2) status= "SAVING"
        else status= "UNKNOWN"

    _xia_print("Mapping Status  ", status)
    _xia_print("Current Pixel   ", sprintf("%d", mappar[1]))
    _xia_print("Last Read Pixel ", sprintf("%d", mappar[2]))
    _xia_print("Saved Files     ", sprintf("%d (/%d)", mappar[3], (XIA_PAR["nbdet"]+(XIA_PAR["nbdet"]>1)+1)))
    } else {
    _xia_print("MapStatus", "Failed to get mapping state", 1)
    }
}'



# -----------------------------------------------------------------------------
# PRINT INFOS
# -----------------------------------------------------------------------------

#%IU% (fnct, msg, type)
#%MDESC% Print formatted message (type=1 means error message)
# (type=1 means warning message)
#
def _xia_print(fnct, msg, type) '{
    # type: 0=info, 1=error, 2=warning
    tty_cntl("md");

        if (type == 1){
            printf("XIA ERROR> ")
        }
        else{
            printf("XIA > ")
        }

        tty_cntl("me")
        if(type == 1){
            cprint(sprintf("%s: %s\n", fnct, msg), 1)
        }
        else if(type == 2){
            cprint(sprintf("%s: %s\n", fnct, msg), 3)
        }
        else{
            cprint(sprintf("%s: %s\n", fnct, msg), 4)
        }
}'


#%UU%
#%MDESC% Report Livetime, DeadTime, ICR and OCR of last acquisition
def xiatimes '{
    local cy ich

    cy= -3 - XIA_PAR["nbdet"]
    if (!$1) {
        for (ich=0; ich>cy; ich--) print
    }
    tty_move(0, cy++, "\[md\]Detector    ICR    OCR LiveTime DeadTime\[me\]")
    for (ich=0; ich<XIA_PAR["nbdet"]; ich++)
        tty_move(0, cy++, sprintf(\
            "      %2d %6d %6d %8.2f    %3d %%", XIA_DET[ich], \
            XIA_STAT[ich][2], XIA_STAT[ich][3], \
            XIA_STAT[ich][4]/1000., XIA_STAT[ich][5]))
    ich= XIA_PAR["nbdet"]
    tty_move(0, cy++, sprintf(\
        "\[md\]Average\[me\]  %6d %6d %8.2f    %3d %%\n", \
        array_op("sum", XIA_STAT[ich][2]), \
        array_op("sum", XIA_STAT[ich][3]), \
        array_op("sum", XIA_STAT[ich][4])/1000., \
        array_op("sum", XIA_STAT[ich][5])))
}'


#%UU%
#%MDESC% Print out status and some parameters
#
def xiastatus '{
    _xia_print("STATUS", esrf_io(XIA_DEV, "DevStatus"))
}'


#%UU%
#%MDESC% Print out device parameters
#
def xiainfo '{
    _xia_print("Device name  ", XIA_DEV)
    _xia_print("Board Type   ", sprintf("%s", XIA_MSG["type"][XIA_PAR["type"]]))
    _xia_print("Nb Modules   ", sprintf("%d", XIA_PAR["nbmod"]))
    _xia_print("Nb Detectors ", sprintf("%d", XIA_PAR["nbdet"]))
    _xia_print("Spec. length ", sprintf("%d", XIA_PAR["chlen"]))
    _xia_print("Channel min  ", sprintf("%d", XIA_PAR["chmin"]))
    _xia_print("Channel max  ", sprintf("%d", XIA_PAR["chmax"]))
}'


# -----------------------------------------------------------------------------
# PyMca/xiastat GUI
# -----------------------------------------------------------------------------

#%UU% <display>
#%MDESC%
# Set display used for external GUI (PyMca, XiaStat)
def xiaguidisplay '{
    if (!$#)
    print "USAGE: $0 <display>"
    else
    XIA_GUIDPY= "$1"
}'


#%UU% [<display>]
#%MDESC% Open PyMca plotting GUI
def xiaguiopen '{
    if ($#>0)
        XIA_GUIDPY= "$1"
    if (!XIA_GUI || unix(sprintf("kill -0 %d 2>/dev/null", XIA_GUI)))
        XIA_GUI= _xia_guistart("PyMca")
}'

#%UU% [<display>]
#%MDESC% Open PyMca plotting GUI
def xiaguion '{
    if ($#>0)
        XIA_GUIDPY= "$1"
    if (!XIA_GUI || unix(sprintf("kill -0 %d 2>/dev/null", XIA_GUI)))
        XIA_GUI= _xia_guistart("PyMca")
}'


#%UU%
#%MDESC% Close PyMca plotting GUI
def xiaguiclose '{
    if (XIA_GUI) {
        _xia_guiclose(XIA_GUI)
        XIA_GUI= 0
    }
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_guistart(guistr) '{
    local guicmd file pid

    if (guistr=="PyMca") {
        guicmd= sprintf("PyMca --spec=%s --shm=XIA_DATA", SPEC, larr)
        file= sprintf("/tmp/xiagui_%s_%s.pid", SPEC, USER)
    }
    else if (guistr=="stat") {
        guicmd= sprintf("xiastat %s", SPEC)
        file= sprintf("/tmp/xiastatgui_%s_%s.pid", SPEC, USER)
    }
    else return (0)

    if ((XIA_GUIDPY != 0) && (guistr != "PyMca"))
        guicmd= sprintf("%s -display %s", guicmd, XIA_GUIDPY)

    if (!unix(sprintf("test -r %s", file))) {
        pid= getline(file)
        getline(file,"close")
        if (pid && !unix(sprintf("kill -0 %d 2>/dev/null",pid))) {
            return (pid)
        }
    }

    unix(sprintf("%s >/dev/null 2>&1 & echo \$! > %s",guicmd,file))
    pid= getline(file)
    getline(file, "close")
    return (pid)
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_guiclose(pid) '{
    unix(sprintf("kill -9 %d 2>/dev/null", pid))
}'


#%UU% [<display>]
#%MDESC% Open statistics GUI
def xiastatopen '{
    if ($#>0)
    XIA_GUIDPY= "$1"
    if (!XIA_STATGUI || unix(sprintf("kill -0 %d 2>/dev/null", XIA_STATGUI)))
    XIA_STATGUI= _xia_guistart("stat")
}'


#%UU%
#%MDESC% Close statistics GUI
def xiastatclose '{
    if (XIA_STATGUI) {
        _xia_guiclose(XIA_STATGUI)
        XIA_STATGUI= 0
    }
}'


# -----------------------------------------------------------------------------
# PLOTTING
# -----------------------------------------------------------------------------

#%IU% (detnum)
#%MDESC% Return array index for detector <detnum>
#%BR% If not found, return -1
#
def _xia_getdetidx(detnum) '{
    local ich

    for (ich=0; ich<XIA_PAR["nbdet"] && XIA_DET[ich]!=detnum; ich++) {}
    if (ich==XIA_PAR["nbdet"]) ich= -1
    return (ich)
}'


#%IU% (det)
#%MDESC% Initialize spec plot for given detector
#
def _xia_plotinit(det) '{
    # --- init plot device
    plot_cntl("filter2,open")
    plot_cntl("erase")
    plot_cntl("+lines")
    plot_cntl("-ebars")
    plot_cntl("-dots")
    plot_cntl(XIA_PLOT["log"]?"+ylog":"-ylog")
    plot_range("auto", "auto", "auto", "auto")
    plot_cntl("colors=49:16:9:3:2:7:8:9:5:4:2")
    plot_move(0, 0, sprintf("XIA DET=%d", det))
    plot_cntl("filter1")

    # --- init plot array
    ulong array XIA_PLOTARR[2][XIA_PAR["chlen"]]
    XIA_PLOTARR[0]= XIA_DATA[0]
    XIA_PLOTARR[1]= 0
}'


#%IU% (det, from, to)
#%MDESC% Plot data on spec plot
#
def _xia_plotdata(idet, from, to) '{
    local beg end idx

    beg= from?from:0
    end= to?to-1:XIA_PAR["chlen"]-1
    if ((idx=_xia_getdetidx(idet))!=-1) {
        XIA_PLOTARR[1][beg:end]= XIA_DATA[idx+1][beg:end]
    }
    plot_cntl("filter2")
    plot_cntl("mca")
    array_plot(XIA_PLOTARR[][beg:end])
    plot_cntl("filter1")
}'


#%UU% <det> [<from>] [<to>]
#%MDESC% Plot data for detector <det>, from channel <from> to <to>
#
def xiaplot '{
    if (!$#) {
        _xia_plotinit(XIA_PLOT["det"])
        _xia_plotdata(XIA_PLOT["det"], XIA_PLOT["min"], XIA_PLOT["max"])
    } else {
        _xia_plotinit($1)
        _xia_plotdata($1, $2, $3)
    }
}'


#%UU% [<min_channel> <max_channel>] [<sleep_time>]
#%MDESC% Loop on all detectors and plot its spectrum
def xiaplotloop '{
    local ich cmin cmax ctps
    cmin= 0
    cmax= 0
    ctps= 0
    if ($#==3) {
        cmin= $1
        cmax= $2
        ctps= $3
    }
    else if ($#==2) {
        cmin= $1
        cmax= $2
    }
    else if ($#==1) {
        ctps= $1
    }
    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        xiaplot XIA_DET[ich] cmin cmax
        if (!ctps)
            input(sprintf("Detector %d: ... Press Enter ...", XIA_DET[ich]))
        else    sleep(ctps)
    }
}'


#%IU%
#%MDESC% Online spec plotting init
#
def _xia_plotonlineinit '{
    if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_PLOT["online"])
        _xia_plotinit(XIA_PLOT["det"])
}'


#%IU%
#%MDESC% Online spec plotting refresh
#
def _xia_plotonlinedata '{
    if ((XIA_PAR["mode"]&XIA_MODEMCA) && XIA_PLOT["online"])
        _xia_plotdata(XIA_PLOT["det"], XIA_PLOT["min"], XIA_PLOT["max"])
}'


#%UU% [<online> [<detno> <plotmin> <plotmax> <plotlog>]]
#%MDESC%
# Selects online spec plotting for one detector
#
def xiaplotselect '{
    local ich _str_det _str
    global XIA_PLOT[]

    if ($#==1) {
        XIA_PLOT["online"]= $1
    }
    else if ($#>=4) {
        XIA_PLOT["online"]= $1
        XIA_PLOT["det"]= $2
        XIA_PLOT["min"]= $3
        XIA_PLOT["max"]= $4
        XIA_PLOT["log"]= $5
    }
    else if (!$#) {
        XIA_PLOT["online"]= yesno("Plot xia spectrum online", XIA_PLOT["online"])
        _str_det= "\n\tAvailable detectors:\n\t\t"

        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            _str_det= _str_det " " XIA_DET[ich]
        }
        print _str_det

        XIA_PLOT["det"]= getval_int("Detector number to plot", XIA_PLOT["det"])

        _str = sprintf("Start plotting channel, min=%d", XIA_PAR["chmin"])
        XIA_PLOT["min"]= getval_int(_str, XIA_PLOT["min"])

        _str = sprintf("End plotting channel, max=%d", XIA_PAR["chmax"])
        XIA_PLOT["max"]= getval_int(_str, XIA_PLOT["max"])

        XIA_PLOT["log"]= yesno("Use log scale", XIA_PLOT["log"])
    }
    else {
        print "xiaplotselect [ <online> [<det> <min> <max> [<log>] ] ]"
        print "\t<online>= 1 for spec online plotting, 0 if not"
        print "\t<det>   = detector number"
        print "\t<min>   = first channel"
        print "\t<max>   = last channel"
        print "\t<log>   = log y scale"
    }

    if (XIA_PLOT["min"]<XIA_PAR["chmin"]) XIA_PLOT["min"]=XIA_PAR["chmin"]
    if (XIA_PLOT["max"]>XIA_PAR["chmax"]) XIA_PLOT["max"]=XIA_PAR["chmax"]
    if (XIA_PAR["nbdet"]) {
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            if (XIA_DET[ich]==XIA_PLOT["det"]) break;
        }
        if (ich==XIA_PAR["nbdet"]) XIA_PLOT["det"]= XIA_DET[0]
    }
}'


# -----------------------------------------------------------------------------
# SAVING DATAFILES
# EDF xia file headers:
#     xtype= board type
#       xtime= counting time
#       xmin/xmax= channel range
#       xcfg= DSP config filename
#       xdata= (bit_1: ct/scan, bit_2: mca/stat, bit_3: sum)
#       xcorr= (bit_1: dt, bit_2: lvt)
#       xnb= number of detectors/sums
#       xdet= detector(s) number
# -----------------------------------------------------------------------------

#%UU% <directory> <file_radix>
#%MDESC%
#    Changes/Defines file path to save data. Checks if local file in
#    ok and displays next saving file.
#  -MODEMCA or MODEMAP:
#      => saves on windows pc in XIA_SAVE["mapdir"]/XIA_SAVE["mapfile"]
#  -SCAMODE:
#      => saves via SPEC on local PC in XIA_SAVE["dir"]/XIA_SAVE["radix"]
#
def xianewfile '{
    global XIA_SAVE[]
    local xdir xradix msg chg _cmd
    chg= 1

    if ($#!=2) {
        printf("- Saving path: \n")
        if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
            xdir   = XIA_SAVE["mapdir"]
            xradix = XIA_SAVE["mapfile"]
        }
        else {
            xdir   = XIA_SAVE["dir"]
            xradix = XIA_SAVE["radix"]
        }
        xdir   = getval_check_path("\t- directory  ", xdir)
        xradix = getval_check("\t- file radix ", xradix)
        }
    else {
        xdir   = "$1"
        xradix = "$2"
    }

    if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
        if (_xia_setfilepar(xdir, xradix, 0, 0, 0, XIA_SAVE["mapauto"], 0))
            _xia_print("Next ZAP files (saved by Device Server on windows PC)", \
                       sprintf("\n      %s", _xia_getfilename("XX", 0)))
    }
    else {
        if (!file_info(xdir, "isdir")) {
            if (!file_info(xdir, "isreg")) {
                printf("Directory <%s> does not exist !!\n", xdir)
                if (yesno("==> Create it", 1)) {
                    unix(sprintf("mkdir -p %s", xdir))
                    if (!file_info(xdir, "isdir")) {
                        _xia_print("NewFile", "Cannot create directory", 1)
                        chg= 0
                    }
                }
                else {
                    chg= 0
                }
            }
            else {
                _xia_print("NewFile", "Directory is a file !!!", 1)
                chg= 0
            }
        }

        if (chg) {
            XIA_SAVE["dir"]   = xdir
            XIA_SAVE["radix"] = xradix
            _cmd = sprintf("exit `ls %s/%s_xia[sc]*_*_*.edf 2> /dev/null | wc -l`", \
                           xdir, xradix)
            XIA_SAVE["num"]   = unix(_cmd)
        }

        if (XIA_SAVE["radix"]) {
            _xia_print("Next step-scan/count file saved by SPEC on linux PC", \
                       _xia_getfilename("XX", 0))
        }
    }
}'


#%UU%
#%MDESC%
# User hook macros to set edf header in mapping mode (when files are
# saved by device server).
#%BR% User has to fill associative array %B%XIA_HEADER%B%
#%BR% Example:
#%BR% XIA_HEADER["theta"]= 23.5
#%BR% XIA_HEADER["expname"]= "name of the experiment"
def user_xia_map_header ''


#%UU%
#%MDESC%
# User hook macros to set edf header in normal mode (when files are
# saved by spec) (not in zapscan)
#%BR% User has to fill associative array %B%XIA_HEADER%B%
#%BR% Example:
#%BR% XIA_HEADER["theta"]= 23.5
#%BR% XIA_HEADER["expname"]= "name of the experiment"
def user_xia_header ''


#%UU%
#%MDESC% Save last acquisition (xiaacq or ct)
#
def xiasave '{
    local fname ich name idet sname sdet nbf nhead
    xia_dbg("xiasave")

    if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
        xia_dbg(sprintf("xiasave: XIA_MODEMCA|XIA_MODEMAP=%s", XIA_MODEMCA|XIA_MODEMAP))
        if (XIA_SAVE["mapfile"]) {
            xia_dbg(sprintf("xiasave: XIA_SAVE[mapfile]=%s", XIA_SAVE["mapfile"]))
            global XIA_MAP_HEADER[] # header send to DS
            unglobal XIA_HEADER
            global XIA_HEADER[]     # user-filled header

            user_xia_map_header
            nhead= 0
            for (name in XIA_HEADER) {
                XIA_MAP_HEADER[nhead++]= name " = " XIA_HEADER[name]
                xia_dbg(sprintf("xiasave : xia_header : %s", XIA_MAP_HEADER[nhead-1]))
            }

            if (nhead) {
                # printf("size of XIA_MAP_HEADER : %g\n", ass_arr_size(XIA_MAP_HEADER))
                esrf_io(XIA_DEV, "DevXiaSetHeader", XIA_MAP_HEADER)
                xia_dbg("xiasave: mapping mode : DevXiaSetHeader")
                xia_dbg(ass_arr2string(XIA_MAP_HEADER, "* "))
            }

            # Asks server to save.
            # Checks of end of saving is done at begining of next line.
            nbf= esrf_io(XIA_DEV, "DevXiaSave")

            _xia_print("Save", sprintf("Saved %d files by server", nbf))
            unglobal XIA_HEADER XIA_MAP_HEADER
        }
        else {
            _xia_print("Save", "No filename defined. Use xianewfile.", 1)
        }
    }
    else if (XIA_SAVE["radix"]) {
        # --- Save one file with all spectrums
        fname= _xia_getfilename("ct")
        xia_dbg(sprintf("xiasave: step mode : fname = %s", fname))

        _xia_saveheader

        if (_xia_iscorrsaved()) {
            xia_dbg("xiasave: saving corrected data")
            fmt_write(fname, "ESRF", XIA_CORRDATA[1:XIA_PAR["nbdet"]], XIA_HEADER)
        } else {
            fmt_write(fname, "ESRF", XIA_DATA[1:XIA_PAR["nbdet"]], XIA_HEADER)
            xia_dbg("xiasave: saving data")
        }

        # --- Save detector sums in separate file
        if (XIA_SAVE["sum"] && (list_n(XIA_SUM)>0)) {
            XIA_HEADER["xdata"]= (1<<2)
            XIA_HEADER["xnb"]= list_n(XIA_SUM)
            delete XIA_HEADER["xdet"]
            for (ich=0; ich<list_n(XIA_SUM); ich++) {
                name= list_item(XIA_SUM, ich+1)
                sdet= ""
                for (idet=0; idet<XIA_SUM[name]["nbdet"]; idet++) {
                    sdet= sdet sprintf("%d ", XIA_SUM[name][idet])
                }
                XIA_HEADER[sprintf("xdet%d", ich)]= sdet
                XIA_HEADER[sprintf("xcorr%d", ich)]= XIA_SUM[name]["dt"] | \
                    (XIA_SUM[name]["lvt"]<<1)
            }
            sname= _xia_getfilename("SN")
            fmt_write(sname, "ESRF", XIA_SUMDATA, XIA_HEADER)
        }
    
        _xia_print("Save", fname)
        XIA_SAVE["num"]++
        unglobal XIA_HEADER
    }
    else {
        _xia_print("Save", "No filename defined. Use xianewfile.", 1)
    }
}'


#%IU% (det)
#%MDESC% Get filename depending on mode and usage.
# In mapping mode, file names are forged by DS.
# <det>:
#  -"ct"    : SCAMODE file name
#  -"SN"    : Sum Name.
#  -"XX"    : generic name for spectra.
#  -"st"    : stat
#  -default : <det> is a detector number.
#
# <sidx> : second index for mesh-like scans.
#
def _xia_getfilename(det, sidx) '{
    local filename idet

    if (det=="ct" || det=="SN") {
        filename= sprintf("%s/%s_xia%s_%04d_0000_0000.edf", XIA_SAVE["dir"], \
                          XIA_SAVE["radix"], det, XIA_SAVE["num"])
    }
    else if (det=="XX") {
        if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
            filename= sprintf("%s/%s_xiaXX_%04d_0000_XXXX.edf", XIA_SAVE["mapdir"], \
                              XIA_SAVE["mapfile"], XIA_SAVE["num"])
        }
        else{
            filename= sprintf("%s/%s_xiaXX_%04d_0000_XXXX.edf", XIA_SAVE["dir"], \
                              XIA_SAVE["radix"], XIA_SAVE["num"])
        }
    }
    else if (det=="st") {
        filename= sprintf("%s/%s_xiast_%04d_0000_%04d.edf", XIA_SAVE["dir"], \
                    XIA_SAVE["radix"], XIA_SAVE["num"], sidx)
    }
    else {
        idet= int(det)
        if (idet<0) {
            filename= sprintf("%s/%s_xiaS%d_%04d_0000_%04d.edf", XIA_SAVE["dir"], \
                              XIA_SAVE["radix"], -1*idet, XIA_SAVE["num"], sidx)
        }
        else {
            filename= sprintf("%s/%s_xia%02d_%04d_0000_%04d.edf", XIA_SAVE["dir"], \
                              XIA_SAVE["radix"], XIA_DET[idet], XIA_SAVE["num"], sidx)
        }
    }
    return(filename)
}'


#%UU%
#%MDESC%  Setup save during scans / save after ct/xiaacq (not in zapscan).
#-XIA_SAVE["mapauto"] : in MCA or MAPPING mode.
#-XIA_SAVE["scan"]    : after a scan.
#-XIA_SAVE["ct"]      : after a count.
def xiasavesetup '{
    global XIA_SAVE[]
    local _str

    if (XIA_PAR["mode"]==(XIA_MODEMCA|XIA_MODEMAP)) {
        _str = "- DS Autosave spectrums/stats at the end of run"
        XIA_SAVE["mapauto"]= yesno(_str, XIA_SAVE["mapauto"])
        xianewfile
    }
    else {
        XIA_SAVE["scan"] = yesno("- SPEC Save spectrums during scans", XIA_SAVE["scan"])
        XIA_SAVE["ct"]   = yesno("- SPEC Save spectrums after ct/xiaacq", XIA_SAVE["ct"])
        if (list_n(XIA_SUM)>0) {
            XIA_SAVE["sum"]= yesno("- SPEC Save also detector sums", XIA_SAVE["sum"])
        }
        if (XIA_SAVE["scan"] || XIA_SAVE["ct"]) {
            xianewfile
        }
    }
}'


#%IU%
#%MDESC%
def _xia_savescaninit '{

    local np ich arrname

    global XIA_HEADER[]

    XIA_HEADER["ScanFile"]= DATAFILE
    XIA_HEADER["ScanNumber"]= SCAN_N
    XIA_HEADER["ScanPoint"]= NPTS
    XIA_HEADER["xtype"]= XIA_MSG["type"][XIA_PAR["type"]]
    XIA_HEADER["xcfg"]= XIA_PAR["dxp"]?XIA_PAR["dxp"]:"default"
    XIA_HEADER["xmin"]= sprintf("%d", XIA_PAR["chmin"])
    XIA_HEADER["xmax"]= sprintf("%d", XIA_PAR["chmax"])

    if (_n1 == 0){
        np = array_op("rows", SCAN_D)
    }
    else{
        np = _n1
    }

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        arrname= sprintf("XIA_DATA_SAVE%d", ich)
    if (_xia_iscorrsaved()) {
        double array @arrname[np][XIA_PAR["chlen"]]
    } else {
            ulong array @arrname[np][XIA_PAR["chlen"]]
    }
        @arrname= 0
    }
    ulong array XIA_STAT_SAVE[np][XIA_PAR["nbdet"]*6]

    if (XIA_SAVE["sum"] && (list_n(XIA_SUM)>0)) {
        for (ich=0; ich<=list_n(XIA_SUM); ich++) {
            arrname= sprintf("XIA_SUMDATA_SAVE%d", ich)
            double array @arrname[np][XIA_PAR["chlen"]]
        }
    }

    user_xia_header
}'


#%IU%
#%MDESC%
def _xia_savescandata '{
    global TTT[]
    local ich arrname idx

    # idx = _g1 if mesh scan (line number for mesh/grid scans)
    #       NPTS otherwise (point number)
    idx = (_stype&8) ? _g1 : NPTS

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        arrname= sprintf("XIA_DATA_SAVE%d", ich)
        if (_xia_iscorrsaved()) {
            @arrname[idx][]= XIA_CORRDATA[ich+1][]
        } else {
            @arrname[idx][]= XIA_DATA[ich+1][]
        }
    }
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            XIA_STAT_SAVE[idx][6*ich:6*ich+5]= XIA_STAT[ich][0:5]
        }
    if (XIA_SAVE["sum"] && (list_n(XIA_SUM)>0)) {
        for (ich=0; ich<list_n(XIA_SUM); ich++) {
        arrname= sprintf("XIA_SUMDATA_SAVE%d", ich)
        @arrname[idx][]= XIA_SUMDATA[ich][]
        }
    }

    # if mesh
    if (_stype&8){
        # if last point of a mesh line
        if (_g1 == (_n1-1)) {
            if( XIA_PAR["spec_v_sup_64"]){
                # NEW SPEC
                # but not last line of a mesh.
                if(_g2 != (_n1 * _n2 - 1)) {
                    # do not save last line of a mesh.
                    _xia_savescanfile
                }
            }
            else{
                # OLD SPEC
                # buit not last line of a mesh.
                if(_g2 != (_n2-1)){
                    # do not save last line of a mesh.
                    _xia_savescanfile
                }
            }
        }
    }
}'


#%IU%
#%MDESC%
def _xia_savescanfile '{
    local ich arrname fname name idet sidx nrow

    if (XIA_SAVE["radix"]) {
        # --- second index for mesh-like scans
        if (_stype & 8) {
            # in a mesh
            nrow= (_g1==_n1) ? _n1-1 : _g1
            if (XIA_PAR["spec_v_sup_64"]){
                sidx = int (_g2/ _n1)
            }
            else{
                sidx = (_g2==_n2) ? _n2-1 : _g2
            }
        }
        else {
            nrow= NPTS-1
            sidx= 0
        }

        xia_dbg(sprintf("_xia_savescanfile : nrow=%d sidx=%d   _g1=%d _g2=%d  ", nrow, sidx, _g1, _g2 ))

        # --- Save spectrums for all det
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            fname= _xia_getfilename(ich, sidx)
            arrname= sprintf("XIA_DATA_SAVE%d", ich)
        XIA_HEADER["xnb"]= 1
            XIA_HEADER["xdata"]= 1
            XIA_HEADER["xdet"]= sprintf("%d", XIA_DET[ich])
        if (_xia_iscorrsaved()) {
        XIA_HEADER["xcorr"]= XIA_CORR["dt"] | (XIA_CORR["lvt"]<<1) | (XIA_CORR["mon"]<<2)
        } else {
        XIA_HEADER["xcorr"]= 0
        }
            fmt_write(fname, "ESRF", @arrname[0:nrow][], XIA_HEADER)
        delete XIA_HEADER["xcorr"]
        }

        # --- Save statistics in separate file
        XIA_HEADER["xnb"]= sprintf("%d", XIA_PAR["nbdet"])
        XIA_HEADER["xdata"]= (1<<0) | (1<<1)
        XIA_HEADER["xdet"]= ""
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            XIA_HEADER["xdet"]= XIA_HEADER["xdet"] sprintf("%d ", XIA_DET[ich])
        }
        fname= _xia_getfilename("st", sidx)
        fmt_write(fname, "ESRF", XIA_STAT_SAVE[0:nrow][], XIA_HEADER)

        # --- Save detector sums in separate files
        if (XIA_SAVE["sum"] && (list_n(XIA_SUM)>0)) {
            XIA_HEADER["xnb"]= 1
            XIA_HEADER["xdata"]= (1<<0) | (1<<2)
            for (ich=0; ich<list_n(XIA_SUM); ich++) {
                name= list_item(XIA_SUM, ich+1)
                XIA_HEADER["xdet"]= ""
                for (idet=0; idet<XIA_SUM[name]["nbdet"]; idet++) {
                    XIA_HEADER["xdet"]= XIA_HEADER["xdet"] sprintf("%d ", XIA_SUM[name][idet])
                }
                XIA_HEADER["xcorr"]= XIA_SUM[name]["dt"] | (XIA_SUM[name]["lvt"]<<1)

            name= _xia_getfilename(-1*(ich+1), sidx)
            arrname= sprintf("XIA_SUMDATA_SAVE%d", ich)
            fmt_write(name, "ESRF", @arrname[0:nrow][], XIA_HEADER)
            }
        delete XIA_HEADER["xcorr"]
        }

        _xia_print("Save", fname)

        if (NPTS >= (_stype & 8 ? _n1*_n2:_n1)){
            XIA_SAVE["num"]++
        }
    }
    else {
        _xia_print("Save", "No filename defined. Use xianewfile.", 1)
    }
}'


#%IU%
#%MDESC%
def _xia_saveheader '{
    local ich det
    global XIA_HEADER[]

        XIA_HEADER["xtime"]= COUNT_TIME
        XIA_HEADER["xtype"]= XIA_MSG["type"][XIA_PAR["type"]]
        XIA_HEADER["xdata"]= 0
    XIA_HEADER["xcfg"]= XIA_PAR["dxp"]?XIA_PAR["dxp"]:"default"
    XIA_HEADER["xnb"]= sprintf("%d", XIA_PAR["nbdet"])
        XIA_HEADER["xmin"]= sprintf("%d", XIA_PAR["chmin"])
        XIA_HEADER["xmax"]= sprintf("%d", XIA_PAR["chmax"])
        XIA_HEADER["xdet"]= ""

    if (_xia_iscorrsaved()) {
        XIA_HEADER["xcorr"]= (XIA_CORR["mon"]<<2) | (XIA_CORR["lvt"]<<1) | XIA_CORR["dt"]
        if (XIA_CORR["mon"] && (!XIA_CORR["inacq"])) {
        XIA_HEADER["xmonrate"]= XIA_CORR["mrate"]
        }
    } else {
        XIA_HEADER["xcorr"]= 0
    }

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            det= XIA_DET[ich]
            XIA_HEADER["xdet"]= XIA_HEADER["xdet"] sprintf("%d ", det)
            XIA_HEADER[sprintf("xevt%02d", det)]= sprintf("%d", XIA_STAT[ich][1])
            XIA_HEADER[sprintf("xicr%02d", det)]= sprintf("%d", XIA_STAT[ich][2])
            XIA_HEADER[sprintf("xocr%02d", det)]= sprintf("%d", XIA_STAT[ich][3])
            XIA_HEADER[sprintf("xlt%02d", det)]= sprintf("%d", XIA_STAT[ich][4])
            XIA_HEADER[sprintf("xdt%02d", det)]= sprintf("%d", XIA_STAT[ich][5])
    }
    user_xia_header
}'


#%IU%
#%MDESC%
def _xia_saveroiheader '{
    local roi mne

    printf("#@XIAFILE %s\n", _xia_getfilename("XX", 0))
    for (roi=1; roi<=list_n(XIA_ROI); roi++) {
    mne= list_item(XIA_ROI, roi)
    printf("#@XIAROI %s %d %d %d %d %d \n", mne, XIA_ROI[mne]["det"], \
        XIA_ROI[mne]["min"], XIA_ROI[mne]["max"], \
        XIA_ROI[mne]["lvt"], XIA_ROI[mne]["dt"])
     }
}'


#%IU% (<directory>, <radix>, <num0>, <num1>, <num2>, <auto>)
#%MDESC%
#    Sets file parameters to device server for MCAMAP mode
#%BR% %B%directory%B%: windows directory
#%BR% %B%radix%B%: file radix
#%BR% %B%num0,1,2%B%: file numbers as in zap macros
#%BR% %B%auto%B%: autosave files at the end of run
#%BR% %B%bidirect%B%: bidirectionnal scans (zap option)
#
def _xia_setfilepar(directory, radix, num0, num1, num2, auto, bidirect) '{
    local inarr[]
    inarr[0]= directory
    inarr[1]= radix
    inarr[2]= sprintf("%d", num0)
    inarr[3]= sprintf("%d", num1)
    inarr[4]= sprintf("%d", num2)
    inarr[5]= sprintf("%d", auto|(bidirect<<1))

    if (esrf_io(XIA_DEV, "DevXiaSetFilePar", inarr)==-1) {
        _xia_print("SetFilePar", "Failed to set file parameters to DS")
        return (0)
    }

    return _xia_getfilepar()
}'


#%IU% ()
#%MDESC% Read back file parameters from device server (store in %B%XIA_SAVE%B%)
#
def _xia_getfilepar() '{
    local outarr[]

    if (esrf_io(XIA_DEV, "DevXiaGetFilePar", outarr)==-1) {
        _xia_print("GetFilePar", "Failed to get file parameters from DS", 1)
        return (0)
    }

    XIA_SAVE["mapdir"]= outarr[0]
    XIA_SAVE["mapfile"]= outarr[1]
    XIA_SAVE["mapnum0"]= outarr[2]
    XIA_SAVE["mapnum1"]= outarr[3]
    XIA_SAVE["mapnum2"]= outarr[4]
    XIA_SAVE["mapauto"]= int(outarr[5])&0x1
    XIA_SAVE["mapbidirect"]= int(outarr[5])&0x2

    return (1)
}'



######################################################################
#############################            #############################
#############################  COUNTERS  #############################
#############################            #############################
######################################################################


#%UU%
#%MDESC% Display XIA counters configured in current spec session
#
def xiacntshow '{
    local cntbase ich str icnt

    cntbase[0]= "xicr"
    cntbase[1]= "xocr"
    cntbase[2]= "xlt"
    cntbase[3]= "xdt"

    tty_cntl("md"); printf("\n<XIA Counters configuration>\n"); tty_cntl("me")

    printf("\nDet.|   ICR    |   OCR    | LiveTime | DeadTime |")
    printf("\n    | (xicrNN) | (xocrNN) | (xltNN)  | (xdtNN)  |")
    printf("\n----|----------|----------|----------|----------|\n")

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        str= sprintf(" %2d ", XIA_DET[ich])
        for (icnt=0; icnt<4; icnt++) {
            str= str sprintf("|   %3s    ", \
                  cnt_num(sprintf("%s%02d", cntbase[icnt], XIA_DET[ich]))==-1?" no":"yes")
        }
        printf("%s|\n", str)
    }

    printf("----|----------|----------|----------|----------|\n")
    if (XIA_PAR["nbdet"]>2) {
        str= "Avg "
        if (XIA_PAR["cntset"] && XIA_PAR["cntdet"]!=-1) {
            str= sprintf("*%2d*", XIA_DET[XIA_PAR["cntdet"]])
        }
        for (icnt=0; icnt<4; icnt++) {
            str= str sprintf("|   %3s    ", \
                cnt_num(cntbase[icnt])==-1?" no":"yes")
        }
        printf("%s|\n", str)
    }

    printf("\n\nTo enable a counter, just define it in spec config.\n\n")
}'


#%UU% [<-1(average)|detector_number>]
#%MDESC%
# Change common counters assignation (xocr, xicr, xlt, xdt)
#%BR% Common counters can be assigned to either -1=Average on all detectors or <detector_number>
#
def xiacntassign '{
    local val old idx

    if (!$#) {
        old= XIA_PAR["cntset"]?XIA_DET[XIA_PAR["cntdet"]]:-1
        print "Assign common counters (xocr, xicr, xlt, xdt) to :"
        val= getval_int ("    Average on all detectors <-1> or one detector <number>", old)
    }
    else {
        val= int($1)
    }
    if (val!=-1) {
        if ((idx=_xia_getdetidx(val))==-1) {
            _xia_print("CntAssign", sprintf("Cannot find detector <%d>. Assign to average.", val), 1)
        }
    }
    else {
        idx= -1
    }
    XIA_PAR["cntset"]= 1
    XIA_PAR["cntdet"]= idx
}'


#%IU%
#%MDESC% Checks cnt assigned if it is still in detectors configured. Used after config changed.
#
def _xia_checkcnt '{
    if (XIA_PAR["cntset"] && XIA_PAR["cntdet"]!=-1) {
        if (XIA_PAR["cntdet"]>=XIA_PAR["nbdet"])
            XIA_PAR["cntdet"]= -1
    }
}'

# ---------------------------------------------------------
# COUNTERS DISABLE/ENABLE
# ---------------------------------------------------------

#%UU%
#%MDESC%
# Disable all xia counters (statistics and rois counters)
#
def xiacntdisable '{
    local icnt iroi roimne num
    for (icnt=1; icnt<COUNTERS; icnt++) {
       if (index(cnt_mne(icnt), "xicr")==1) counter_par(icnt, "disable", 1)
       if (index(cnt_mne(icnt), "xocr")==1) counter_par(icnt, "disable", 1)
       if (index(cnt_mne(icnt), "xdt")==1) counter_par(icnt, "disable", 1)
       if (index(cnt_mne(icnt), "xlt")==1) counter_par(icnt, "disable", 1)
    }

    for (iroi=1; iroi<=list_n(XIA_ROI); iroi++) {
        roimne= list_item(XIA_ROI, iroi)
    if ((num=cnt_num(roimne))!=-1) {
        counter_par(cnt_num(roimne), "disable", 1)
        }
    }
}'


#%UU%
#%MDESC%
# Enable all xia counters (statistics and rois counters) %BR%
# for all currently configured detectors
#
def xiacntenable '{
    local ich num iroi roimne state

    # --- disable all
    xiacntdisable

    # --- enable only for configured dets
    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        if ((num=cnt_num(sprintf("xicr%02d", XIA_DET[ich])))!=-1)
        counter_par(num, "disable", 0)
        if ((num=cnt_num(sprintf("xocr%02d", XIA_DET[ich])))!=-1)
        counter_par(num, "disable", 0)
        if ((num=cnt_num(sprintf("xlt%02d", XIA_DET[ich])))!=-1)
        counter_par(num, "disable", 0)
        if ((num=cnt_num(sprintf("xdt%02d", XIA_DET[ich])))!=-1)
        counter_par(num, "disable", 0)
    }
    if ((num=cnt_num("xicr"))!=-1) counter_par(num, "disable", 0)
    if ((num=cnt_num("xocr"))!=-1) counter_par(num, "disable", 0)
    if ((num=cnt_num("xdt"))!=-1) counter_par(num, "disable", 0)
    if ((num=cnt_num("xlt"))!=-1) counter_par(num, "disable", 0)

    for (iroi=1; iroi<=list_n(XIA_ROI); iroi++) {
        roimne= list_item(XIA_ROI, iroi)
        if ((num=cnt_num(roimne))!=-1) {
            if ((XIA_ROI[roimne]["det"]==-1) || (XIA_ROI[roimne]["det"]==-2))
                state= 0
            else
                state= (_xia_getdetidx(XIA_ROI[roimne]["det"])==-1)
            counter_par(num, "disable", state)
        }
    }
}'



######################################################################
################################       ###############################
################################  ROI  ###############################
################################       ###############################
######################################################################

#%IU%
#%MDESC% Remove roi definition
def _xia_roiremove(cmne) '{
    local sidx ich iroi

    if (cmne=="*") {
        _xia_roiremoveall()
    }
    else if ((sidx=index(cmne, "*"))>0) {

        cmne= substr(cmne, 1, sidx-1)

        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            _xia_roiremovesingle(sprintf("%s%02d", cmne, XIA_DET[ich]))
    }

        _xia_roiremovesingle(sprintf("%sAvg", cmne))
        _xia_roiremovesingle(sprintf("%sSum", cmne))
    }
    else {
        _xia_roiremovesingle(cmne)
    }
}'


#%IU%
#%MDESC% user hook macro called each time a roi has been removed
#%BR% First parameter sent ($1) is the roi mnemonic
def user_xia_roi_remove '{
    local __param__

    __param__ = $1
}'


#cdef("user_xia_roi_remove", "", "", "")


#%IU%
#%MDESC% Remove one roi and call user hook
def _xia_roiremovesingle(cmne) '{
    if (list_check(XIA_ROI, cmne) > 0) {
        user_xia_roi_remove cmne
            list_remove(XIA_ROI, cmne)
        }
}'


#%IU%
#%MDESC% Remove all roi and call user hook
def _xia_roiremoveall() '{
    local iroi roimne

    for (iroi=1 ; iroi<=list_n(XIA_ROI) ; iroi++) {
        roimne = sprintf("%s",list_item(XIA_ROI, iroi))
        user_xia_roi_remove roimne
    }

    list_init XIA_ROI
}'


#%UU%
#%MDESC% Menu to Add/Modify/Delete/Save/Load rois
#
def xiaroimenu '{
    local mode
    mode= XIA_PAR["mode"]
    if (mode == XIA_MODEHWSCA)
        _xia_hwscamenu
    else
        _xia_roimenu
}'

def _xia_roimenu '{
    local nb key ans upd
    local cmne cdet cmin cmax clvt cdt norm imne
    local cdis ndis ddis ii sidx det_type

    upd= 0

    while (1) {
    nb= _xia_roishow()
    tty_move(0,nb++, "\[md\]A\[se\]dd/\[md\]R\[se\]emove/\[md\]M\[se\]odify ROI(s),")
    tty_move(0,nb++, "\[md\]D\[se\]isable/\[md\]E\[se\]nable Detector,")
    tty_move(0,nb++, "\[md\]L\[se\]oad from/\[md\]S\[se\]ave to file,  or \[md\]Q\[se\]uit ? ")


#    August 6, 2017 - RELEASE 6.06.04
#    "IMPROVEMENTS":   Line Editing For input(), yesno(), getval() and getsval()
#
# DOES NOT WORK ANYMORE :(
#    while ((pressed_key=input(-1))=="") {}

    print("\n\n")
    key = getval_one_char("enter key (a, r, m, d, e, l, s, q)")
    printf("\n\n")

    if (key=="q"||key=="Q"){
        break
    }
    else if (key=="r"||key=="R") {
        cmne= getval("Counter mnemonic (\"*\" to remove all)",0)
        if (cmne!="0") _xia_roiremove(cmne)
        upd= 1
    }
    else if (key=="a"||key=="A") {
        printf("\n 1) Add a single detector ROI")
        printf("\n 2) Add same ROI an ALL detectors")
        printf("\n 3) Add an AVG ROI (average on ROIs with a given prefix name)")
        printf("\n 4) Add an SUM ROI (sum on ROIs with a given prefix name)")
        ans= getval("\n > Roi type", 0)
        if (ans==1) {
            cmne= getval(" > Counter mnemonic    ", 0)
            if (cmne) {
                cdet= getval(" > Detector number     ", 0)
                cmin= getval(" > First channel       ", XIA_PAR["chmin"])
                cmax= getval(" > Last channel        ", XIA_PAR["chmax"])
                clvt= yesno (" > LiveTime correction ", 0)
                cdt = yesno (" > DeadTime correction ", 0)
                norm= getval(" > Normalize by a given counter [0 for none]", 0)
                _xia_roiadd(cmne, cdet, cmin, cmax, clvt, cdt, norm)
                upd= 1
            }
        }
        else if (ans==2) {
            cmne= getval(" > Counter mnemonic prefix ", 0)
            if (cmne) {
                cmin= getval(" > First channel           ", XIA_PAR["chmin"])
                cmax= getval(" > Last channel            ", XIA_PAR["chmax"])
                clvt= yesno (" > LiveTime correction     ", 0)
                cdt = yesno (" > DeadTime correction     ", 0)
                norm= getval(" > Normalize by a given counter [0 for none]", 0)
                _xia_roiadd(cmne, "all", cmin, cmax, clvt, cdt, norm)
                upd= 1
            }
        }
        else if (ans==3) {
            cmne= getval(" > Counter mnemonic prefix ", 0)
            if (cmne) _xia_roiadd(cmne, "avg")
        }
        else if (ans==4) {
            cmne= getval(" > Counter mnemonic prefix ", 0)
            if (cmne) _xia_roiadd(cmne, "sum")
        }
    }
    else if (key=="m"||key=="M") {
        cmne= getval(" > Counter mnemonic (use \"*\" to select many counters)", 0)
        if ((sidx=index(cmne,"*"))>0) {
            cmne= substr(cmne, 1, sidx-1)
            for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
                if (list_check(XIA_ROI, sprintf("%s%02d", cmne, XIA_DET[ich]))>0) {
                    imne= sprintf("%s%02d", cmne, XIA_DET[ich])
                    cmin= XIA_ROI[imne]["min"]
                    cmax= XIA_ROI[imne]["max"]
                    clvt= XIA_ROI[cmne]["lvt"]
                    cdt= XIA_ROI[cmne]["dt"]
                    norm= XIA_ROI[cmne]["norm"]
                    upd= 1
                    break;
                }
            }
            if (ich==XIA_PAR["nbdet"]) {
                printf("\nNO ROI beginning with <%s> has been found", cmne)
                input("... Press Enter ...")
            }
            else {
                cmin= getval(" > First channel           ", cmin)
                cmax= getval(" > Last channel            ", cmax)
                clvt= yesno (" > LiveTime correction     ", clvt)
                cdt = yesno (" > DeadTime correction     ", cdt)
                norm= getval(" > Normalize by a given counter [0 for none]", norm)
                for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
                    imne= sprintf("%s%02d", cmne, XIA_DET[ich])
                    if (list_check(XIA_ROI, imne)>0) {
                        XIA_ROI[imne]["min"]= cmin
                        XIA_ROI[imne]["max"]= cmax
                        XIA_ROI[imne]["lvt"]= clvt
                        XIA_ROI[imne]["dt"]= cdt
                        XIA_ROI[imne]["norm"]= norm
                        upd= 1
                    }
                }
            }
        }
        else if (list_check(XIA_ROI, cmne)>0) {
            if (XIA_ROI[cmne]["det"] < 0) {
                norm= getval(" > Counter mnemonic prefix ", XIA_ROI[cmne]["norm"])
                if (norm!=XIA_ROI[cmne]["norm"]) {
                    det_type = XIA_ROI[cmne]["det"]
                    _xia_roiremove(cmne)
                    if (norm) {
                        if (det_type == -1)
                             _xia_roiadd(norm, "avg")
                        if (det_type == -2)
                             _xia_roiadd(norm, "sum")
                    }

                }
            }
            else {
                XIA_ROI[cmne]["det"]= getval_int(" > Detector number        ", XIA_ROI[cmne]["det"])
                XIA_ROI[cmne]["min"]= getval_int(" > First channel          ", XIA_ROI[cmne]["min"])
                XIA_ROI[cmne]["max"]= getval_int(" > Last channel           ", XIA_ROI[cmne]["max"])
                XIA_ROI[cmne]["lvt"]= yesno (" > LiveTime correction    ", XIA_ROI[cmne]["lvt"])
                XIA_ROI[cmne]["dt"]= yesno  (" > DeadTime correction    ", XIA_ROI[cmne]["dt"])
                XIA_ROI[cmne]["norm"]= getval(" > Normalize by counter [0 for none]", XIA_ROI[cmne]["norm"])
                upd= 1
            }
        }
    }
    else if (key=="d"||key=="D") {
        cdis= getval("Enter Detector numbers to disable separated by space [0 for none]", 0)
        xiadetenable all
        if (cdis!=0) {
            ndis= split(cdis, ddis)
            for (ii=0; ii<ndis; ii++)
                xiadetdisable ddis[ii]
        }
    }
    else if (key=="e"||key=="E") {
        cdis= getval("Enter Detector numbers to enable separated by space [0 for none]", 0)
        xiadetdisable all
        if (cdis!=0) {
            ndis= split(cdis, ddis)
            for (ii=0; ii<ndis; ii++)
                xiadetenable ddis[ii]
        }
    }
    else if (key=="s"||key=="S") {
        file= getval("Save ROIs to file [0:default file]", 0)

        if (file=="0") xiaroisave
        else eval(sprintf("xiaroisave %s", file))

        input("... Press Enter ...")
    }
    else if (key=="l"||key=="L") {

        xiaroiload
        input("... Press Enter ...")
    }
    }

    if (upd && ((XIA_PAR["type"]==3)||(XIA_PAR["mode"]&XIA_MODESCA)||(XIA_PAR["mode"]&XIA_MODEMAP)))
        _xia_roitosca()
}'


#%UU% [<filename>]
#%MDESC% Saves rois definition in a file. If <filename> is not specified,
# saves to a default file.
def xiaroisave '{
    local saving_dir filename mne roi rmne

    saving_dir = sprintf("%s/local/spec/userconf/xiaroi", BLISSADM)

    if ($#==1) {
        if(index("$1", "/") > 0) {
            print "usage :"
            print "   xiaroisave [<filename>]"
            print "   <filename> : a single file name (no directories)."
            print "   saving directory is ", saving_dir
            exit
        }
        filename= sprintf("%s/%s", saving_dir, "$1")
    }
    else {
        # default saving file.
        filename= sprintf("%s/xiaroi.def.%s", saving_dir, USER)
    }

    # Moves ROI file if it exists
    if (!unix(sprintf("test -r %s", filename))) {
        _xia_print("ROI", sprintf("Archiving old file to %s.bup", filename))
        unix(sprintf("/bin/mv %s %s.bup",filename, filename))
    }

    # Tests if default saving dir exists.
    if (file_info(saving_dir) == 0){
        _msg = sprintf("Saving directory (%s/) does not exist.", saving_dir)
        _xia_print("xiaroisave", _msg, 1)
        exit
    }

    # Opens file to write.
    if (on(filename) == -1) {
        _xia_print("Error", sprintf("Cannot open file %s", filename), 1)
    }
    else {
        offt
        printf("# -------- XIA ROIs ----------\n")
        printf("# name det min max lvt dt norm\n")
        for (roi=1; roi<=list_n(XIA_ROI); roi++) {
            mne= list_item(XIA_ROI, roi)
            printf("%s %d %d %d %d %d %s \n", mne, XIA_ROI[mne]["det"], \
                   XIA_ROI[mne]["min"], XIA_ROI[mne]["max"], \
                   XIA_ROI[mne]["lvt"], XIA_ROI[mne]["dt"], \
                   XIA_ROI[mne]["norm"]==0?"-":XIA_ROI[mne]["norm"])
        }
        ont; close(filename)
        _xia_print("ROI", sprintf("Saved to %s", filename))
    }
}'


#%UU% [<filename>]
#%MDESC% Load rois from a file. If <filename> is not specified, load from the standard location
#%BR% Loading rois from file will erase current roi settings.
def xiaroiload '{
    local filename line pars[]
    local cmne cdet cmin cmax cnorm iroi
    local ls_res  _ans  nb_files  saving_dir

    local roi_files[]
    roi_files[0] = 0

    saving_dir = sprintf("%s/local/spec/userconf/xiaroi", BLISSADM)

    if ($#==1){
        if(index("$1", "/") > 0) {
            print "usage :"
            print "   xiaroiload [<filename>]"
            print "   <filename> : file name containing ROI to load (no directories)."
            exit
        }
        filename = sprintf("%s/%s", saving_dir, "$1")
    }
    else{
        if (file_info(saving_dir, "isdir") == 0) {
            _xia_print("xiaroiload", sprintf("%s directory does not exist", saving_dir), 1)
            exit
        }

        roi_files = list_dir(saving_dir)
        nb_files = ass_arr_nb_key(roi_files)
        printf("Found %d file(s) in %s/ :\n", nb_files, saving_dir)
        _ans = getval_list_by_key("\nChoose a file to load XIA ROI", roi_files, 0)
        filename = sprintf("%s/local/spec/userconf/xiaroi/%s", BLISSADM, _ans)
    }

    if (unix(sprintf("test -r %s", filename))) {
        _xia_print("Error", sprintf("Cannot find file %s", filename))
    }
    else {
        _xia_roiremoveall()

        # 
        for (line=getline(filename);line!=-1;line=getline(filename)) {
            if (split(line,pars)==7) {
                _xia_roiinsert(pars[0], int(pars[1]),                   \
                               int(pars[2]), int(pars[3]),              \
                               int(pars[4]), int(pars[5]),              \
                               pars[6]=="-"?0:pars[6])
            }
        }
        getline(filename, "close")
        _xia_print("ROI", sprintf("%d rois have been loaded from %s",   \
                                  list_n(XIA_ROI), filename))
        if ((XIA_PAR["type"]==3)||(XIA_PAR["mode"]&XIA_MODESCA)||(XIA_PAR["mode"]&XIA_MODEMAP))
            _xia_roitosca()
    }
}'


#%UU% <roimne> <detector|"all"|"sum"|"avg"> <first> <last> [<lvt_corr>] [<dt_corr>] [<mne_norm>]
#%MDESC% Define a new roi. If no arguments are given, run xiaroimenu.
#%BR% Arguments are:
#%BR% * %B%roimne%B%  : counter mnemonic for the roi (should be defined in spec config)
#%BR% * %B%detector%B%:
#%BR% ... if ==\"all\" : add same roi on all detector. roi are named <roimne>N
#%BR% ... if ==\"avg\" : the roi named <roimne>Avg is an average on all <roimne>N
#%BR% ... if ==\"sum\" : the roi named <roimne>Avg is an average on all <roimne>N
#%BR% ... if ==<detetector_number> : add a single roi on the given detector
#%BR% * %B%first%B%   : first channel
#%BR% * %B%last%B%    : last channel
#%BR% * %B%lvt_corr%B%: if ==1, normalize roi by livetime, 0 otherwise
#%BR% * %B%dt_corr%B% : if ==1, deadtime correction, 0 otherwise
#%BR% * %B%mne_norm%B%: Normalize the roi using the given counter
#
def xiaroi '{
    global XIA_ROI

    if (list_n(XIA_ROI)<0){
        list_init XIA_ROI
    }

    if ($#>=2) {
        if ("$2"=="all"||"$2"=="avg"||"$2"=="sum"){
            _xia_roiadd("$1","$2",$3,$4,$5,$6,"$7","$8")
        }
        else{
            _xia_roiadd("$1",int($2),$3,$4,$5,$6,"$7","$8")
        }

        if ((XIA_PAR["mode"]&XIA_MODESCA)||(XIA_PAR["mode"]&XIA_MODEMAP)){
                    _xia_roitosca()
        }
    }
    else {
        xiaroimenu
    }
}'


#%IU% (cmne, cdet, min, max, lvt, dt, norm)
#%MDESC% Add a roi with following rules:
#%BR% if cdet==\"all\": add the same roi on all detectors named %B%<cmne>N%B%
#%BR% if cdet==\"avg\": add a roi named %B%<cmne>Avg%B%, which will be computed as a average of %B%<cmne>N%B%
#%BR% if cdet==\"sum\": add a roi named %B%<cmne>Sum%B%, which will be computed as a sum of %B%<cmne>N%B%
#%BR% if cdet==detector_number: add a single roi on given detector
#
def _xia_roiadd(cmne, cdet, min, max, lvt, dt, norm, name) '{
    local ich

    if (cdet=="all") {
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            _xia_roiinsert(sprintf("%s%02d", cmne, XIA_DET[ich]),XIA_DET[ich],min, max, lvt, dt, norm, name)
        }
    } else if (cdet=="avg") {
        _xia_roiinsert(sprintf("%sAvg", cmne), -1, 0, 0, 0, 0, cmne, name)
    } else if (cdet=="sum") {
        _xia_roiinsert(sprintf("%sSum", cmne), -2, 0, 0, 0, 0, cmne, name)
    } else {
        _xia_roiinsert(cmne, cdet, min, max, lvt, dt, norm, name)
    }
}'


#%IU%
#%MDESC% user hook macro called each time a roi has been added
#%BR% First parameter sent ($1) is the roi mnemonic
def user_xia_roi_add '{
    local __param__

    __param__ = $1
}'


#cdef("user_xia_roi_add", "", "", "")

#%IU%
#%MDESC% add a roi in list %B%XIA_ROI%B% and call user hook
def _xia_roiinsert(mne, det, min, max, lvt, dt, norm, name) '{

    if ((det < 0)||(_xia_getdetidx(det)!=-1)) {
        list_add(XIA_ROI, mne)
        XIA_ROI[mne]["det"]= det
        XIA_ROI[mne]["min"]= min
        XIA_ROI[mne]["max"]= max
        XIA_ROI[mne]["lvt"]= lvt
        XIA_ROI[mne]["dt"]= dt
        XIA_ROI[mne]["norm"]= norm
        if (name != "") {
            XIA_ROI[mne]["name"]= name
        } else {
            if (XIA_ROI[mne]["name"] == "")
                XIA_ROI[mne]["name"] = mne
        }

        user_xia_roi_add mne
    }
    else{
        _xia_print("_xia_roiinsert",                            \
                   sprintf("bad detector number : %d", det),    \
                   1)
    }
}'


#%UU% <detector_number>
#%MDESC% Disable detector in ROI which computes SUM/AVG on all det.
#%BR% if <detector_number>==\"all\": disable all detectors
#
def xiadetdisable '{
    if ($#!=1) {
        print "USAGE: xiadetdisable <detector_number>"
        print "if <detector_number>==\"all\", disable all detectors"
        exit
    }
    if ("$1"=="all") {
        local ich
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++)
            XIA_DETDISABLE[XIA_DET[ich]]= 1
    }
    else {
        XIA_DETDISABLE[int($1)]= 1
    }
}'


#%UU% <dectector_number>
#%MDESC% Enable detector in ROI which computes SUM/AVG on all det.
#%BR% if <detector_number>==\"all\": enable all detectors.
#
def xiadetenable '{
    if ($#!=1) {
        print "USAGE: xiadetenable <detector_number>"
        print "if <detector_number>==\"all\", enable all detectors"
        exit
    }
    if ("$1"=="all") {
        local ich
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++)
            XIA_DETDISABLE[XIA_DET[ich]]= 0
    }
    else {
        XIA_DETDISABLE[int($1)]= 0
    }
}'

def _xia_hwscamenu '{
    local nb key cmne cdet cmin cmax file

    while (1) {
        nb= _xia_hwscashow()
        tty_move(0,nb++, "\[md\]A\[se\]dd/\[md\]R\[se\]emove/\[md\]M\[se\]odify ROI(s),")
        tty_move(0,nb++, "\[md\]L\[se\]oad from/\[md\]S\[se\]ave to file,  or \[md\]Q\[se\]uit ? ")

        print("\n\n")
        key = getval_one_char("enter key (a, r, m, d, e, l, s, q)")
        printf("\n\n")

        if (key=="q"||key=="Q"){
            break
        }
        else if (key=="r"||key=="R") {
            cmne= getval("Counter mnemonic (\"*\" to remove all)",0)
            if (cmne!="0") _xia_roiremove(cmne)
        }
        else if (key=="a"||key=="A") {
            cmne= getval(" > Counter mnemonic    ", 0)
            if (cmne) {
                cdet= getval_int(" > Detector number     ", 0)
                cmin= getval_int(" > First channel       ", XIA_PAR["chmin"])
                cmax= getval_int(" > Last channel        ", XIA_PAR["chmax"])
                _xia_roiadd(cmne, cdet, cmin, cmax, 0, 0, 0)
            }
        }
        else if (key=="s"||key=="S") {
            file= getval_check("Save ROIs to file [0:default file]", 0)

            if (file=="0") xiaroisave
            else eval(sprintf("xiaroisave %s", file))

            input("... Press Enter ...")
        }
        else if (key=="l"||key=="L") {

            xiaroiload
            input("... Press Enter ...")
        }
    }
    _xia_roitosca()
}'

def _xia_hwscashow() '{
    local nroi nb roi
    local ich idet outroi

    if ((nroi=list_n(XIA_ROI))<0) list_init XIA_ROI

    clscreen()
    tty_move(20,0,"\[md\]< XIA ROI >\[me\]")
    tty_move(0,2,"           Counter     From   To  Output Signal")

    nb= 3

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        idet= XIA_DET[ich]
        outroi= 0
        tty_move(0,nb++, sprintf("Detector %2d --------------------------------------------",idet))

        for (roi=1; roi<=nroi; roi++) {
            if (list_getpar(XIA_ROI,roi,"det")==idet) {
                tty_move(0, nb++, \
                    sprintf("\[md\]          %8s      %4d %4d \[me\]   %s", \
                        list_item(XIA_ROI,roi), list_getpar(XIA_ROI,roi,"min"), \
                        list_getpar(XIA_ROI,roi,"max"), XIA_MSG["hwsca"][outroi]))
                outroi++
            }
        }
        tty_move(12,nb++, "--------------------------------------------")
        tty_move(12,nb++, " Fast Trigger Output     Grey #7")
        tty_move(12,nb++, " LiveTime Output         Grey #8 (gate)")
    }
    tty_move(0,nb++,"--------------------------------------------------------")
    nb++
}'

#%IU% ()
#%MDESC%
#   Shows ROI definition
def _xia_roishow() '{
    local nroi nb roi
    local ich idet

    if ((nroi=list_n(XIA_ROI))<0) list_init XIA_ROI

    clscreen()
    tty_move(20,0,"\[md\]< XIA ROI >\[me\]")
    tty_move(0,2,"           Counter     From   To  Config  LVT  DT  Norm.")

    nb= 3

    tty_move(0,nb++,"Avg all det. -------------------------------------------")
    for (roi=1; roi<=nroi; roi++) {
        if (list_getpar(XIA_ROI, roi, "det")==-1) {
            tty_move(0, nb++, \
                sprintf("\[md\]          %8s %15s   %s  %s %s %6s\[me\]", \
                list_item(XIA_ROI,roi), sprintf("<on %s*>",list_getpar(XIA_ROI,roi,"norm")), \
                (cnt_num(XIA_ROI[roi])==-1)?" No":"Yes", \
                " - ", " - ", "-"))
        }
    }
    tty_move(0,nb++,"Sum all det. -------------------------------------------")
    for (roi=1; roi<=nroi; roi++) {
        if (list_getpar(XIA_ROI, roi, "det")==-2) {
            tty_move(0, nb++, \
                sprintf("\[md\]          %8s %15s   %s  %s %s %6s\[me\]", \
                list_item(XIA_ROI,roi), sprintf("<on %s*>",list_getpar(XIA_ROI,roi,"norm")), \
                (cnt_num(XIA_ROI[roi])==-1)?" No":"Yes", \
                " - ", " - ", "-"))
        }
    }

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        idet= XIA_DET[ich]
        if (XIA_DETDISABLE[idet])
            tty_move(0,nb++, sprintf("Detector %2d --------------------------------- [disabled]",idet))
        else     tty_move(0,nb++, sprintf("Detector %2d --------------------------------------------",idet))
        

        for (roi=1; roi<=nroi; roi++) {
            if (list_getpar(XIA_ROI,roi,"det")==idet) {
                tty_move(0, nb++, \
                sprintf("\[md\]          %8s      %4d %4d    %s  %s %s %6s\[me\]", \
                    list_item(XIA_ROI,roi), list_getpar(XIA_ROI,roi,"min"), \
                    list_getpar(XIA_ROI,roi,"max"), (cnt_num(XIA_ROI[roi])==-1)?" No":"Yes", \
                    list_getpar(XIA_ROI,roi,"lvt")?"Yes":" No", \
                    list_getpar(XIA_ROI,roi,"dt")?"Yes":" No", \
                    list_getpar(XIA_ROI,roi,"norm")=="0"?"-":list_getpar(XIA_ROI,roi,"norm")))
            }
        }
        }
    tty_move(0,nb++,"--------------------------------------------------------")
    nb++
    return (nb)
}'


#%IU%
#%MDESC% Computes all defined rois
#%BR% Roi values are stored in %B%XIA_ROIVAL%B%
#%BR% and saved in standard %B%S[]%B% array if counter exists
#
def _xia_readrois '{
    local nroi roi roimne roinum
    unglobal XIA_ROIVAL
    global XIA_ROIVAL[]

    nroi= list_n(XIA_ROI)
    if (nroi) {
        # --- single rois first
        for (roi=1; roi<=nroi; roi++) {
            roimne= list_item(XIA_ROI, roi)
            if (XIA_ROI[roimne]["det"] >= 0) {
                XIA_ROIVAL[roimne]= _xia_roicalc(roimne)
                if ((roinum=cnt_num(roimne))!=-1)
                    S[roinum]= XIA_ROIVAL[roimne]
            }
        }
        # --- average/sum rois
        for (roi=1; roi<=nroi; roi++) {
            roimne= list_item(XIA_ROI, roi)
            if (XIA_ROI[roimne]["det"] < 0) {
                XIA_ROIVAL[roimne]= _xia_roioperation(roimne)
                if ((roinum=cnt_num(roimne))!=-1)
                    S[roinum]= XIA_ROIVAL[roimne]
            }
        }
    }
}'


#%IU% (mne)
#%MDESC% Computes average/sum Rois assuming that single Roi has already been stored in XIA_ROIVAL
#
def _xia_roioperation(roimne) '{
    local ich dmne sum nbr idet normmne roitype

    normmne = XIA_ROI[roimne]["norm"]
    roitype = XIA_ROI[roimne]["det"]
    sum= 0
    nbr= 0
    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        idet= XIA_DET[ich]
        if (!XIA_DETDISABLE[idet]) {
            dmne= sprintf("%s%02d", normmne, idet)
            if (list_check(XIA_ROI, dmne)>0) {
                sum+= XIA_ROIVAL[dmne]
                nbr++
            }
        }
    }
    if (sum>0 && nbr>0 && (roitype == -1))
        sum= sum/nbr
    return (sum)
}'


#%IU% (mne)
#%MDESC% Return roi value. If requested, the roi value if altered for
#live-time and dead-time correction.
def _xia_roicalc(mne) '{
    local idet beg end sum chmax isca norm

    idet= _xia_getdetidx(XIA_ROI[mne]["det"])
    if (idet<0) return (0)

        if (XIA_PAR["mode"]==XIA_MODESCA) {
        isca= XIA_ROI[mne]["sca"]
        sum= XIA_SCAS[isca]
    }
    else {
        beg= XIA_ROI[mne]["min"] - XIA_PAR["chmin"]
        end= XIA_ROI[mne]["max"] - XIA_PAR["chmin"]

        chmax= XIA_PAR["chmax"]
        if (beg<0) beg= 0
        if (beg>chmax) beg= chmax
        if (end>chmax) end= chmax
        sum= array_op("sum", XIA_DATA[idet+1][beg:end])
    }
        # Divide the sum by livetime returned by the DS.
    if (XIA_ROI[mne]["lvt"] && XIA_STAT[idet][4]>0) {
        sum= 1000.*sum/XIA_STAT[idet][4]
    }
        # Multiply the sum by ICR/OCR returned by the DS.
    if (XIA_ROI[mne]["dt"] && XIA_STAT[idet][3]>0) {
        sum= sum * (XIA_STAT[idet][2]/XIA_STAT[idet][3])
    }
        # Divide the sum by a given counter.
    if (XIA_ROI[mne]["norm"]!="0") {
        if ((norm= cnt_num(XIA_ROI[mne]["norm"]))!=-1) {
            if (S[norm]>0) sum= sum / S[norm]
        }
    }
    return (sum)
}'



######################################################################
#######################                        #######################
#######################  SPECTRUM CORRECTIONS  #######################
#######################                        #######################
######################################################################



#%UU% [parma]
#%MDESC%
#    
def xiacorrsetup '{
    if ($#!=4) {
    XIA_CORR["lvt"]= yesno("LiveTime normalisation", XIA_CORR["lvt"])
    XIA_CORR["dt"]= yesno("DeadTime correction", XIA_CORR["dt"])
    XIA_CORR["mon"]= yesno("Monitor normalisation", XIA_CORR["mon"])
    print
    XIA_CORR["save"]= yesno("Save corrected instead of raw spectrums", XIA_CORR["save"])
    }
    else {
    XIA_CORR["lvt"]= int($1)
        XIA_CORR["dt"]= int($2)
        XIA_CORR["mon"]= int($3)
        XIA_CORR["save"]= int($4)
    }
    _xia_createarrays()
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_hascorr() '{
    return (XIA_CORR["lvt"] || XIA_CORR["dt"] || XIA_CORR["mon"])
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_iscorrsaved() '{
    return (XIA_CORR["save"] && (XIA_CORR["lvt"] || XIA_CORR["dt"] || XIA_CORR["mon"]))
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_corrcreatearray '{
    if (_xia_hascorr()) {
            shared double array XIA_CORRDATA[XIA_PAR["nbdet"]+1][XIA_PAR["chlen"]]

        array_op("fill", XIA_CORRDATA[0][])
        if (XIA_PAR["chmin"]) XIA_CORRDATA[0][]+= XIA_PAR["chmin"]
    } else {
        unglobal XIA_CORRDATA
    }
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_corrdata '{
    if (_xia_hascorr()) {
        local float array corr[XIA_PAR["nbdet"]]
        local idet

        corr[:]= 1.
        if (XIA_CORR["lvt"]) {
        for (idet=0; idet<XIA_PAR["nbdet"]; idet++) {
            if (XIA_STAT[idet][4]>0)
                corr[idet] = corr[idet] * (1000./XIA_STAT[idet][4])
        }
        }

        if (XIA_CORR["mon"] && (!XIA_CORR["inacq"])) {
        if ((S[sec]>0) && (S[mon]>0) && (cnt_num(MON)!=-1)) {
            XIA_CORR["mrate"]= S[MON]/S[sec]
            corr[:]= corr[:]/XIA_CORR["mrate"]
        }
        else {
            XIA_CORR["mrate"]= 1.
        }
        }

        if (XIA_CORR["dt"]) {
        for (idet=0; idet<XIA_PAR["nbdet"]; idet++) {
            if (XIA_STAT[idet][3]>0)
                corr[idet]= corr[idet] * (XIA_STAT[idet][2]/XIA_STAT[idet][3])
            }
        }

        for (idet=0; idet<XIA_PAR["nbdet"]; idet++) {
        XIA_CORRDATA[idet+1][:]= XIA_DATA[idet+1][:]*corr[idet]
        }
    }
}'



######################################################################
###########################                 ##########################
###########################  SUM DETECTORS  ##########################
###########################                 ##########################
######################################################################


#%UU%
#%MDESC% Menu to define spectrum detectors sum or average
#%BR% Options are given to perform livetime and/or deadtime corrections
#
def xiasummenu '{
    local nb key dets lvt dt name idet avg idx file
    local detn deta[] nsum

    nsum= list_n(XIA_SUM)
    while (1) {
    nb= _xia_sumshow()
    tty_move(0,nb++, "\[md\]A\[se\]dd/\[md\]R\[se\]emove/\[md\]M\[se\]odify SUM(s),")
    tty_move(0,nb++, "\[md\]L\[se\]oad from/\[md\]S\[se\]ave to file,  or \[md\]Q\[se\]uit ? ")

    print("\n\n")
    key = getval_one_char("enter key (a, r, m, d, e, l, s, q)")
    printf("\n\n")

    if (key=="q"||key=="Q") break
    else if (key=="a"||key=="A") {
        dets= getval(" > Detector numbers, -1 for all ", "")
        if (dets!="") {
        lvt = yesno (" > Do livetime correction       ", 0)
        dt  = yesno (" > Do deadtime correction       ", 0)
        avg = yesno (" > Average (sum/nbdet)          ", 1)

        detn= index(dets, "-1")>0?-1:split(dets, deta)
        _xia_addsum(-1, detn, deta, lvt, dt, avg)
        }
    }
    else if (key=="r"||key=="R") {
        idx= getval(" > Sum number, -1 for all ", "")
        if (idx!="")
        _xia_delsum(idx)
    }
    else if (key=="m"||key=="M") {
        idx= getval(" > Sum number", "")
        name= list_item(XIA_SUM, idx)
        if (name!=-1) {
        dets= ""
        for (idet=0; idet<XIA_SUM[name]["nbdet"]; idet++)
            dets= dets sprintf("%d ", XIA_SUM[name][idet])
        dets= getval(" > Detector numbers, -1 for all ", dets)
        if (dets!="") {
            detn= split(dets, deta)
            lvt = yesno (" > Do livetime correction       ", XIA_SUM[name]["lvt"])
            dt  = yesno (" > Do deadtime correction       ", XIA_SUM[name]["dt"])
            avg = yesno (" > Average (sum/nbdet)          ", XIA_SUM[name]["avg"])
            _xia_addsum(idx, detn, deta, lvt, dt, avg)
        }
        }
    }
    else if (key=="s"||key=="S") {
        file= getval_check("Save SUMs to file [0:default file]", 0)
        if (file=="0") xiasumsave
        else xiasumsave file
        input("... Press Enter ...")
    }
    else if (key=="l"||key=="L") {
        file= getval_check("Load SUMs from file [0:default file]", 0)
        if (file=="0") xiasumload
        else xiasumload file
        input("... Press Enter ...")
    }
    if (list_n(XIA_SUM)!=nsum)
        _xia_sumcreatearray
    }
}'


#%IU% ()
#%MDESC% Display current detector sum configured
#
def _xia_sumshow() '{
    local nb iv name dets idet detn

    clscreen()
    tty_move(15,0,"\[md\]< XIA DETECTORS SUM >\[me\]")
    tty_move(0,2,"              -- Corrections ---  ")
    tty_move(0,3,"SumNb  NbDet  LiveTime  DeadTime  Average  Detectors")
    tty_move(0,4,"-----  -----  --------  --------  -------  ----------------")

    nb= 5
    if (list_n(XIA_SUM)<=0) {
        tty_move(10,++nb, "\[md\]-- None configured --\[me\]")
        nb++
    }
    else {
        for (iv=0; iv<list_n(XIA_SUM); iv++) {
            name= list_item(XIA_SUM, iv+1)

        if (XIA_SUM[name]["nbdet"]==-1) {
        detn= XIA_PAR["nbdet"]
        dets= "ALL"
        }
        else {
        detn= XIA_SUM[name]["nbdet"]
        dets= ""
        for (idet=0; idet<detn; idet++)
            dets= dets sprintf("%d ", XIA_SUM[name][idet])
        }

        tty_move(0,nb++, sprintf(" %3d   %5d       %3s       %3s      %3s  %s", \
            iv+1, detn, XIA_SUM[name]["lvt"]?"Yes":"No", \
            XIA_SUM[name]["dt"]?"Yes":"No", \
            XIA_SUM[name]["avg"]?"Yes":"No", dets))
        }
        tty_move(0,nb++,"-----  -----  -------------  -------------  ---------------")
    }
    return (nb+1)
}'


#%UU% [<sumno> <lvt_corr> <dt_corr> <do_avg> <det1> ... <detn>]
#%MDESC%
#%BR%If no arguments, display a menu to configure detector sum
#%BR%If arguments are given, add the defiened detector sum
#
def xiasum '{
    if ($#<4) {
    xiasummenu
    }
    else {
    local idx lt dt avg det[]
    local i npar pars[]

    npar= split("$*", pars)
    idx= pars[0]
    lt=  pars[1]
    dt=  pars[2]
    avg= pars[3]
    for (i=4; i<npar; i++) {
        det[i-4]= int(pars[i])
    }
    if (det[0]==-1) {
        _xia_addsum(idx, -1, 0, lt, dt)
    } else {
        _xia_addsum(idx, npar-4, det, lt, dt)
    }
    _xia_sumcreatearray
    }
}'



#%IU% [parma]
#%MDESC%
#    
def _xia_addsum(idx, ndet, det, lvt_corr, dt_corr, do_avg) '{
    local vdet idet

    if (list_n(XIA_SUM)<0) list_init XIA_SUM

    if (idx==-1) {
    for (idx=0; idx<=list_n(XIA_SUM); idx++) {
        vdet= sprintf("S%d", idx)
        if (!(vdet in XIA_SUM)) break
    }
    }
    else {
    vdet= list_item(XIA_SUM, idx)
    if (vdet==-1) {
        _xia_print("DetectorSum", "Wrong sum number", 1)
        return
    }
    }
    if (list_check(XIA_SUM, vdet)<=0)
        list_add(XIA_SUM, vdet)

    XIA_SUM[vdet]["type"]= type
    XIA_SUM[vdet]["nbdet"]= ndet
    XIA_SUM[vdet]["lvt"]= lvt_corr
    XIA_SUM[vdet]["dt"]= dt_corr
    XIA_SUM[vdet]["avg"]= do_avg

    for (idet=0; idet<ndet; idet++) {
    XIA_SUM[vdet][idet]= det[idet]
    }
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_delsum(idx) '{
    if (idx==-1) {
        list_init XIA_SUM
    }
    else {
        local vdet
        vdet= list_item(XIA_SUM, idx)
    if (vdet!=-1)
        list_remove(XIA_SUM, vdet)
    }
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_sumcreatearray '{
    local nsum
    nsum= list_n(XIA_SUM)
    if (nsum>0 && XIA_PAR["chlen"]>0)
    shared double array XIA_SUMDATA[nsum][XIA_PAR["chlen"]]
    else
    unglobal XIA_SUMDATA
}'


#%IU% [parma]
#%MDESC%
#    
def _xia_readsum '{
    local nsum

    nsum= list_n(XIA_SUM)
    if (nsum) {
    local name is id idet lt dt usedet[] used

    for (is=0; is<nsum; is++) {
        name= list_item(XIA_SUM, is+1)
        lt= XIA_SUM[name]["lvt"]
        dt= XIA_SUM[name]["dt"]

        XIA_SUMDATA[is][:]= 0

        if (XIA_SUM[name]["nbdet"]==-1) {
        used= XIA_PAR["nbdet"]
        for (id=0; id<used; id++)
            usedet[id]= id
        }
        else {
        used= 0
        for (id=0; id<XIA_SUM[name]["nbdet"]; id++) {
            idet= _xia_getdetidx(XIA_SUM[name][id])
            if (idet!=-1) {
            usedet[used]= idet
            used++
            }
        }
        }

        for (id=0; id<used; id++) {
        idet= usedet[id]
        if (lt && dt)
            XIA_SUMDATA[is][:] += (XIA_DATA[idet+1][:] * \
                ((1000.*XIA_STAT[idet][2]) / (XIA_STAT[idet][3]*XIA_STAT[idet][4])))
        else if (lt && !dt)
            XIA_SUMDATA[is][:] += (XIA_DATA[idet+1][:] * (1000. / XIA_STAT[idet][4]))
        else if (!lt && dt)
            XIA_SUMDATA[is][:] += (XIA_DATA[idet+1][:] * (XIA_STAT[idet][2] / XIA_STAT[idet][3]))
        else
            XIA_SUMDATA[is][:] += XIA_DATA[idet+1][:]
        }
        if ((XIA_SUM[name]["avg"]==1) && (used>1))
        XIA_SUMDATA[is][:] /= used
    }
    }
}'


#%UU% [<filename>]
#%MDESC% Save spectrum sum definitions in a file. If <filename> is not specified, save to the standard location
#
def xiasumsave '{
    local filename name isum idet

    if ($#==1) filename="$1"
    else filename=sprintf("%s/local/spec/userconf/xiasum.def.%s", BLISSADM, USER)

    if (!unix(sprintf("test -r %s", filename))) {
    unix(sprintf("/bin/rm -f %s",filename))
    }
    if (on(filename)==-1) {
    _xia_print("Error", sprintf("Cannot open file %s", filename))
    }
    else {
    offt
    printf("# -------- XIA SUMs ----------\n")
        printf("# lvt dt avg dets\n")
    for (isum=1; isum<=list_n(XIA_SUM); isum++) {
        name= list_item(XIA_SUM, isum)
        printf("%d %d %d", XIA_SUM[name]["lvt"], XIA_SUM[name]["dt"], XIA_SUM[name]["avg"])
        if (XIA_SUM[name]["nbdet"]==-1) {
        printf(" -1\n")
        } else {
        for (idet=0; idet<XIA_SUM[name]["nbdet"]; idet++)
            printf(" %2d", XIA_SUM[name][idet])
        printf("\n")
        }
    }
    ont; close(filename)
    _xia_print("SUM", sprintf("Saved to %s", filename))
    }
}'

#%UU% [<filename>]
#%MDESC% Load spectrum sum definition from a file. If <filename> is
#not specified, load from the standard location
#%BR% Loading sum from file will erase current sum settings.
#
def xiasumload '{
    local filename line npar pars[]

    if ($#==1) filename="$1"
    else filename= sprintf("%s/local/spec/userconf/xiasum.def.%s", BLISSADM, USER)

    if (unix(sprintf("test -r %s", filename))) {
    _xia_print("Error", sprintf("Cannot find file %s", filename))
    }
    else {
    list_init XIA_SUM
    for (line=getline(filename);line!=-1;line=getline(filename)) {
        if (index(line, "#")==0) {
        local det[]

        if ((npar= split(line,pars))>=4) {
            for (i=3; i<npar; i++) {
            det[i-3]= int(pars[i])
            }
            _xia_addsum(-1, npar-3, det, pars[0], pars[1], pars[2])
        }
        }
    }
    getline(filename, "close")
    _xia_print("SUM", sprintf("%d sums have been loaded from %s", \
                list_n(XIA_SUM), filename))
    }
}'


######################################################################
##############################          ##############################
##############################  LINEUP  ##############################
##############################          ##############################
######################################################################


#%UU%
#%MDESC% Set lineup facility ON
#%BR% Lineup will store all data in %B%MCA_DATA%B%
#
def xialineupon '{
    XIA_LINEUP=1
    _xia_lineupcreatearray
    cdef("user_prepcount", ";_xia_lineupclear;", "_lpxia", 0x20)
    cdef("user_getcounts", ";_xia_lineupdata;", "_lpxia", 0x20)
}'


#%UU%
#%MDESC% Set lineup facility OFF
def xialineupoff '{
    XIA_LINEUP=0
    cdef("", "", "_lpxia", "delete")
}'


#%IU%
#%MDESC% Create MCA_DATA for lineup
def _xia_lineupcreatearray '{
    local size
    size= _xia_lineupsize()
    if (size>0) {
        ulong array MCA_DATA[size][2]
        array_op("fill", MCA_DATA[][0])
    }
}'


#%IU%
#%MDESC% Store data of all detectors (read in %B%XIA_DATA%B%)
# in array %B%MCA_DATA%B%
def _xia_lineupdata '{
    if (esrf_io(XIA_DEV, "DevXiaReadData", 1, MCA_DATA[][1])==-1) {
        _xia_print("LineupData", "Failed to read spectrums", 1)
    }
}'


#%IU% ()
#%MDESC% Return total size of lineup array
def _xia_lineupsize() '{
    local size
    size= XIA_PAR["nbdet"]*XIA_PAR["chlen"]
    return (size)
}'


#%IU%
#%MDESC% Clear MCA_DATA array
def _xia_lineupclear '{
    MCA_DATA[][1]= 0
}'



######################################################################
##########################                   #########################
##########################   DSP PARAMETERS  #########################
##########################                   #########################
######################################################################


#%UU% <detector_number>
#%MDESC% Read ALL DSP parameters for one detector
def xiareaddsp '{
    if (!$#) {
        print "$0 <detector_number>"
        exit
    }

    local ichan, nb
    local names[]

    ichan= int($1)

    nb= esrf_io(XIA_DEV, "DevXiaGetDspNames", ichan, names)
    if (nb==-1) {
        _xia_print("Dsp", "Cannot read dsp parameter names", 1)
        exit
    }

    local short array values[nb]
    if (esrf_io(XIA_DEV, "DevXiaGetDspValues", ichan, values)==-1) {
        _xia_print("Dsp", "Cannot read dsp parameter names", 1)
        exit
    }

    for (ichan=0; ichan<nb; ichan++) {
        printf(" - %-15.15s : 0x%04x\n", names[ichan], values[ichan])
    }
}'


#%UU% <parameters_names>
#%MDESC% Read one or several DSP parameters on all detectors
def xiagetdsp '{
    local ipar nbpar param[]
    local nbch ich
    local str

    if (!$#) {
        print "xiagetdsp <parameters_names>"
        exit
    }

    nbpar= split("$*", param)
    nbch= XIA_PAR["nbdet"]

    local long array XIA_DSPPAR[nbpar==1?2:nbpar][nbch==1?2:nbch]

    _xia_print("DSP", "Read parameters")
    for (ipar=0; ipar<nbpar; ipar++) {
        if (esrf_io(XIA_DEV, "DevXiaGetDspPar", param[ipar], XIA_DSPPAR[ipar])==-1) {
            _xia_print("DspPar", sprintf("Cannot get DSP parameters <%s>", param[ipar]), 1)
            exit
        }
    }

    tty_cntl("md")
    str= "Detector"
    for (ipar=0; ipar<nbpar; ipar++)
        str= str sprintf(" %13.13s", param[ipar])
    printf("\n%s\n", str)
    tty_cntl("me")

    for (ich=0; ich<nbch; ich++) {
        str= sprintf("%02d:     ", XIA_DET[ich])
        for (ipar=0; ipar<nbpar; ipar++)
            str= str sprintf(" %4d (0x%04x)", XIA_DSPPAR[ipar][ich], XIA_DSPPAR[ipar][ich])
        print str
    }
    print
}'


#%UU% <parameter_name>
#%MDESC% Set one DSP parameter on all detectors
def xiasetdsp '{
    local param ich nbch option

    if ($#!=1) {
        print "xiasetdsp <parameter_name>"
        exit
    }

    param = "$1"
    nbch  = XIA_PAR["nbdet"]

    local long array XIA_DSPPAR[nbch==1?2:nbch]
    option = 1

    while (option) {
        if (option==1) {
            # --- reload parameters
            _xia_print("DSP", "Read parameters")
            if (esrf_io(XIA_DEV, "DevXiaGetDspPar", param, XIA_DSPPAR)==-1) {
                _xia_print("DspPar", "Cannot get DSP parameters", 1)
                exit
            }
        }

        tty_cntl("md")
        printf("\nDetector %s\n", param)
        tty_cntl("me")
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            printf("%02d:       %4d (0x%04x)\n", XIA_DET[ich],          \
                   XIA_DSPPAR[ich], XIA_DSPPAR[ich])
        }
        option= getval_int("\n(0) Quit, (1) Read, (2) Change ---> ", 0)

        if (option==2) {
            # --- change parameters
            printf("\nEnter %s values in decimal:\n", param)
            for (ich=0; ich<nbch; ich++)
                XIA_DSPPAR[ich]= getval(sprintf("\tDetector %02d", XIA_DET[ich]), XIA_DSPPAR[ich])
            _xia_print("DSP", "Update parameters")
            if (esrf_io(XIA_DEV, "DevXiaSetDspPar", XIA_DSPPAR)==-1) {
                _xia_print("DSP", "FAILED.")
                option= 0
            }
            else {
                _xia_print("DSP", "DONE.")
                if (XIA_PAR["type"]<2) _xia_test
                option= 1
            }
        }
    }
}'



######################################################################
#############################            #############################
#############################  BASELINE  #############################
#############################            #############################
######################################################################


#%UU%
#%MDESC% Read baseline history
def xiareadbase '{
    shared ulong array XIA_BASELINE[XIA_PAR["nbdet"]+1][XIA_PAR["baselen"]]
    if (esrf_io(XIA_DEV, "DevXiaReadBase", XIA_BASELINE[1:XIA_PAR["nbdet"]])==-1) {
        _xia_print("ReadBase", "Failed to read baseline", 1)
    }
    array_op("fill", XIA_BASELINE[0])
    xiabaseres
}'


#%UU% [<det> [<min> <max>]]
#%MDESC% Plot baseline history for detector <det>. Optionnal plotting interval
#%BR% Caution: xiareadbase needs to be executed first. No automatic read
def xiaplotbase '{
    local num beg end fstr
    if (!$#) {
        for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
            _xia_plotbase(XIA_DET[ich])
            input("... Press Enter for next detector ...\r")
        }
    }
    else {
        _xia_plotbase($1, $2, $3)
    }
}'


#%UU% <filename>
#%MDESC% Save all baseline history in EDF file
def xiasavebase '{
    local fname
    if (!$#) {
        print "$0 <filename>"
        exit
    }
    fname= "$1"
    fmt_write(fname, "ESRF", XIA_BASELINE)
    _xia_print("SaveBase", sprintf("Saved to %s", fname))
}'


#%IU% (<num>, <beg>, <end>)
#%MDESC%
#    
def _xia_plotbase(num, beg, end) '{
    local fstr idx

    if ((idx=_xia_getdetidx(num))==-1) {
        print "Detector "num" not defined."
        exit
    }

    if (!end || end>=XIA_PAR["baselen"]) end=XIA_PAR["baselen"]-1

    plot_cntl("filter3,open")
    plot_cntl("erase")
    plot_cntl("+lines")
    plot_cntl("-ebars")
    plot_cntl("-dots")
    plot_range("auto", "auto", "auto", "auto")
    plot_cntl("colors=49:16:9:3:2:7:8:9:5:4:2")
    fstr= sprintf("FWHM is %.5g at %.5g", \
            array_op("fwhm", XIA_BASELINE[0][beg:end], XIA_BASELINE[idx+1][beg:end]), \
            array_op("cfwhm", XIA_BASELINE[0][beg:end], XIA_BASELINE[idx+1][beg:end]))
    plot_move(0, 0, sprintf("XIA BASELINE DET=%d ; %s", num, fstr))
    plot_cntl("mca")
    array_plot(XIA_BASELINE[0][beg:end], XIA_BASELINE[idx+1][beg:end])
    plot_cntl("filter1")
}'


#%UU%
#%MDESC% Computes FWHM, COM, MAX on baseline history
def xiabaseres '{
    local _fw _cfw _co _m _rm

    tty_cntl("md")
    printf("Detector : Fwhm\t: COM\t: Max\n")
    tty_cntl("me")

    for (ich=0; ich<XIA_PAR["nbdet"]; ich++) {
        _fw= array_op("fwhm", XIA_BASELINE[0], XIA_BASELINE[ich+1])
        _cfw= array_op("cfwhm", XIA_BASELINE[0], XIA_BASELINE[ich+1])
        _co= array_op("com", XIA_BASELINE[0], XIA_BASELINE[ich+1])
        _m= array_op("max", XIA_BASELINE[ich+1])
        _rm= array_op("cmax", XIA_BASELINE[ich+1])
        printf("%2d       : %.8g @ %.8g\t: %.8g\t %d @ %d\n", XIA_DET[ich], _fw, _cfw, _co, _m, _rm)
    }
}'


#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% E.Papillon