esrf

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

#%TITLE% multimca.mac
#%NAME%
#   Multi Channel Analyser. Macros handling multiple devices at once
#
#%CATEGORY% Detection, MCA
#
#%LOG%
#$Revision: 1.45 $
#$Log: multimca.mac,v $
#Revision 1.45  2022/12/05 16:00:36  witsch
#Introduction of a macro MCA (named Can556), which needs some adaption
#in the code. Some functions didn't go throught the Can556_cmd() and hindere
#the macro MCA's work. The two macro sets were tested together and it worked. 
#
#The real use on the beam line needs to be awaited to see, if new problems 
#arise.
#
#Revision 1.43  2017/05/29 08:59:07  papillon
#bug in mcaroiload corrected by FS on id10
#
#Revision 1.42  2013/11/19 15:38:38  claustre
#Added support for mythen version 2 (newly supported by spec, see help mythen)
#Since spec 6 auto_run is reset to 0 (was 1 before) update _mcacheckoff
#Replace PyMca with pymca in _mcaguistart(), PyMca script is no longer exist
#
#Revision 1.41  2013/08/21 15:42:36  witsch
#changes to allow easier implementation of mcas with a reduced set
#of commands.
#
#implementation of a roentec
#implementation of a dxp
#
#Revision 1.41  2011/06/11 09:26:35  witsch
#integrate Rontec, close to the Mythen.
#
#Revision 1.40  2011/02/17 16:35:32  claustre
#Thanks to Manu Pap who fixed some bugs introduced into the previous
#version with mythen integration.
#
#Revision 1.39  2010/10/27 07:48:45  beteva
#corrected a typo
#
#Revision 1.38  2010/10/19 14:40:19  homsrego
#identical to 1.37
#
#Revision 1.37  2010/10/19 14:29:34  homsrego
#* _mcacheckoff() : included test for irresponsive devices
#
#Revision 1.36  2010/10/11 09:31:06  witsch
#G. Swislow provided a first implementation for the use of the Mythen in Spec.
#There were some small things to correct and adjust. After that the work
#consisted of adjusting the multimca.mac to for its use.
#
#This meant to exclude certain actions on the Mythen, which were:
#
#the Mythen does not accept TCP connections, exclude the change in the macros.
#the Mythen does not accept commands like select_group, real, elapsed_live,
#elapsed_real, dead, clear. This inability lies in the mca_par builtin
#function. The exclusion take place in the mca_io macro:
#
#Revision 1.35  2009/10/13 12:40:39  papillon
#* change the way cdef are used:
#- create cdefs in mcaon and mcasetup
#- do not remove cdefs in mcaoff
#- let cdef macros defined and use MCA_ON variables
#* check spec auto_run flag before counting
#  (after reconfig, auto_run is to 1, but MCA_ON can still be 0:
#   force auto_run to 0 if MCA_ON is 0)
#* add a mcaunsetup to cleanup cdefs if needed
#* correct roi counters
#- remove old per counter cdefs not used anymore
#- when multiple mca, rois was all computed for each mca,
#  even if roi belongs to another mca
#* mca savings during scans test MCA_ON and not MCA_ACTIVE
#* correct HEADING for file saving in mcaacq
#
#Revision 1.34  2009/07/16 14:11:21  witsch
#mcaacq no longer needs an argument. if no argument is given,
#set count_time to 1 billion seconds, about 11000 days. That should be
#long enough even for ID18.
#
#Revision 1.33  2008/10/03 12:35:16  domingue
#correct user_Fheader and user_scan_loop call
#
#Revision 1.32  2008/08/12 14:15:24  rey
#documentation changes
#
#Revision 1.31  2008/03/18 12:57:22  witsch
#in mcaacq in case of continuing counting for a fixed amount of time, we need to know the elapsed counting time to add the new counting time. Only then the device server will acquire anew.
#
#Revision 1.30  2007/11/05 11:56:30  sole
#Make sure the noclear flag is appropriately handled during scans.
#
#Revision 1.29  2007/10/09 14:05:32  berruyer
#add _MCA_ROI_ADD and _MCA_ROI_DEL for user roi add macros
#
#Revision 1.28  2007/08/23 10:11:11  guijarro
#bug fixes in _mcaroicounts
#
#Revision 1.27  2007/08/23 08:42:56  guijarro
#fix bug with invalid use of 'list_getpar'
#
#Revision 1.26  2007/08/03 08:00:37  berruyer
#fill cntconf field in mcaroimenu
#
#Revision 1.25  2007/08/02 13:34:28  beteva
#added _mcacalibget() and _mcaroisetup() functions. Get the ROI pseudo counters
#setup when _mcasetup() executed and MCA is active.
#
#Revision 1.24  2007/07/31 14:06:22  beteva
#changed ROI handling, added mca_user_roi_add and mca_user_roi_delete,
#added mcatype
#
#Revision 1.23  2007/07/18 15:04:50  witsch
#in function mcawait the wait(0x24) doesn't fulfill the task,
#when using external synchronization. The macro mcaacq will return
#to the prompt right away, when launched with a count time.
#wait(0x24) will not take the main counter (here software counter)
#into account. Change that to wait(0x26).
#
#Revision 1.22  2007/07/12 10:53:09  beteva
#added read ROI spectra only, corrected bugs for the reduction factor
#
#Revision 1.21  2007/05/30 13:11:07  berruyer
#correction of syntax error in mcasetup ($#>$4)
#
#Revision 1.20  2006/07/26 15:21:49  beteva
#added save in one non-standard file option;
#if no save oprions and ROIs configured, read only the ROIs channels and not whole spectra;
#
#Revision 1.19  2006/04/20 16:00:47  beteva
#added change to TCP and big timeout for non MUSST MCA
#
#Revision 1.18  2005/12/13 08:32:31  papillon
#* Changes to integrate MUSST MCA
#
#Revision 1.17  2005/09/21 12:42:57  pepellin
#Use clscreen()
#
#Revision 1.16  2005/05/03 12:32:01  beteva
#added reduced reading if AE scan to save time with the Rontec
#
#Revision 1.15  2005/04/28 09:13:58  papillon
#Missing ; in some cdefs
#
#Revision 1.14  2004/10/05 06:31:50  claustre
#missing local declaration of variables in _mcaroicounts()
#
#Revision 1.13  2004/09/16 08:15:35  sole
#Added support for new PyMca
#
#Revision 1.13  2004/09/10 14:40:50  sole
#Support of new PyMca
#
#Revision 1.12  2004/09/10 14:40:50  papillon
#Correct parameters reading in mcasetup
#
#Revision 1.11  2004/05/13 14:46:39  witsch
#just added changing the plot frequency to the main menu.
#
#Revision 1.10  2004/05/07 13:01:52  beteva
#added _mcagetE() and _mcagetch() functions and print of energy for the roi;
#added choise of the gui to start - changes in mcasetup, mcamenu, mcaguion;
#fixed bug in mcawait
#
#%END%

# -- acquisition
global MCA_ACTIVE[] MCA_ON[]
global MCA_PAR[]
global MCA_IN_SCAN
# -- memory group
global MCA_MEM[]
# -- saving options
global MCA_SAVE[]

global MCA_N
if (whatis("MCA_N")&0x08000000) { MCA_N = 0 }
global MCA_SUFFIX
if (whatis("MCA_SUFFIX")&0x08000000) { MCA_SUFFIX = ".mca" }

# -- plot
global MCA_PID[]
# -- times
global MCA_TIMES[]
# -- rois definition
global MCA_ROI

# implicitely global vars
MCA_AVOID_CMDS_MYTHEN = "select_group real elapsed_live elapsed_real dead clear"
MCA_AVOID_CMDS_ROENTEC = "select_group group_size"
MCA_AVOID_CMDS_DXP = MCA_AVOID_CMDS_ROENTEC

# --- plot refresh
global MCA_PLOT_UPD
if (whatis("MCA_PLOT_UPD") & 0x08000000) MCA_PLOT_UPD = 0.1

need sps
need saveload

#%UU%
#%MDESC%
#    Toggles the debug mode.
if (!(whatis("__MultiMCA_debug")  & 2)) rdef __MultiMCA_debug \'#$*\'

def MultiMCA_debug '{
  if ((whatis("__MultiMCA_debug")>>16) <= 3) { # macro length is 3 bytes: comment
     rdef __MultiMCA_debug "eprint \"---> MultiMCA \""
     print "MultiMCA macro debug mode is ON"
  }
  else {
     rdef __MultiMCA_debug \'#\$*\'
     print "MultiMCA macro debug mode is OFF"
  }
}'


#%IU%
#%MDESC%
# Utility to print mca messages
def _mcamsg(no, msg) '{
    tty_cntl("md")
    if (no == "all") printf("MCA: ")
    else printf("MCA device %d: ", no)
    tty_cntl("me")
    print msg
}'

# ---------------------------------------------------------
# CONFIG MENU
# ---------------------------------------------------------

#%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)
}'


#%UU%
#%MDESC% List all configured MCA devices and their state
def mcalist '{
    local no
    for (no = 0; no<MCAS; no++)
    _mcalist(no)
}'

#%IU% (no)
#%MDESC% short list of the MCA %B%no%B% configuration
def _mcalist(no) '{
    local ctrl dev resp

    ctrl = mca_spar(no, "controller")
    dev = ctrl == "MUSSTMCA"?"GPIB":mca_spar(no, "device_id")
    resp = mca_spar(no, "responsive")

    tty_cntl("md"); printf("%2d : ", no); tty_cntl("me")
    printf("%s - %s - %s - %s - %s\n", \
        ctrl, dev, resp?"Responsive":"Unresponsive", \
        MCA_ACTIVE[no]?"Active":"Inactive", MCA_ON[no]?"ON":"OFF")
}'

#%IU%
#%MDESC% print the menu of all the set in the config MCAs
def _mcamenu '{
    local _mca_u interact ok str

    if (!MCAS) {
        tty_cntl("md")
        printf("No MCA configured !!")
        tty_cntl("me")
        exit
    }

    _mca_u = -1
    interact = ($# == 0)
    while (1) {
        ok = 1
        if (interact) {
            clscreen()
            tty_cntl("md")
            printf("\n\n\nMCA Devices Configured:\n\n")
            tty_cntl("me")
            mcalist

            tty_cntl("ue")
            tty_cntl("md"); printf("\n%2d : ", 99); tty_cntl("me")
            printf("Plot Frequency -        <%0.1f>\n\n", MCA_PLOT_UPD)

            while ((++_mca_u < MCAS) && \
                !mca_spar(_mca_u, "responsive"));
            _mca_u = (_mca_u < MCAS) ? _mca_u : -1
            str = "\n\tMCA number or -1 to Exit"
            _mca_u = getval(str, _mca_u)
            if (_mca_u < 0)
            break
            else if (_mca_u == 99) {
                print
                MCA_PLOT_UPD = getval("        Plot Frequency", MCA_PLOT_UPD)
                _mca_u = -1
                continue
            }
            if (!mca_spar(_mca_u, "responsive")) {
                str = "\nMCA device %d is Unresponsive. Do " \
                    "you want to configure it anyway"
                ok = yesno(sprintf(str, _mca_u), 0)
            }

        } else {
            _mca_u = int($1)
        }

        if (_mca_u >= MCAS) {
            _mcamsg(_mca_u, "Device not in spec config !!")
            ok = 0
        }

        if (ok)
            _mcasubmenu(_mca_u)

        if (!interact)
        break
    }
}'

#%IU% (no)
#%MDESC% Configure the MCA %B%no%B% when using the mcasetup menu
def _mcasubmenu(no) '{
    local ii desc option gui str

    _mcadefaults(no)
    option = 1
    while (option) {
        clscreen()
        tty_cntl("md"); printf("\t\t< MCA SETUP >\n"); tty_cntl("me")
        _mcalist(no)
        tty_cntl("us")
        printf("                                                             \n\n")
        tty_cntl("ue")
        printf("\n  1 - MCA ACTIVE . . . . . . . . . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_ACTIVE[no]?"YES":"NO")
        tty_cntl("me")

        printf("\n  2 - AUTO-RUN in ct/scan . . . . . . . . . . . . . . .:")
        tty_cntl("md")
        printf("<%s>", MCA_ON[no]?"ON":"OFF")
        tty_cntl("me")
        printf("\n      21 - TIME mode . . . . . . . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_PAR[no]["tmode"]?"Live":"Real")
        tty_cntl("me")
        printf("\n      22 - SYNCHRO . . . . . . . . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_PAR[no]["sync"]?"External":"Internal")
        tty_cntl("me")
        printf("\n      23 - AUTO-CLEAR memory . . . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_PAR[no]["noclear"]?"NO":"YES")
        tty_cntl("me")
        printf("\n      24 - Read ROI(s) spectra only . . . . . . . . . .:")
        tty_cntl("md")
        printf("<%s>", MCA_PAR[no]["whole"]?"YES":"NO")
        tty_cntl("me")

        printf("\n  3 - Memory group Size - Active . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%d - %d>", MCA_MEM[no]["size"], MCA_MEM[no]["num"])
        tty_cntl("me")

        printf("\n  4 - SAVE spectrum during SCANS . . . . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_SAVE[no]["scan"]?"YES":"NO")
        tty_cntl("me")
        printf("\n  5 - SAVE spectrum after CT or MCAACQ . . . . . . . . :")
        tty_cntl("md")
        printf("<%s>", MCA_SAVE[no]["acq"]?"YES":"NO")
        tty_cntl("me")
        if ((MCA_SAVE[no]["scan"] == 1) || (MCA_SAVE[no]["acq"] == 1)) {
            printf("\n  6 - SAVE options . . . . . . . . . . . . . . . . . . :")
            printf("\n      61 - Reduction factor . . . . . . . . . . . . . .:")
            tty_cntl("md")
            printf("<%d>", MCA_SAVE[no]["red"]>0?MCA_SAVE[no]["red"]:1)
            tty_cntl("me")
            printf("\n      62 - Data format . . . . . . . . . . . . . . . . :")
            tty_cntl("md")
            printf("<%s>", MCA_SAVE[no]["fmt"])
            tty_cntl("me")
            printf("\n      63 - Save to standard datafile . . . . . . . . . :")
            tty_cntl("md")
            printf("<%s>", MCA_SAVE[no]["std"]?"YES":"NO")
            tty_cntl("me")

            if (MCA_SAVE[no]["std"]) {
                printf("\n           Current: %s", DATAFILE)
                printf("\n           Scan No: %d", SCAN_N)
            } else {
                tty_cntl("me")
                printf("\n           63.1 - Save each spectra in a separate file :")
                tty_cntl("md")
                printf("<%s>", MCA_SAVE[no]["onefile"]?"YES":"NO")
                tty_cntl("me")
                if (MCA_SAVE[no]["onefile"]) {
                    printf("\n              ==> Save to: %s_%d_%03d%s", \
                        MCA_SAVE[no]["prefix"], no, MCA_N, MCA_SUFFIX)
                    printf("\n                       or: %s_%d_<s>_<p>%s in scans", \
                        MCA_SAVE[no]["prefix"], no, MCA_SUFFIX)
                } else {
                    printf("\n              ==> Save to: %s%s", \
                        MCA_SAVE[no]["prefix"], MCA_SUFFIX)
                }
            }
        }
        printf("\n  7 - GUI  . . . . . . . . . . . . . . . . . . . . . . :")
        gui = MCA_PAR[no]["gui"]
        gui == 0?(str = "OFF"):gui == 1?(str = "mcatcl"):\
            gui == 2?(str = "PyMca"):gui == 3?(str = "newplot"):(str = "????")
        tty_cntl("md")
        printf("<%s>", str)
        tty_cntl("me")

        option = getval("\n\n\n\t     Option  ", 0)
        printf("\n\n")
        if (option) {
            if (option == 1) {
                MCA_ACTIVE[no]= MCA_ACTIVE[no]?0:1
                if (!MCA_ACTIVE[no] && MCA_ON[no])
                _mcaoff(no)
            }

            if (option == 2) {
                if (!MCA_ON[no])
                _mcaon(no)
                else
                _mcaoff(no)
            }
            if (option == 21) {
                if (MCA_PAR[no]["MUSSTMCA"]) {
                    MCA_PAR[no]["tmode"]= 0
                    MCA_PAR[no]["type"] = 2
                } else
                MCA_PAR[no]["tmode"]= MCA_PAR[no]["tmode"]?0:1
            }
            if (option == 22) {
                MCA_PAR[no]["sync"]= MCA_PAR[no]["sync"]?0:1
            }
            if (option == 23) {
                MCA_PAR[no]["noclear"]= MCA_PAR[no]["noclear"]?0:1
            }
            if (option == 24) {
                MCA_PAR[no]["whole"]= MCA_PAR[no]["whole"]?0:1
            }
            if (option == 3) {
                MCA_MEM[no]["size"]= \
                    getval("- Memory group size", MCA_MEM[no]["size"])
                MCA_MEM[no]["num"]= \
                    getval("- Active group", MCA_MEM[no]["num"])
            }

            if (option == 4) {
                MCA_SAVE[no]["scan"]= MCA_SAVE[no]["scan"]?0:1
                if (MCA_ON[no])
                _mcaon(no)
            }

            if (option == 5) {
                MCA_SAVE[no]["acq"]= MCA_SAVE[no]["acq"]?0:1
                if (MCA_ON[no])
                _mcaon(no)
            }
            if (option == 6 || option == 61) {
                MCA_SAVE[no]["red"] = \
                    getval(" - Mca reduction coefficient", MCA_SAVE[no]["red"])
                MCA_SAVE[no]["red"] = MCA_SAVE[no]["red"]>0?MCA_SAVE[no]["red"]:1
            }
            if (option == 6 || option == 62) {
                MCA_SAVE[no]["fmt"]= \
                    getval(" - Data format", MCA_SAVE[no]["fmt"])
            }
            if (option == 6 || option == 63) {
                MCA_SAVE[no]["std"]= \
                    yesno(" - Save to standard datafile", MCA_SAVE[no]["std"])
            }
            if (!MCA_SAVE[no]["std"] && (option == 63.1 || option == 6 || option == 63)) {
                MCA_SAVE[no]["onefile"] = \
                    yesno(" - Save each spectra in separate file?", \
                    MCA_SAVE[no]["onefile"])
                if (MCA_SAVE[no]["onefile"]) {
                    str = " - File prefix - specify full directory path"
                    MCA_N = getval(" - Current Mca Number", MCA_N)
                } else
                str = " - File name - specify full directory path"
                MCA_SAVE[no]["prefix"] = \
                    getval(sprintf ("%s", str), MCA_SAVE[no]["prefix"])
            }
            if (option == 7) {
                if (MCA_PAR[no]["gui"])
                _mcaguioff(no)
                else {
                    MCA_PAR[no]["gui"] = \
                        getval(" - Use which gui (off = 0, mcatcl = 1, PyMca = 2, newplot = 3)", \
                        MCA_PAR[no]["gui"])
                    if (MCA_PAR[no]["gui"] != 0)
                    MCA_PAR[no]["guiconf"] = MCA_PAR[no]["gui"]
                    _mcaguion(no)
                }
            }
        }
    }
    if (MCA_ACTIVE[no]) {
        _mcasetup(no)
    }
    else {
        _mcamsg(no, "Device INACTIVE.")
    }
}'

# ---------------------------------------------------------
# DEVICE ON/OFF
# ---------------------------------------------------------
#%UU% [<device_no>]
#%MDESC% Set all MCA devices ON, or only <device_no>
#%BR% If device is on, it is used in standard acquisition macros (scans, ct)
def mcaon '{
    local ii

    if ($#)
    _mcaon($1)
    else {
        for (ii = 0; ii<MCAS; ii++)
        _mcaon(ii)
    }
}'

#%IU% (no)
#%MDESC% Set MCA device %B%no%B% ON
def _mcaon(no) '{

    if (mca_spar(no, "auto_run", 1) == -1) {
        _mcamsg(no, "Cannot set auto-run. Device set OFF.")
        MCA_ON[no]= 0
        _mcadeldef(no)
    } else {
        MCA_ON[no]= 1
        MCA_ACTIVE[no]= 1
        _mcacdef(no)
        #_mcamsg(no, "ON")
    }
}'

#%UU%[<device_no>]
#%MDESC% Set all MCA devices OFF, or only <device_no>
def mcaoff '{
    local ii
    if ($#) _mcaoff($1)
    else for (ii = 0; ii < MCAS; ii++)
    _mcaoff(ii)
}'

#%IU% (no)
#%MDESC% Set MCA device %B%no%B% OFF
def _mcaoff(no) '{
    MCA_ON[no]= 0
    mca_spar(no, "auto_run", 0)
    #_mcamsg(no, "OFF")
}'

#%IU%
#%MDESC%
# Since spec version 6, this pb is fixed so reconfig set auto_run to 0
# When doing reconfig, spec sets auto_run to 1 even if mca is off in the macro.
# %BR% So, before counting, if mca is off (MCA_ON[]=0), we force auto_run to 0.
# This will avoid difference between MCA_ON and internal auto_run flag.
def _mcacheckoff() '{
    local ii
    for (ii = 0; ii<MCAS; ii++) {
        if ( mca_spar(ii, "responsive")) {
            if(MCA_ON[ii]) mca_spar(ii, "auto_run", 1)
            else mca_spar(ii, "auto_run",0)
        }
    }
}'

# ---------------------------------------------------------
# DEVICE ACTIVE
# ---------------------------------------------------------

#%UU% [device_no]
#%MDESC% Set MCA device number <device_no> ACTIVE.
#%BR% If device is active, it is used in mca acquisition macro (mcaacq)
def mcaactive '{
    if (!$#) {
        printf ("mcaactive [mca_device_no]\n")
    } else {
        if (mca_spar($1, "responsive") != 1) {
            _mcamsg($1, "Device unresponsive. Cannot set active.")
            MCA_ACTIVE[$1]= 0
        } else {
            MCA_ACTIVE[$1]= 1
            if (MCA_PAR[$1]["gui"])
            _mcaguiopen($1)
            _mcamsg($1, "Set ACTIVE.")
        }
    }
}'

#%UU% [device_no]
#%MDESC% Set MCA device number <device_no> INACTIVE.
def mcainactive '{

    if (!$#) {
        printf ("mcainactive [mca_device_no]\n")
    } else {
        MCA_ACTIVE[$1]= 0
        if (MCA_PAR[$1]["gui"]) _mcaguiclose($1)
        _mcamsg($1, "Set INACTIVE.")
    }
}'

# ---------------------------------------------------------
# DEVICE SETUP
# ---------------------------------------------------------

#%UU% <no> [<size> <num> <tmode> <sync> <noclear> <gui> <scan> <acq> <std> <prefix> <red> <fmt> <whole> <type>]
#%MDESC% MCA device setup
#%BR%If no arguments, or only <no>, run an interactive menu.
#%BR%If arguments are given, setup mca silently
#%BR%Arguments are:
#%BR%%B%no%B%: device number as in spec config
#%BR%%B%size%B%: memory size (default read from device)
#%BR%%B%num%B%: memory group number (default 0)
#%BR%%B%tmode%B%: time mode = 0:real time, 1:live time (default 0)
#%BR%%B%sync%B%: sync mode = 0:Internal, 1:External (default 0)
#%BR%%B%noclear%B%: do not clear buffer between several mcaacq (default 0)
#%BR%%B%scan%B%: save spectrum during scans (default 0)
#%BR%%B%acq%B%: save spectrum during mcaacq/ct (default 0)
#%BR%%B%std%B%: save spectrum to standard file (default 0)
#%BR%%B%prefix%B%: mca file prefix (default =\"data\")
#%BR%%B%red%B%: spectrum reduction factor (default = 1 = no reduction)
#%BR%%B%fmt%B%: file dump format as used in data_dump (default = %%16C)
#%BR%%B%whole%B%: read whole spectra or not (default = 0 - whole)
#%BR%%B%type%B%: MCA controller type AIM/MAX = 0, MMAX = 1, MUSST = 2 (default = 0-AIM)
def mcasetup '{
    if ($# == 0) {
        _mcamenu
    } else if ($# == 1) {
        _mcamenu $1
    } else {
        MCA_ACTIVE[$1]= 1
        if ($#>1) MCA_MEM[$1]["size"] = $2
        if ($#>2) MCA_MEM[$1]["num"] = $3
        if ($#>3) MCA_PAR[$1]["tmode"] = $4
        if ($#>4) MCA_PAR[$1]["sync"] = $5
        if ($#>5) MCA_PAR[$1]["noclear"] = $6
        if ($#>6) MCA_PAR[$1]["gui"] = $7
        if ($#>7) MCA_SAVE[$1]["scan"] = $8
        if ($#>8) MCA_SAVE[$1]["acq"] = $9
        if ($#>9) MCA_SAVE[$1]["std"] = $10
        if ($#>10) MCA_SAVE[$1]["prefix"] = "$11"
        if ($#>11) MCA_SAVE[$1]["red"] = $12
        if ($#>12) MCA_SAVE[$1]["fmt"] = "$13"
        if ($#>13) MCA_PAR[$1]["whole"] = "$14"
        if ($#>14) MCA_PAR[$1]["type"] = $15
        _mcadefaults($1)
        _mcasetup($1)
        MCA_IN_SCAN = 0
    }
}'

def mcaunsetup '{
    local no
    if ($# == 1) {
        MCA_ON[no]= 0
        MCA_ACTIVE[no]= 0
        _mcadeldef(no)
    } else {
        local no
        for (no = 0; no<16; no++)
        _mcadeldef(no)
        unglobal MCA_ON MCA_ACTIVE
        global MCA_ON[] MCA_ACTIVE[]
        cdef("", "", "_mca", "delete")
    }
}'

#%IU% (no)
#%MDESC% Setup defaults parameters for MCA device <no>.
#
def _mcadefaults(no) '{
    local maxsize
    if (MCA_MEM[no]["size"] <= 0) {
        maxsize = mca_spar(no, "max_channels")
        MCA_MEM[no]["size"]= maxsize>0?maxsize:8191
        MCA_MEM[no]["num"]= 0
    }
    MCA_SAVE[no]["red"]= MCA_SAVE[no]["red"]>0?MCA_SAVE[no]["red"]:1
    if (!length(MCA_SAVE[no]["prefix"])) MCA_SAVE[no]["prefix"]= "data"
    if (!length(MCA_SAVE[no]["fmt"])) MCA_SAVE[no]["fmt"]= "%16C"
    if (!MCA_SAVE[no]["scan"]) MCA_SAVE[no]["save"]= 0
    if (!MCA_SAVE[no]["acq"]) MCA_SAVE[no]["acq"]= 0
    if (!MCA_SAVE[no]["std"]) MCA_SAVE[no]["std"]= 0
    if (!MCA_PAR[no]["whole"]) MCA_PAR[no]["whole"]= 0
    if (!MCA_PAR[no]["tmode"]) MCA_PAR[no]["tmode"]= 0
    if (!MCA_PAR[no]["sync"]) MCA_PAR[no]["sync"]= 0
    if (!MCA_PAR[no]["noclear"]) MCA_PAR[no]["noclear"]= 0
    if (MCA_PAR[no]["gui"])
    MCA_PAR[no]["guiconf"] = MCA_PAR[no]["gui"]
    if (!MCA_PAR[no]["guiconf"])
    MCA_PAR[no]["guiconf"] = 2
    if (!MCA_PAR[no]["type"]) MCA_PAR[no]["type"] = 0
}'

#%IU% (no)
#%MDESC% Setup the MCA device %B%no%B%.
#%BR% If setup failed, the device is set inactive
def _mcasetup(no) '{
    local i controller
    controller = mca_spar(no, "controller")
    # SPEC now support UDP (MYTHEN) and TCP (MYTHEN2) protocol
    # depending of the mythen detector fireware version (1.x or 2.x), see help mythen
    if (controller == "MYTHEN" || controller == "MYTHEN2") controller = "MYTHEN"
    MCA_PAR[no][controller] = 1

    if (MCA_PAR[no]["MUSSTMCA"]) {
        MCA_PAR[no]["type"] = 2
    }
    else if (MCA_PAR[no]["PSE_MAC_MCA"]) {
        MCA_PAR[no]["device_id"] = mca_spar(no, "device_id")
        __MultiMCA_debug "Macro MCA controller !!!! " MCA_PAR[no]["device_id"]
    }
    else if (MCA_PAR[no]["MYTHEN"]) {
        ;
    }
    else {
        dev = mca_spar(no, "device_id")
        if (dev) {
            MCA_PAR[no]["device_id"] = dev
            esrf_io(dev, "tcp")
            esrf_io(dev, "timeout", 1000)
        }
    }

    if (mca_spar(no, "responsive") != 1) {
        _mcamsg(no, "Device unresponsive. Setup aborted.")
        MCA_ACTIVE[no]= 0
    } else if (!_mcamemsetup(no)) {
        _mcamsg(no, "Cannot setup memory. Setup aborted.")
        MCA_ACTIVE[no]= 0
    } else {
        if (MCA_PAR[no]["noclear"]) mca_spar(no, "auto_clear", 0)
        else _mcaio(no, "auto_clear", 1)

        if (MCA_PAR[no]["MUSSTMCA"]) {
            MCA_PAR[no]["tmode"]= 0
        }
        else {
            if (MCA_PAR[no]["tmode"]) mca_spar(no, "live")
            else _mcaio(no, "real")
        }
        if ((! MCA_PAR[no]["MYTHEN"]) && (MCA_PAR[no]["sync"])) {
            mca_spar(no, "soft_preset", 0)
            if (MCA_PAR[no]["MUSSTMCA"]) mca_spar(no, "gate", 1)
        }
        else { # MYTHEN and Can556 always in soft_preset
               # otherwise, count time will set to zero
            mca_spar(no, "soft_preset", 1)
            if (MCA_PAR[no]["MUSSTMCA"]) mca_spar(no, "gate", 0)
        }

        if (MCA_PAR[no]["gui"]) _mcaguion(no)
        else _mcaguioff(no)

        if (MCA_PAR[no]["whole"] != 0) {
            if (MCA_ROI[0] == 0) {
                mca_spar(no, "auto_run", 0)
                MCA_ON[no] = 0
            }
        }
        _mcaroisetup(no)
        _mcacdef(no)
        _mcamsg(no, "Setup done.")
    }
}'

#%IU% (no)
#%MDESC% Get the pseudo counter configuration for all defined for MCA
#device %B%no%B% ROIs. Return 0 if no ROI configured, nb of rois otherwise.
def _mcaroisetup(no) '{
    local i cnt

    for (i = 1; i <= MCA_ROI[0]; i++) {
        cnt = MCA_ROI[i]
        list_setpar(MCA_ROI, cnt, "cntconf", cnt_num(cnt))
    }
    return(MCA_ROI[0])
}'

#%IU% (no)
#%MDESC% Setup memory parameters for device <no>
#%BR% Return 1 on success, 0 otherwise.
def _mcamemsetup(no) '{
    local maxsize, gsize, gnum, maxgrp
    if ( ((maxsize = _mcaio(no, "max_channels")) == -1) || \
        ((gsize = _mcaio(no, "group_size")) == -1) || \
        ((gnum = _mcaio(no, "select_group")) == -1) ) {
        return 0
    }

    if (MCA_MEM[no]["size"] > maxsize) MCA_MEM[no]["size"] = maxsize
    if (MCA_MEM[no]["size"] <= 0) return 0 #HW# changed < to <=, causes div.by.zero further down
    if (MCA_MEM[no]["size"] != gsize) {
        MCA_MEM[no]["size"] = _mcaio(no, "group_size", MCA_MEM[no]["size"])
        if (MCA_MEM[no]["size"] <= 0) return 0 #HW# changed < to <=, causes div.by.zero further down
    }

    maxgrp = maxsize/MCA_MEM[no]["size"] - 1
    if (MCA_MEM[no]["num"]>maxgrp) MCA_MEM[no]["num"] = 0
    if (MCA_MEM[no]["num"] != gnum) {
        MCA_MEM[no]["num"] = _mcaio(no, "select_group", MCA_MEM[no]["num"])
        if (MCA_MEM[no]["num"]<0) return 0
    }
    _mcaarraycreate(no)
    return 1
}'

#%IU% (no, command, argument)
#%MDESC% Send command to device %B%no%B%.
def _mcaio(no, command, argument) '{
    local ret
    # ~ __MultiMCA_debug "_mcaio(" no", "command", "argument")"
    # one works the other doesn`t but both are needed by the present macros
    if ((MCA_PAR[no]["MYTHEN"] || \
      MCA_PAR[no]["ROENTEC"] || \
      MCA_PAR[no]["DXP"]) && (command == "group_size")) {
        command = "max_channels"
    } else if (MCA_PAR[no]["PSE_MAC_MCA"]) {
        if ( command == "start") command = "On"
        if ( command == "elapsed_live,") command = "LiveTime"
        if ( command == "elapsed_real") command = "RealTime"
        if ( command == "dead") return 0
    } else {
        if (MCA_PAR[no]["MYTHEN"]) {
            if (index(MCA_AVOID_CMDS_MYTHEN, command)) {
                return
            }
        }
        else if (MCA_PAR[no]["ROENTEC"]) {
            if (index(MCA_AVOID_CMDS_ROENTEC, command)) {
                return
            }
        }
        else if (MCA_PAR[no]["DXP"]) {
            if (index(MCA_AVOID_CMDS_DXP, command)) {
                return
            }
        }
    }
    if (length(argument)) {

        ret = mca_spar(no, command, argument)
        if (ret < 0) ret = mca_spar(no, command)
    } else {
        ret = mca_spar(no, command)
    }
    return ret
}'

#%IU% (no)
#%MDESC% Hooks MCA operation to the standard macros for device %B%no%B%.
def _mcacdef(no) '{
    local key

    #general acquitistion
    cdef("prompt_mac", "MCA_IN_SCAN=0;", "_mca")
    cdef("user_prescan_head", "MCA_IN_SCAN=1;", "_mca")
    cdef("user_scan_tail", "MCA_IN_SCAN=0;", "_mca")
    cdef("user_countersrun", "if(wait(0x24)) return(1);", "_mca")
    cdef("user_prepcount", "_mcacheckoff();", "_mca", 0x10)

    key = sprintf("_mca%d", no)
    cdef("user_prepcount", sprintf("_mcaclearct(%d);", no), key, 0)
    cdef("user_getcounts", sprintf("_mcareadct(%d); _mcareadroi(%d);", no, no), key)

    #TIMES#
    cdef("user_getcounts", sprintf("S[mcaLt%d]=MCA_TIMES[%d][\"live\"];", \
        no, no), sprintf("mcaLt%d", no), 0x02)
    cdef("user_getcounts", sprintf("S[mcaRt%d]=MCA_TIMES[%d][\"real\"];", \
        no, no), sprintf("mcaRt%d", no), 0x02)
    cdef("user_getcounts", sprintf("S[mcaDt%d]=MCA_TIMES[%d][\"dead\"];", \
        no, no), sprintf("mcaDt%d", no), 0x02)

    cdef("user_Fheader", sprintf("mcasavescanheader %d;", no), key)
    cdef("user_scan_loop", sprintf("mcasavescandata %d;", no), key)

    cdef("user_handlecounts", "mcasavect;", "_mca")
}'

#%IU% (no)
#%MDESC% Un-Hooks MCA operation to the standard macros for device %B%no%B%.
def _mcadeldef(no) '{

    cdef("", "", sprintf("_mca%d", no), "delete")
    cdef("", "", sprintf("mcaLt%d", no), "delete")
    cdef("", "", sprintf("mcaRt%d", no), "delete")
    cdef("", "", sprintf("mcaDt%d", no), "delete")
}'

# ---------------------------------------------------------
# DATA ARRAY
# ---------------------------------------------------------

#%IU% (no)
#%MDESC% Create data array %B%MCA_DATAno%B% where %B%no%B% is the MCA device
#number. If the array already exists, check its size and eventually change it.
def _mcaarraycreate(no) '{
    local carr darr size

    darr = sprintf("MCA_DATA%d", no)
    size = MCA_MEM[no]["size"]
    MCA_SAVE[no]["cmin"] = 0
    MCA_SAVE[no]["cmax"] = size-1
    if (!whatis(darr) || (size != array_op("rows", @darr))) {
        shared ulong array @darr[size][2]
    }
    array_op("fill", @darr[][0])
    if (MCA_SAVE[no]["red"]>1) {
        darr = sprintf("MCA_DATARED%d", no)
        size = MCA_MEM[no]["size"]/MCA_SAVE[no]["red"]
        if (!whatis(darr)) {
            ulong array @darr[size][2]
        } else if (size != array_op("rows", @darr)) {
            ulong array @darr[size][2]
        }
    }
    carr = sprintf("MCA_DATA%d_PARAM", no)
    if (!whatis(carr)) {
        shared double array @carr[3]
    }
    if (@carr == 0)
    @carr[1] = 1
}'

#%IU% (no)
#%MDESC% Reset data array MCA_DATAno where %B%no%B% is the MCA device number.
def _mcaarrayclear(no) '{
    local darr
    darr = sprintf("MCA_DATA%d", no)
    @darr[][1]= 0
}'

#%IU% (no)
#%MDESC% Read in data from MCA to array MCA_DATAno where %B%no%B% is the MCA
#device number.
def _mcaarrayread(no) '{
    local darr i j tmpch[]
    local chmin chmax
    local mne val

    darr = sprintf("MCA_DATA%d", no)
    if (!MCA_ROI[0]) {
        chmin = 0
        chmax = MCA_MEM[no]["size"]-1
    } else {
        if (!MCA_PAR[no]["whole"]) {
            chmin = 0
            chmax = MCA_MEM[no]["size"]-1
        } else {
            if (MCA_ROI[MCA_ROI[1]]["device"] == no) {
                j = 0
                chmin = 0
                chmax = 0
                for (i = 1; i <= MCA_ROI[0]; i++) {
                    mne = MCA_ROI[i]
                    val = cnt_num(mne)
                    if (val != -1) {
                        if (counter_par(mne, "disable") == 0) {
                            tmpch[0] = list_getpar(MCA_ROI, MCA_ROI[i], "min")
                            tmpch[1] = list_getpar(MCA_ROI, MCA_ROI[i], "max")
                            if (j == 0) {
                                chmin = tmpch[0]
                                chmax = tmpch[1]
                            } else {
                                if (tmpch[0] < chmin)
                                chmin = tmpch[0]
                                if (tmpch[1] > chmax)
                                chmax = tmpch[1]
                            }
                            j++
                        }
                    }
                }
            }
            if (AE_DOSCAN) {
                chmin = ch[0]
                chmax = ch[1]
            }
        }
    }
    MCA_SAVE[no]["cmin"] = chmin
    MCA_SAVE[no]["cmax"] = chmax
    if (chmin != chmax) {
        mca_sget(no, @darr[chmin:chmax][1], chmin, chmax)
    }
}'

# ---------------------------------------------------------
# ACQUISITION
# ---------------------------------------------------------

#%IU% ()
#%MDESC% Get number of active mca devices
def _mcanbactive() '{
    local nb no
    nb = 0
    for (no = 0; no < MCAS; no++) nb += MCA_ACTIVE[no]
    return nb
}'

#%UU% [counting_time]
#Do an acquisition for %B%counting_time%B% seconds or until manual stop if
#no time sp[ecified.
def mcaacq '{
    local no stimer nbmca ask_time actmca

    ask_time = $1
    HEADING = "mcaacq $*"
    stimer = 0
    nbmca = 0

    mcastop
    for (no = 0; no < MCAS; no++) {
        if (MCA_ACTIVE[no]) {

            __MultiMCA_debug "active "no
            if (!MCA_PAR[no]["noclear"]) _mcaclear(no)
            if (MCA_PAR[no]["sync"]) {
                stimer = 1
                __MultiMCA_debug "sync: " MCA_PAR[no]["sync"] " " stimer
            } else {
                local presetmca
                if (MCA_PAR[no]["MUSSTMCA"] || MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
                    COUNT_TIME = ask_time
                } else {
                    COUNT_TIME = ask_time ? ask_time : 1000000000 # about 11000 days :-)
                }
                #HW11/3/2008
                # in case of continuing counting for a fixed amount of time,
                # we need to know, where we are to add the new count time.
                if (COUNT_TIME) {
                    presetmca = _mcaio(no, "elapsed_live") + COUNT_TIME
                }
                __MultiMCA_debug "presetmca: " presetmca*1.0
                #HW11/3/2008
                # Hmm, I guess this needs setting with internal sync.
                _mcapreset(no, presetmca)
                #        _mcapreset(no, COUNT_TIME)
            }
            nbmca += MCA_ACTIVE[no]
            actmca = no
        }
    }
    if (!nbmca) {
        _mcamsg("all", "No active MCA device. Abort.")
        exit
    }

    for (no = 0; no < nbmca-1; no++)
        print

    no = actmca
    mcastart

    if (stimer)
        tcount(COUNT_TIME ? COUNT_TIME : 1800)
    mcawait
    if (stimer)
        stop(2)

    mcaread
    mcatimes
    mcasaveacq
    for (no = 0; no < nbmca-1; no++)
        print
}'

#%UU% [<device_no>]
#%MDESC% Stop acquisition on all active device or only on %B%device_no%B%.
def mcastop '{
    local ii

    if ($#) _mcastop($1)
    else {
        for (ii = 0; ii < MCAS; ii++) {
            if (MCA_ACTIVE[ii]) _mcastop(ii)
        }
    }
}'

#%IU% (no)
#%MDESC% Stop acquisition on device %B%no%B%.
def _mcastop(no) '{
    if (MCA_PAR[ii]["sync"]) {
        if (wait(0x22)) stop(2)
    }
    if (MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
        tango_io(mca_spar(no, "address"), "Off")
    } else
    if (wait(0x24)) mca_spar(no, "halt")
}'

#%UU% [device_no]
#%MDESC% Clear memory for all active device or only on %B%device_no%B%.
def mcaclear '{
    local ii

    if ($#) {
        _mcaio($1, "clear")
        _mcaclear($1)
    } else {
        for (ii = 0; ii < MCAS; ii++) {
            if (MCA_ACTIVE[ii]) {
                _mcaio(ii, "clear")
                _mcaclear(ii)
            }
        }
    }
}'

#%IU% (no)
#%MDESC% Clear the memory and the arrays on MCA %B%no%B%.
def _mcaclear(no) '{
    _mcaio(no, "clear")
    _mcaarrayclear(no)
}'

#%IU% (no)
#%MDESC% Clear the memory and the arrays for MCA %B%no%B% if the device is on.
def _mcaclearct(no) '{
    # Previous behaviour was clear always irrespectively of noclear flag and of being in a scan.
    # Now it will always clear the first point of a scan or if noclear flag is 0
    # or if we are not in a scan.
    if ((NPTS == 0) || (!MCA_PAR[no]["noclear"]) || (!MCA_IN_SCAN))
    {
        if (MCA_ON[no])
        _mcaio(no, "clear")
        _mcaarrayclear(no)
    }
}'

#%UU% [no] <preset_time>
#%MDESC% Set %B%preset_time%B% [s] for all active MCAs or only on MCA %B%no%B%.
def mcapreset '{
    local ii

    if ($# == 2) _mcapreset($1, $2)
    else if ($# == 1) {
        for (ii = 0; ii < MCAS; ii++) {
            if (MCA_ACTIVE[ii]) _mcapreset(ii, $1)
        }
    } else
    printf ("USAGE: mcapreset [<mca_no>] <preset_time>\n")
}'

#%IU% (no, pt)
#%MDESC% Set preset time to %B%pt%B% seconds on mca device %B%no%B%.
def _mcapreset(no, pt) '{
    __MultiMCA_debug "_mcapreset: "  pt
    if (MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
        tango_put(mca_spar(no, "address"), "PresetLiveTime", pt)
    } else
    if (mca_spar(no, "preset", pt)<0) {
        _mcamsg(no, "Cannot preset time. Device set inactive.")
        MCA_ACTIVE[no]= 0
    }
}'

#%UU% [no]
#%MDESC% Start acquisition for all active MCAs or only on  MCA %B%no%B%.
#%BR% !!No preset time set inside this macro: use mcapreset before.
def mcastart '{
    local ii
    if ($#) _mcastart($1)
    else for (ii = 0; ii < MCAS; ii++) {
        if (MCA_ACTIVE[ii]) _mcastart(ii)
    }
}'

#%IU% (no)
#%MDESC% Start acquisition on MCA %B%no%B%.
def _mcastart(no) '{
    if (MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
        tango_io(mca_spar(no, "address"), "On")
    } else
        mca_spar(no, "run")
}'

#%UU% [no]
#%MDESC% Read data and times for all active MCAs or only on MCA %B%no%B%.
def mcaread '{
    local ii

    if ($#)
    _mcaread($1)
    else {
        for (ii = 0; ii < MCAS; ii++) {
            if (MCA_ACTIVE[ii])
            _mcaread(ii)
        }
    }
    mca_user_read
}'

#%IU% (no)
#%MDESC%read out data from mca device %B%no%B%
#%BR% Spectrum are stored in array %B%MCA_DATA<no>%B%
#%BR% Times are stored in array %B%MCA_TIMES%B%. To be used in user_getcounts.
def _mcareadct(no) '{
    if (MCA_ON[no] == 1) {
        if ((MCA_PAR[no]["whole"]) && (MCA_ROI[0] == 0)) {
            mca_spar(no, "auto_run", 0)
            MCA_ON[no] = 0
            return(-1)
        }
        _mcaarrayread(no)
        _mcatimes(no)
    }
}'

#%IU% (no)
#%MDESC% read out data from mca device %B%no%B%
#%BR% Spectrum are stored in array %B%MCA_DATA<no>%B%
#%BR% Times are stored in array %B%MCA_TIMES%B%
def _mcaread(no) '{

    _mcaarrayread(no)
    _mcatimes(no)
}'

#%UU%
#%MDESC% Wait for all device to stop counting
def mcawait '{
    local disp key, ii
    disp = (MCA_PLOT_UPD<COUNT_TIME)?MCA_PLOT_UPD:COUNT_TIME

    def _mca_innerloop \'
        mcaread
        mcatimes
        if (MCA_PAR[no]["gui"])
            mcaguiopen
        mca_user_waitcounts

        key = input(0)
        if (key != "" && key != "\004") { mcakey key }
        mca_user_key
        sleep(disp)
    \'

    # somehow wait() doesn`t catch the get_status of the Can556_cmd().
    # we`ll duplicate code here, ugly, but makes it work today !!!
    if(MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
        # no will come from the calling macro
        while (!tango_io(mca_spar(no, "address"), "State")) {
            _mca_innerloop
        }
    } else {
        while (wait(0x26)) {
            _mca_innerloop
        }
    }
}'

#%UU%
#%MDESC% On-line menu while waiting for acquisition to end.
def mcakey '{
    if ($1 == "s"||$1 == "q") {
        mcastop
        print
        _mcamsg("all", "MCA acquisition STOPPED.")
    }
}'


# ---------------------------------------------------------
# TIMES REPORTING
# ---------------------------------------------------------
#%IU% (no)
#%MDESC% Read mca times and save it in array %B%MCA_TIMES%B%
def _mcatimes(no) '{
    MCA_TIMES[no]["live"]= _mcaio(no, "elapsed_live")
    MCA_TIMES[no]["real"]= _mcaio(no, "elapsed_real")
    MCA_TIMES[no]["dead"]= _mcaio(no, "dead")
    if(MCA_PAR[no]["PSE_MAC_MCA"] && MCA_PAR[no]["device_id"] == "Can556") {
        if (MCA_TIMES[no]["real"] == 0)
            MCA_TIMES[no]["dead"] = 0
        else
            MCA_TIMES[no]["dead"] = 100. * (MCA_TIMES[no]["real"] - MCA_TIMES[no]["live"]) / MCA_TIMES[no]["real"]
    }

}'

#%UU%
#%MDESC% Print out live, real, dead times for all active devices.
#%BR%!!No read is performed: use macro mcaread before
def mcatimes '{
    local pos ii

    pos = 1
    for (ii = MCAS-1; ii >= 0; ii--) {
        if (MCA_ACTIVE[ii]) {
            tty_move(0, -1*pos, \
                sprintf("MCA %d Elapsed times: live %4.2f real %4.2f sec. dead time %3.2f %%   ", \
                ii, MCA_TIMES[ii]["live"], MCA_TIMES[ii]["real"], MCA_TIMES[ii]["dead"]))
        }
        pos++
    }
}'

# ---------------------------------------------------------
# CALIBRATION
# ---------------------------------------------------------

#%UU% [ <no> <A> <B> <C> ]
#%MDESC% With no arguments, runs an interactive menu to set calib coeff.
#%BR% With input arguments, change the calibration shared array
def mcacalib '{
    if ($# == 4)
    _mcacalib($1, $2, $3, $4)
    else
    mcacalibmenu
}'

#%UU%
#%MDESC% Interactive menu to change calibration for all devices
def mcacalibmenu '{
    local option il no carr
    local key

    while (1) {
        il = _mcacalibshow()

        tty_move(0, il++, \
            "MCA number to change, \[us\]\[md\]S\[se\]\[ue\]ave, \[us\]\[md\]L\[se\]\[ue\]oad or \[us\]\[md\]Q\[se\]\[ue\]uit ? ")

    # DOES NOT WORK ANYMORE WITH SPEC > 6.6.4
    # while ((key = input(-1)) == "") { sleep(0.1) }
        # key = substr(key, 1, 1)
    key = getval_one_char("enter key (l, s, q)")

        if (key == "q"||key == "Q") {
           break
    }
        else if (key == "s"||key == "S") {
            printf("\n")
            mcacalibsave
            input("\n... Press Enter ..."); continue
        } else if (key == "l"||key == "L") {
            printf("\n")
            mcacalibload
            input("\n... Press Enter ..."); continue
        } else if (key == "\n")
        continue

        no = int(key)
        if (no >= 0 && no < MCAS) {
            printf("\n\n")
            carr = sprintf("MCA_DATA%d_PARAM", no)
            @carr[0]= getval("\tCoeff.A", @carr[0])
            @carr[1]= getval("\tCoeff.B", @carr[1])
            @carr[2]= getval("\tCoeff.C", @carr[2])
        }
    }
}'

#%IU% (no)
#%MDESC% Return the calibration for MCA %B%no%B%.
def _mcacalibget(no) '{
    local carr

    carr = sprintf("MCA_DATA%d_PARAM", no)
    if (!whatis(carr)) {
        shared double array @carr[3]
        @carr[1] = 1
    }
    return(@carr)
}'

#%UU%
#%MDESC% Show current calibration of all devices
def mcacalibshow '_mcacalibshow()'
def _mcacalibshow() '{
    local il carr
    local no

    clscreen()
    tty_move(0, 1, "\[md\]<MCA CALIBRATION>\[me\]")
    tty_move(0, 3, "MCA    Coeff.A    Coeff.B    Coeff.C")
    tty_move(0, 4, "--- ---------- ---------- ----------")
    il = 5

    for (no = 0; no < MCAS; no++) {
        carr = sprintf("MCA_DATA%d_PARAM", no)
        tty_move(0, il++, sprintf("\[us\]\[md\]%d\[me\]\[ue\] %10.10g %10.10g %10.10g", \
            no, @carr[0], @carr[1], @carr[2]))
    }
    tty_move(0, il++, "")
    return (il)
}'

#%IU% (no, ca, cb, cc)
#%MDESC% Change calibration coeff for mca %B%no%B%.
def _mcacalib(no, ca, cb, cc, silent) '{
    local carr

    carr = sprintf("MCA_DATA%d_PARAM", no)
    if (!whatis(carr)) {
        if (!silent)
        _mcamsg(no, "NO calibration array. Run mcasetup first.")
    } else {
        @carr[0]= ca
        @carr[1]= cb
        @carr[2]= cc
    }
}'

#%UU% [<filename>]
#%MDESC% Save current calibrations to file
#%BR% If no <filename> is specified, use default one.
#%BR% Default filename is BLISSADM/local/spec/userconf/mcacalib.USER
def mcacalibsave '{
    local filename no carr

    if ($# == 1) {
        filename = "$1"
    }
    else {
        filename = sprintf("%s/local/spec/userconf/mcacalib.%s", BLISSADM, USER)
    }
    unix(sprintf("/bin/rm -f %s", filename))

    if (on(filename) == -1) {
        _mcamsg("all", sprintf("Cannot open file %s", filename))
    }
    else {
        offt
        for (no = 0; no < MCAS; no++) {
            carr = sprintf("MCA_DATA%d_PARAM", no)
            printf("%d %g %g %g\n", no, \
                @carr[0], @carr[1], @carr[2])
        }
        ont; close(filename)
        _mcamsg("all", sprintf("Calibrations saved to %s", filename))
    }
}'

#%UU% [<filename>]
#%MDESC% Load MCA calibrations from file. This overrides current calibrations
#%BR% If no <filename> is specified, use default one.
#%BR% Default filename is BLISSADM/local/spec/userconf/mcacalib.USER
def mcacalibload '{
    local file cno totcal line pars[]

    if ($# == 1) {
        file = "$1"
    }
    else {
        file = sprintf("%s/local/spec/userconf/mcacalib.%s", \
            BLISSADM, USER)
    }

    if (unix(sprintf("test -r %s", file))) {
        _mcamsg("all", sprintf("Cannot find calibration file %s", file))
    }
    else {
        totcal = 0
        for (line = getline(file);line != -1;line = getline(file)) {
            if (split(line, pars) == 4) {
                cno = int(pars[0])
                if ((cno >= 0) || (cno < MCAS)) {
                    _mcacalib(cno, pars[1]+0, \
                        pars[2]+0, pars[3]+0, 1)
                    totcal++
                } else
                print "Invalid MCA:", pars[0]
            }
        }
        getline(file, "close")
        _mcamsg("all", sprintf("%d calibrations have been loaded from %s", totcal, file))
    }
}'

# ---------------------------------------------------------
# ROIS
# ---------------------------------------------------------

#%UU% [<roi_mne> <mca_dev> <roi_min> <roi_max> <roi_alias>]
#%MDESC% Define a new roi. If no arguments is given, call mcaroimenu.
#%BR% %B%roi_mne%B% : counter mnemonic
#%BR% %B%mca_dev%B% : mca device number
#%BR% %B%roi_min%B% : roi first channel
#%BR% %B%roi_max%B% : roi last channel
#%BR% %B%roi_alias%B% : roi alias
#%BR% %B%mmax_ch%B% : mmax channel (if appropriate)
#
def mcaroi '{
    if ($# == 4)
    _mcaroiadd("$1", $2, $3, $4, "$5", $6)
    else
    mcaroimenu
}'

#%UU% <roi_mne>
#%MDESC% Deletes ROI <roi_mne>
def mcaroidel '{

    if ($# != 1)
    printf("USAGE: mcadelroi <roi_mne>\n")
    else
    _mcaroidel($1)
}'
#%UU%
#%MDESC% Menu to Add/Modify/Delete/Save/Load rois
def mcaroimenu '{
    local key nb dev min max nroi
    local mmax_ch
    local ip

    if (list_n(MCA_ROI)<0) list_init MCA_ROI

    while (1) {
        ip = _mcaroishow()

        tty_move(0, ip++, \
            "\[md\]A\[se\]dd/\[md\]D\[se\]elete/\[md\]M\[se\]odify, \[md\]S\[se\]ave/\[md\]L\[se\]oad or \[md\]Q\[se\]uit ? ")

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

        if (key == "d"||key == "D") {
            roi = getval("\tCounter mnemonic  ", 0)
            if (roi != "0")
            _mcaroidel(roi)
        } else if (key == "a" || key == "A") {
            roi = getval("\tCounter mnemonic  ", 0)
            if (roi != "0") {
                dev = getval("\tMCA device number ", 0)
                min = getval("\tFirst channel     ", 0)
                max = getval("\tLast channel      ", 1023)
                alias = getval("\tROI alias       ", alias)
                if (MCA_PAR[dev]["type"] == 1) {
                    mmax_ch = getval("\tMMAX channel number (1-8):", 1)
                    list_setpar(MCA_ROI, roi, "mmax_ch", mmax_ch)
                }
                _mcaroiadd(roi, dev, min, max, alias, mmax_ch)
            }
        } else if (key == "m" || key == "M") {
            roi = getval("\nCounter mnemonic  ", roi)
            if (list_check(MCA_ROI, roi) > 0) {
                dev = getval("\tMCA device number ", MCA_ROI[roi]["device"])
                min = getval("\tFirst channel     ", MCA_ROI[roi]["min"])
                max = getval("\tLast channel      ", MCA_ROI[roi]["max"])
                alias = getval("\tROI alias      ", MCA_ROI[roi]["alias"])
                nroi = getval("\tNew mnemonic      ", roi)
                if (MCA_PAR[dev]["type"] == 1)
                mmax_ch = getval("\tMMAX channel number (1-8):", \
                    MCA_ROI[roi]["mmax_ch"])
                if (nroi == roi) {
                    MCA_ROI[roi]["device"] = dev
                    MCA_ROI[roi]["min"] = min
                    MCA_ROI[roi]["max"] = max
                    MCA_ROI[roi]["emin"] = _mcagetE(dev, min)
                    MCA_ROI[roi]["emax"] = _mcagetE(dev, max)
                    MCA_ROI[roi]["alias"] = alias
                    MCA_ROI[roi]["cntconf"] = cnt_num(roi)
                    if (MCA_PAR[dev]["type"] == 1) {
                        MCA_ROI[roi]["mmax_ch"] = mmax_ch
                        _mcammaxroiadd(dev, MCA_ROI[roi]["emin"], MCA_ROI[roi]["emax"], \
                            alias, mmax_ch, 11)
                    }
                } else {
                    _mcaroidel(roi)
                    _mcaroiadd(nroi, dev, min, max, alias, mmax_ch)
                }
            }
        } else if (key == "s" || key == "S") {
            mcaroisave
            input("... Press Enter ...")
        } else if (key == "l" || key == "L") {
            mcaroiload
            input("... Press Enter ...")
        } else if (key == "q" || key == "Q") {
            break
        }
    }
}'

#%UU%
#%MDESC% Show ROIs definition
#
def mcaroishow '_mcaroishow()'
def _mcaroishow() '{
    local ip im ir nroi
    local chmin chmax emin emax str alias
    local carr
    local mstr[] mmax_ch

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

    clscreen()
    tty_move(0, 1, "\[md\]<MCA ROI Definition>\[me\]")
    mstr[3] = sprintf("Counter | MCA | From  | To    |       |       | ROI    |")
    mstr[4] = sprintf("mnemonic|  #  | chan  | chan  | Eini  | Efin  | alias  |")
    mstr[5] = sprintf("--------|-----|-------|-------|-------|-------|--------|")
    if (MCA_PAR[no]["type"] == 1) {
        mstr[3] = sprintf ("%s MMAX |", mstr[3])
        mstr[4] = sprintf ("%s chan |", mstr[4])
        mstr[5] = sprintf ("%s------|", mstr[5])
    }
    for (ip = 3; ip<6; ip++) {
        tty_move(0, ip, mstr[ip])
    }
    for (im = 0; im < MCAS; im++) {
        for (ir = 1; ir <= nroi; ir++) {
            if (list_getpar(MCA_ROI, ir, "device") == im) {
                chmin = list_getpar(MCA_ROI, ir, "min")
                chmax = list_getpar(MCA_ROI, ir, "max")
                carr = sprintf("MCA_DATA%d_PARAM", im)
                if (@carr[0] != 0) {
                    emin = _mcagetE(im, chmin)
                    emax = _mcagetE(im, chmax)
                    list_setpar(MCA_ROI, ir, "emin", emin)
                    list_setpar(MCA_ROI, ir, "emax", emax)
                } else {
                    emin = list_getpar(MCA_ROI, ir, "emin")
                    emax = list_getpar(MCA_ROI, ir, "emax")
                }
                alias = list_getpar(MCA_ROI, ir, "alias")
                mmax_ch = list_getpar(MCA_ROI, ir, "mmax_ch")
                if (mmax_ch == -1)
                mmax_ch = " "
                str = sprintf("%-8s|  %-2d | %-5d | %-5d | %-5d | %-5d | %-7s|", \
                    list_item(MCA_ROI, ir), list_getpar(MCA_ROI, ir, "device"), \
                    chmin, chmax, emin, emax, alias)
                if (@carr[0] != 0)
                str = sprintf("%-8s|  %-2d | %-5d | %-5d | %-5.2f | %-5.2f | %-7s|", \
                    list_item(MCA_ROI, ir), list_getpar(MCA_ROI, ir, "device"), \
                    chmin, chmax, emin, emax, alias)
                if (MCA_PAR[no]["type"] == 1)
                str = sprintf ("%s  %-2s  |", str, mmax_ch)
                tty_move(0, ip++, str)
            }
        }
    }
    ip++
    return (ip)
}'

#%IU% (dev, cnt, min, max, alias)
#%MDESC% Add roi in the list
#
def _mcaroiadd(cnt, dev, min, max, alias, mmax_ch) '{
    local emin emax type
    global _MCA_ROI_ADD
    if (list_n(MCA_ROI)<0) {
    list_init MCA_ROI
    }

    list_add(MCA_ROI, cnt)
    list_setpar(MCA_ROI, cnt, "device", dev)
    list_setpar(MCA_ROI, cnt, "min", min)
    list_setpar(MCA_ROI, cnt, "max", max)
    emin = _mcagetE(dev, min)
    emax = _mcagetE(dev, max)
    list_setpar(MCA_ROI, cnt, "emin", emin)
    list_setpar(MCA_ROI, cnt, "emax", emax)

    if (alias){
    list_setpar(MCA_ROI, cnt, "alias", alias)
    }
    else{
    list_setpar(MCA_ROI, cnt, "alias", cnt)
    }

    type = MCA_PAR[dev]["type"]
    if (type == 1) {
        if ((emin <= 30) && (emin > 0) && (emax > 0) && (emax <= 30)){
            if (mmax_ch == 0)
            mmax_ch = 1
            nb = list_getpar(MCA_ROI, cnt, "elem_nb")
            if (nb == -1)
            nb  = 11
            _mcammaxroiadd(dev, emin, emax, alias, mmax_ch, nb)
            list_setpar(MCA_ROI, cnt, "mmax_ch", mmax_ch)
        }
    }
    list_setpar(MCA_ROI, cnt, "cntconf", cnt_num(cnt))

    _MCA_ROI_ADD = cnt
    mca_user_roi_add
}'

def _mcammaxroiadd(dev, emin, emax, alias, mmax_ch, nb) '{
    global cmd
    cmd = sprintf("%d %d %s %d %d", mmax_ch, nb, alias, \
        int(emin*1000), int(emax*1000))
    p cmd
    #return(esrf_io(dev, "DevMcaSetROI", cmd))
}'

#%IU% (nb, ch)
#%MDESC% Return the energy [keV] as function of the channel %B%ch%B% for the MCA number %B%nb%B%
def _mcagetE(nb, ch) '{
    local carr
    carr = sprintf("MCA_DATA%d_PARAM", nb)
    return(@carr[0] + @carr[1] * ch + @carr[2] * pow(ch, 2))
}'

#%IU% (nb, en)
#%MDESC% Return the channel as function of the energy %B%en%B% [keV] for the MCA number %B%nb%B%
def _mcagetch(nb, en) '{
    local carr
    carr = sprintf("MCA_DATA%d_PARAM", nb)
    if (@carr[2] == 0) {
        if (@carr[1] != 0)
        return(int((en - @carr[0])/@carr[1]))
        else
        return(0)
    }
    if (@carr[1] > 0)
    return (int((-@carr[1]+sqrt(pow(@carr[1], 2)-4*(@carr[0]-en)*@carr[2]))/(2*@carr[2])))
    if (@carr[1] < 0)
    return (int((-@carr[1]-sqrt(pow(@carr[1], 2)-4*(@carr[0]-en)*@carr[2]))/(2*@carr[2])))

}'
#%IU% (cnt)
#%MDESC% Delete roi from the list
def _mcaroidel(cnt) '{
    global _MCA_ROI_DEL

    _MCA_ROI_DEL = cnt
    mca_user_roi_delete
    list_remove(MCA_ROI, cnt)
}'

def _mcareadroi(no) '{
    local i cnt

    if (MCA_ON[no]) {
        for (i = 1; i <= MCA_ROI[0]; i++) {
            cnt = MCA_ROI[i]
            if (MCA_ROI[cnt]["device"] == no)
            _mcaroicounts(MCA_ROI[i])
        }
    }
}'

#%IU% (cnt)
#%MDESC% Hook macro to update roi counter's value
def _mcaroicounts(cnt) '{
    local idev mne darr min max num

    num = cnt_num(cnt)
    if (num == -1)
    return(-1)
    mne = cnt_mne(num)
    if (counter_par(mne, "disable") != 0)
    return(-1)
    darr = sprintf("MCA_DATA%d", list_getpar(MCA_ROI, mne, "device"))
    min = list_getpar(MCA_ROI, mne, "min")
    max = list_getpar(MCA_ROI, mne, "max")
    S[num] = array_op("sum", @darr[min:max][1])
}'

#%UU% [<filename>]
#%MDESC% Save current rois definition to file
#%BR% If no <filename> is specified, use default one.
#%BR% Default filename is BLISSADM/local/spec/userconf/mcaroi.def.USER
#
def mcaroisave '{
    local roi mne filename

    if ($# == 1) {
        filename = "$1"
    } else {
        filename = sprintf("%s/local/spec/userconf/mcaroi.def.%s", BLISSADM, USER)
    }
    unix(sprintf("/bin/rm -f %s", filename))

    if (on(filename) == -1) {
        _mcamsg("all", sprintf("Cannot open file %s", filename))
    } else {
        offt
        for (roi = 1; roi <= list_n(MCA_ROI); roi++) {
            mne = list_item(MCA_ROI, roi)
            printf("%s %2d %5d %5d %5.2f %5.2f %s\n", mne, \
                list_getpar(MCA_ROI, mne, "device"), list_getpar(MCA_ROI, mne, "min"), \
                list_getpar(MCA_ROI, mne, "max"), list_getpar(MCA_ROI, mne, "emin"), \
                list_getpar(MCA_ROI, mne, "emax"), list_getpar(MCA_ROI, mne, "alias"))
        }
        ont; close(filename)
        _mcamsg("all", sprintf("ROI saved to %s", filename))
    }
}'

#%UU% [<filename>]
#%MDESC% Load rois definition from file. This overrides current rois definition.
#%BR% If no <filename> is specified, use default one.
#%BR% Default filename is BLISSADM/local/spec/userconf/mcaroi.def.USER
#
def mcaroiload '{
    local file ir line pars[]
    local alias

    if ($# == 1) {
        file = "$1"
    } else {
        file = sprintf("%s/local/spec/userconf/mcaroi.def.%s", BLISSADM, USER)
    }

    if (unix(sprintf("test -r %s", file))) {
        _mcamsg("all", sprintf("Cannot find roi file %s", file))
    } else {
        for (ir = 1; ir <= list_n(MCA_ROI); ir++)
        _mcaroidel(list_item(MCA_ROI, ir))
        list_init MCA_ROI
        for (line = getline(file);line != -1;line = getline(file)) {
            if (split(line, pars) >= 4) {
                alias = substr(pars[6], 1, length(pars[6]))
                _mcaroiadd(pars[0], int(pars[1]), int(pars[2]), int(pars[3]), alias)
            }
        }
        getline(file, "close")
        _mcamsg("all", sprintf("%d rois have been loaded from %s", \
            list_n(MCA_ROI), file))
    }
}'

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

#%UU% [<no>]
#%MDESC% Set GUI ON for all mca device or just device <no>
#%BR% If not already opened, open gui if device is active
def mcaguion '{
    local ii
    if ($#) {
        MCA_PAR[$1]["gui"] = $2
        _mcaguion($1)
    } else for (ii = 0; ii < MCAS; ii++) {
        _mcaguion(ii)
    }
}'

#%IU% (no)
#%MDESC% Set GUI ON for device <no>
def _mcaguion(no) '{

    if (MCA_ACTIVE[no]) _mcaguiopen(no)
    else _mcaguiclose(no)
}'

#%IU% [<no>]
#%MDESC% Set GUI OFF for all device or just device <no>
#%BR% Close gui if opened.
def mcaguioff '{
    local ii
    if ($#) _mcaguioff($1)
    else for (ii = 0; ii < MCAS; ii++)
    _mcaguiclose(ii)
}'

#%IU% (no)
#%MDESC% Set GUI OFF for device <no>
def _mcaguioff(no) '{
    MCA_PAR[no]["gui"]= 0
    _mcaguiclose(no)
}'

#%UU% [<device_no>]
#%MDESC% Open GUI for <device_no>, or for all active device if <device_no> not specified
def mcaguiopen '{
    local ii
    if ($#) _mcaguiopen($1)
    else for (ii = 0; ii < MCAS; ii++)
    if (MCA_ACTIVE[ii]&&MCA_PAR[ii]["gui"]) _mcaguiopen(ii)
}'

def _mcaguiopen(no) '{

    if (MCA_PAR[no]["gui"]) {
        if (MCA_PAR[no]["guiconf"] != MCA_PAR[no]["gui"]) {
            MCA_PAR[no]["guiconf"] = MCA_PAR[no]["gui"]
            _mcaguiclose(no)
            MCA_PAR[no]["gui"] = MCA_PAR[no]["guiconf"]
        } else
        MCA_PAR[no]["guiconf"] = MCA_PAR[no]["gui"]
    } else
    MCA_PAR[no]["gui"] = MCA_PAR[no]["guiconf"]


    if (!MCA_PID[no] || unix(sprintf("kill -0 %d 2>/dev/null", MCA_PID[no])))
    MCA_PID[no]= _mcaguistart(no)
}'

#%UU% [<device_no>]
#%MDESC% Close GUI for <device_no>, or for all devices if <device_no> not specified
def mcaguiclose '{
    local ii
    if ($#) _mcaguiclose($1)
    else for (ii = 0; ii<MCAS; ii++)
    _mcaguiclose(ii)
}'

def _mcaguiclose(no) '{
    if (MCA_PID[no])
    unix(sprintf("kill -9 %d 2>/dev/null", MCA_PID[no]))
    MCA_PID[no]= 0
    MCA_PAR[no]["gui"] = 0
}'

def _mcaguistart(no) '{
    local mystr
    local pid file guicmd larr

    __MultiMCA_debug "### starting _mcaguistart"
    if (MCA_PAR[no]["gui"] == 1) {
        file = sprintf("/tmp/mcagui_%d_%s_%s.pid", no, SPEC, USER)
        larr = sprintf("MCA_DATA%d", no)
        guicmd = sprintf("mcatcl -ver %s -shm %s", SPEC, larr)
    } else if (MCA_PAR[no]["gui"] == 2) {
        file = sprintf("/tmp/mcagui_%d_%s_%s.pid", no, SPEC, USER)
        larr = sprintf("MCA_DATA%d", no)
        guicmd = sprintf("pymca --spec=%s --shm=%s", SPEC, larr)
        __MultiMCA_debug "### guicmd: " guicmd
    } else if (MCA_PAR[no]["gui"] == 3) {
        larr = sprintf("MCA_DATA%d_PARAM", no)
        mystr = sprintf ("%g:%g:%g", @larr[0], @larr[1], @larr[2])
        larr = sprintf("MCA_DATA%d_ENV", no)
        shared string array @larr [50][50]
        SPS_PutEnv(@larr, "calibration", mystr)

        file = sprintf("/tmp/mcagui_%d_%s_%s.pid", no, SPEC, USER)
        larr = sprintf("MCA_DATA%d", no)
        guicmd = sprintf("newplot -s %s --shm=%s", SPEC, larr)
    }

    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)
}'

# ---------------------------------------------------------
# FILE SAVING
# ---------------------------------------------------------

#%IU%<device_no>
#%MDESC% Save MCA specific header during a scan
def mcasavescanheader '{
    local ii

    if ((MCA_ON[$1]) && (MCA_SAVE[$1]["scan"]) && (MCA_SAVE[$1]["std"])) {
        savemultimcaheader(DATAFILE, $1, 0)
    }
}'

#%IU%<device_no>
#%MDESC% Save MCA data during a scan
def mcasavescandata '{
    local ii

    if (MCA_ON[$1] && (MCA_SAVE[$1]["scan"])) {
        if (MCA_SAVE[$1]["std"]) {
            savemultimcadata(DATAFILE, $1)
        }   else {
            mcasaveprivate($1, 1)
        }
    }
}'

#%IU%
#%MDESC% Save mca header and data after a ct
def mcasavect '{
    local ii nbstd nbpriv
    local std[] priv[]

    nbstd = 0
    nbpriv = 0

    for (ii = 0; ii < MCAS; ii++) {
        if (MCA_ON[ii] && MCA_SAVE[ii]["acq"]) {
            if (MCA_SAVE[ii]["std"]) {
                std[nbstd]= ii
                nbstd++
            }   else {
                priv[nbpriv]= ii
                nbpriv++
            }
        }
    }

    if (nbpriv||nbstd) {
        HEADING = sprintf("ct %s", COUNT_TIME)
        DATE = date()

        if (nbpriv) {
            for (ii = 0; ii<nbpriv; ii++)
            mcasaveprivate(priv[ii], 0)
            MCA_N++
        }

        if (nbstd)
        mcasavestandard(nbstd, std, 1)
    }
}'

#%IU%
#%MDESC% Save mca header and data after a mcaacq
def mcasaveacq '{
    local ii nbstd nbpriv
    local std[]

    nbstd = 0
    nbpriv = 0
    for (ii = 0; ii<MCAS; ii++) {
        if (MCA_ACTIVE[ii] && MCA_SAVE[ii]["acq"]) {
            if (MCA_SAVE[ii]["std"]) {
                std[nbstd]= ii
                nbstd++
            }   else {
                mcasaveprivate(ii, 0)
                nbpriv++
            }
        }
    }
    if (nbpriv) MCA_N++
    if (nbstd) mcasavestandard(nbstd, std, 0)
}'

#%UU%
#%MDESC% Save last acquisition for all active devices
#%BR% Do not consider saving options: save all in mca files
def mcasavelast '{
    local ii

    MCA_N++
    for (ii = 0; ii<MCAS; ii++) {
        if (MCA_ACTIVE[ii]) mcasaveprivate(ii, 0)
    }
}'

#%IU%
#%MDESC% Save mca header and data in standard spec datafile
def mcasavestandard(nb, std, inct) '{

    if (!_mcasavestandard(nb, std, inct)) {
        _mcamsg("all", "ERROR saving spectrum to standard file")
    }
}'

#%IU% (nb, std, inct)
def _mcasavestandard(nb, std, inct) '{
    local ii

    SCAN_N = savestdheader(DATAFILE, 3, SCAN_N)
    if (SCAN_N<0) {
        SCAN_N = -SCAN_N
        return (0)
    }
    for (ii = 0; ii < nb; ii++)
    if (!savemultimcaheader(DATAFILE, std[ii])) return (0)
    if (inct) {
        FPRNT = ""
        if (savecntheader(DATAFILE)<0) return (0)
        if (savecounters(DATAFILE)<0)  return (0)
    }
    for (ii = 0; ii < nb; ii++)
    if (!savemultimcadata(DATAFILE, std[ii])) return (0)
    return (1)
}'

#%IU% (no)
#%MDESC% Save MCA header and data in a private file
#%BR% Return 1 on success, 0 otherwise
#
def mcasaveprivate(no, inscan) '{
    local filename ret
    filename = mcafilename(no, inscan)
    if (!filename) return (0)

    ret = 1
    if (savefileheader(filename) < 0) { ret = 0 }
    if (ret && savestdheader(filename, 3, 0) == -1) { ret = 0 }
    if (ret) ret = savemultimcaheader(filename, no, inscan?0:1)
    if (!inscan) {
        FPRNT = ""
        if (ret) ret = (savecntheader(filename) >= 0)
        if (ret) ret = (savecounters(filename) >= 0)
    }
    if (ret) ret = savemultimcadata(filename, no)

    if (!ret) _mcamsg(no, sprintf("Failed to save spectrum in %s", filename))
    else if (!inscan) _mcamsg(no, sprintf("Saved spectrum to %s", filename))
    close(filename)
}'

#%IU% (no, inscan)
#%MDESC% Create filename for specific mca files
#
def mcafilename(no, inscan) '{
    local prefix fname

    prefix = MCA_SAVE[no]["prefix"]
    if ((prefix == "/dev/null")||(prefix == "/dev/tty")) return prefix
    if ((prefix == "")||(prefix == "0")) return 0

    if (!MCA_SAVE[no]["onefile"])
    fname = sprintf("%s%s", prefix, MCA_SUFFIX)
    else {
        if (inscan) {
            fname = sprintf("%s_%d_%03d_%03d%s", prefix, no, SCAN_N, NPTS, MCA_SUFFIX)
        } else {
            fname = sprintf("%s_%d_%03d%s", prefix, no, MCA_N, MCA_SUFFIX)
        }
    }
    return (fname)
}'

#%IU% (file, no, withtime)
#%MDESC% Save MCA specific header for device <no>
#%BR% If <withtime>!= 0, save counting, live and real times
#%BR% Return 1 on sucess, 0 otherwise
#
def savemultimcaheader(file, no, withtime) '{
    local cmin cmax npts
    local carr
    local nroi

    if (open(file)) return (0)
    fprintf(file, "#@MCADEV %d\n", no)
    fprintf(file, "#@MCA %s\n", MCA_SAVE[no]["fmt"])
    cmin = MCA_SAVE[no]["cmin"]
    cmax = MCA_SAVE[no]["cmax"]
    #cmax = MCA_MEM[no]["size"]-1
    npts = int(cmax/MCA_SAVE[no]["red"]) - int(cmin/MCA_SAVE[no]["red"]) +1
    npts = npts<0?0:npts
    fprintf(file, "#@CHANN %g %g %g %g\n", npts, cmin, cmax, MCA_SAVE[no]["red"])
    if (withtime) {
        fprintf(file, "#@CTIME %g %g %g\n", COUNT_TIME, \
            MCA_TIMES[no]["live"], MCA_TIMES[no]["real"])
    }

    carr = sprintf("MCA_DATA%d_PARAM", no)
    fprintf(file, "#@CALIB %g %g %g\n", @carr[0], @carr[1], @carr[2])

    nroi = list_n(MCA_ROI)
    for (ir = 1; ir <= nroi; ir++) {
        dev = list_getpar(MCA_ROI, ir, "device")
        if (dev == no) {
            fprintf(file, "#@ROI %s %g %g\n", list_item(MCA_ROI, ir), \
                list_getpar(MCA_ROI, ir, "min"), list_getpar(MCA_ROI, ir, "max"))
        }
    }
    return (1)
}'

#%IU% (file, no)
#%MDESC% Save MCA spectrum data for device <no>
#%BR% Return 1 on sucess, 0 otherwise
#
def savemultimcadata(file, no) '{
    local darr chan[]

    if (open(file)) return (0)
    if (MCA_SAVE[no]["red"]>1) {
        _mcadatareduction(no)
        darr = sprintf("MCA_DATARED%d", no)
        chan[0] = int(MCA_SAVE[no]["cmin"]/MCA_SAVE[no]["red"])
        chan[1] = int(MCA_SAVE[no]["cmax"]/MCA_SAVE[no]["red"])
    } else {
        darr = sprintf("MCA_DATA%d", no)
        chan[0] = MCA_SAVE[no]["cmin"]
        chan[1] = MCA_SAVE[no]["cmax"]
    }
    fprintf(file, "@A ")
    on(file);offt
    data_dump(@darr[chan[0]:chan[1]][1], MCA_SAVE[no]["fmt"])
    ont; off(file)
    return (1)
}'

#%IU% (no)
#%MDESC% Computes reduction on %B%MCA_DATA<no>%B%. Results are stored in %B%MCA_DATARED<no>%B%
#
def _mcadatareduction(no) '{
    local darr rarr
    darr = sprintf("MCA_DATA%d", no)
    rarr = sprintf("MCA_DATARED%d", no)
    @rarr[][1]= MCA_SAVE[no]["red"]*array_op("contract", @darr[][1], MCA_SAVE[no]["red"])
}'

# ---------------------------------------------
# Copy data of all MCA_DATAn arrays in MCA_DATA
# ---------------------------------------------
#%UU%
#%MDESC% Read data from all mca ON (arrays MCA_DATAn) and save data in array MCA_DATA
#%BR% Data are written in MCA_DATA in the same order as in spec configuration
def mcalineupon '{
    local size

    size = _mcalineupsize()
    if (size>0) {
        ulong array MCA_DATA[size][2]
        array_op("fill", MCA_DATA[][0])

        cdef("user_prepcount", "_mcalineupclear\n", "_lpmca", 0x20)
        cdef("user_getcounts", "_mcalineupdata\n", "_lpmca", 0x20)
        cdef("mca_user_read", "_mcalineupdata\n", "_lpmca", 0x20)
    }
}'

#%IU% ()
#%MDESC% Computes size needed for MCA_DATA to store all MCA_DATAn arrays
def _mcalineupsize() '{
    local size ii
    size = 0
    for (ii = 0; ii < MCAS; ii++) {
        if (MCA_ON[ii]) { size += MCA_MEM[ii]["size"] }
    }
    return (size)
}'

#%IU%
#%MDESC% Macro used in all read hooks to fillup MCA_DATA
def _mcalineupdata '{
    local ii size darr beg
    beg = 0
    for (ii = 0; ii < MCAS; ii++) {
        if (MCA_ON[ii]) {
            size = MCA_MEM[ii]["size"]-1
            darr = sprintf("MCA_DATA%d", ii)
            MCA_DATA[beg:beg+size][1]= @darr[0:size][1]
            beg = beg+size+1
        }
    }
}'

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

#%UU%
#%MDESC% Set lineup facility off. MCA_DATA is not updated anymore
def mcalineupoff '{
    cdef("", "", "_lpmca", "delete")
}'


def mcatype '{
    local i pars[] nb

    nb = split("$*", pars)
    if (nb == 0) {
        for (i = 0; i<MCAS; i++)
        _mcatype(i)
    } else if ((nb %2) == 0) {
        for (i = 0; i < nb; i += 2)
        _mcatype(pars[i], pars[i+1], 1)
    } else {
        if ((pars[0] >= MCAS) || (pars[0] < 0))
        eprintf ("MCA #%d not configured\n", pars[0])
        else
        _mcatype(pars[0])
    }
}'

def _mcatype(no, type, flag) '{
    local str

    if (flag)
    MCA_PAR[no]["type"] = type
    else
    type = MCA_PAR[no]["type"]

    printf("MCA #%d controller type: ", no)
    type == 0 ? (str = "AIM/MAX") : type == 1 ? (str = "MMAX"): \
        type == 2 ? (str = "MUSST") : (str = "????")
    tty_cntl("md")
    printf("<%s>\n", str)
    tty_cntl("me")

}'
# ----------------------------------------
# user hook macros
# ----------------------------------------
if (!(whatis("mca_user_waitcounts")&2)) {
    rdef mca_user_waitcounts \'\'
}
if (!(whatis("mca_user_key")&2)) {
    rdef mca_user_key \'\'
}
if (!(whatis("mca_user_read")&2)) {
    rdef mca_user_read \'\'
}

cdef("mca_user_roi_add", "", "multimca")
cdef("mca_user_roi_delete", "", "multimca")

cdef("end_mac", "mcaguiclose;", "mca")


#%MACROS%
#%IMACROS%
#%DEPENDENCIES% %B%saveload.mac%B% %B%sps.mac%B%
#%AUTHOR%
# MC.Lagier, E.Papillon, A.Beteva %BR%
# $Revision: 1.45 $ / $Date: 2022/12/05 16:00:36 $
#%TOC%