esrf

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

#%TITLE% MCA.MAC 
#%NAME%
#  Multi Channel Analyser.
#
#%CATEGORY% Detection, MCA
#
#%DESCRIPTION%
#  These macros provide users with basic MCA commands, i.e. start, stop, init, read memory, etc..., as well as with more sophisticated features such as ROIs, channel calibration, peak search, data saving and recovering, etc...%BR%
#  MCA control is inserted in SPEC internal code, making it possible to automatically operate the MCA, from standard SPEC counting and scanning commands, e.g. acquire, plot out, save spectrum for each point of a scan. A Graphical User Interface is also available. 
#%ATTENTION%
#About the usage of the Graphical User Interface (GUI) :
# it is at the moment only capable of monitoring the data acquired, as there is no connection between SPEC and that GUI, appart from the spectrum data itself and its calibration parameters, both stored in shared memory. For instance, the ROIs defined from SPEC or from the GUI are not connected together. 
#They are two seperate sets of ROI definitions. The GUI is not capable of sending control commands to the hardware. Be more particularly aware that the acquisition times are not known by the GUI, so if you save the spectrum from the GUI, they wont be included in the file. rather use SPEC for saving your data. The GUI is a display.
#%SETUP%
#%BR%Hardware supported :
#%DL%
#%DT% SILENA Memory Buffer.
#%DD% remote controlled through GPIB. SPEC can address it in 3 different ways:
#%DL%
#%DT% Direct from SPEC.
#%DD% In SPEC config, select MCA TYPE Silena 73XX MCA (GPIB), TCP MODE.
#%BR%The GPIB interface can be any of those supported by SPEC.
#%DT% Device server McaSICL.
#%DD% In SPEC config, select MCA TYPE ESRF MCA, TCP MODE. 
#%BR%The GPIB is addressed by the device server, so you do not necessarily need to declare it in SPEC, but only HP E2050 LAN/HPIB controller is supported; McaSICL server runs on HP-UX machines only.
#%DT% Device server McaMB.
#%DD% In SPEC config, select MCA TYPE ESRF MCA, TCP MODE. 
#%BR%The GPIB is addressed by the device server, so you do not necessarily need to declare it in SPEC, but only Themis T409 VME Board is supported; McaMB server runs on OS9 crates.
#%XDL%
#%DT% CANBERRA A.I.M. 
#%DD% It is remote controlled via Ethernet LAN. SPEC addresses it through a device server, called %B%McaAIM%B% that runs on HP-UX machines. In SPEC config, select MCA TYPE ESRF MCA, TCP MODE.
#%XDL%
#MCA macros are able to detect that a MCA has been configured. If it happens that it is taken out, the macros disable themselves automatically, as well as they enable back in case of a MCA is configured again. 
#%BR%%BR%Some Particular settings:
#%DL%%DT%MCAON / MCAOFF
#%DD%Both COUNTERS and MCA are operated simultaneously from %B%ct%B% and %B%scans%B% commands if %B%mcaon%B% is set. %B%mcaoff%B% disables the MCA to be addressed from those commands. 
#%BR%%BR%On the other hand, %B%mcaacq%B% always run the MCA, but never run the counters, whatever mcaon or mcaoff is set. 
#%B%mcasetup%B% AUTO-RUN option (toggling enabled /disabled) does the same as mcaon / mcaoff.%BR%
#%PRE%
#------------------------------------------------------------
# command		%B%mcaon%B%		%B%mcaoff%B%
#------------------------------------------------------------
#%B%mcaacq%B%		MCA			MCA
#%B%ct%B%/%B%scans%B%	MCA + COUNTERS		COUNTERS
#============================================================
#
#%PRE%
#%BR%%BR%
#%DT%REAL TIME / LIVE TIME / EXTERNAL SYNCHRO
#%DD%The %B%real%B% time is the clock time. The %B%live%B% time is the real time substracted the electronics %B%dead%B% time. 
#%PRE%
#	%B%real = live + dead%B%
#%PRE%
#In%B%internal synchro%B%mode, MCA acquisitions terminate when the amount of time elapsed, either %B%real%B% or %B%live%B% in respect of %B%mcasetup%B% time mode settings, matches the time the MCA internal timer was %B%preset%B% with.
#%BR%%BR%In %B%external%B% %B%synchro%B% mode, MCA acquisitions from %B%ct%B% and %B%scans%B%, are externally (hardware) gated by the SPEC timer (vct6 or whatever timer has a gate output). The real or live time modes are not relevant in those cases . Nevertheless, the external synchro mode never affects %B%mcaacq%B%, which still presets MCA timer, in %B%real%B% or %B%live%B% time mode regarding %B%mcasetup%B% settings.
#%BR%%BR%In any case, SPEC always waits for an acquisition to terminate before 	going to the next step.
#%PRE%
#------------------------------------------------------------------------------
#	MCA setup		MCA elapsed times		SPEC timer 
#
#  Synchro	Time mode	real		live
#------------------------------------------------------------------------------
#  internal	%B%real%B%	preset		preset-dead	preset
#  internal	%B%live%B%	preset+dead	preset 		preset
#%B%external%B%	not relevant	~preset		~preset-dead	preset
#==============================================================================
#%PRE%
#%XDL%


#%OVERVIEW%
#%DL% 
#%DT% mcasetup %DD% Hardware and software initialisation and setup.
#%DT% mcainit %DD% The same but without any input; default/current values are set.
#%DT% mcastat %DD% Display MCA configuration and status.
#%DT% mcastart %DD% Start an acquisition. 
#%DT% mcastop %DD% Stop an acquisition.
#%DT% mcaread %DD% Read the MCA memory.
#%DT% mcatimes %DD% Report the MCA elapsed times.
#%DT% mcaclear %DD% Clear the MCA memory.  
#%DT% mcaacq %DD% MCA acquisition. 
#%DT% mcaoff %DD% Disable MCA control from scans and ct.
#%DT% mcaon %DD% Enable back MCA control from scans and ct.
#%DT% mcasave %DD% Save spectrum to disk file. 
#%DT% mcaload %DD% Load back spectrum from disk file.
#%DT% mcaroi %DD% define ROIs.
#%DT% mcacal, mcacalm %DD% Computer aided and manual calibration of the MCA.
#%BR% Better use the GUI if it is installed.
#%DT% mcapar %DD% Show calibration fit parameters or input new parameters.
#%DT% mcaE %DD% Toggle between channel (uncalib) and calibrated mode.
#%DT% mcaguioff %DD% Switch the GUI off.
#%DT% mcaguion %DD% Switch the GUI on. 
#%DT% mcasplot %DD% Plot the current MCA data when GUI is off. 
#%DT% mcacplot %DD% A screen plot of the current MCA data in cplot format.
#%DT% mcapplot %DD% A printer plot of the current MCA data in cplot format.
#%XDL%
#%EXAMPLE%
#%DL%
#%DT% mcaroi roi1 %DD%
#%PRE%
#ROI       |   Channels    | Energy                      | ROI  | Roi 
#names     | first | last  | min          | max          |ACTIVE| numbers
#---------------------------------------------------------------------
#roi       | 0     | 8191  | 0.0000       | 0.0000       |  -   | 0
#roi1      | 0     | 511   | 0.0000       | 0.0000       |  X   | 1
#%PRE%
# Sets ROI number 1 as the one active.%BR%%BR%
# Counters %B%roi1%B% and %B%roi%B% are declared in %B%config%B%.
#%BR%
#%DT% ct %DD%
#%PRE%
#Fri Dec  1 10:41:57 1995
#
#     Seconds = 1
#         MCA = 5340 (5340/s)
#       MCA 1 = 292 (292/s)
#%PRE%
# The MCA acquires data on the wider range over the counter-assigned-ROIs plus the active ROI. The eventually saved spectrum is limited to the active ROI, while each counter-assigned-ROIs reports integrated counts value over the particular ROI they are assigned to. 
#%BR%
#%DT% ascan m0 0 10 5 1 %DD%
#%PRE%
#Total 11 points, 11 seconds
#
#Scan  37   Fri Dec  1 10:56:08 1995   file = ./data/test  mcl  user = lagier
#ascan  m0 0 10  10 1
#
#   Motor 0 MCA 1  MCA    Seconds 
#  0    0.0000       292      5340     	    1
#  1    2.0000       328      5363          1 
#  2    4.0000       299      5400          1 
#  3    6.0000       299      5333          1 
#  4    8.0000       328      5398          1 
#  5   10.0000       328      5400          1 
#%PRE%
# A spectrum is accumulated at each scan step.
#%XDL%
#%END%

#====================================================================== GLOBALS

global MCA_DEVNAME MCA_AROFF MCA_DEVOK 
global MCA_SAVED MCA_old_channel 
global MCA_ADCNO MCA_MEMGRPSIZE MCA_MEMGRP MCA_TMODE 
global MCA_DISP_SEC MCA_CP_XLBL MCA_CP_XUNT MCA_GRP MCA_GUI
global MCA_LINES MCA_DOTS MCA_EBARS MCA_LOG MCA_PLOTATTR MCA_PLOTERASE
global MCA_REDUCTION MCA_SAVEBUFFER MCA_FLAG 
global MCA_SYNCHRO MCA_BACKSUB 
global MCA_ROI_GCH_MIN MCA_ROI_GCH_MAX
global MCA_ROI_CH_MIN MCA_ROI_CH_MAX MCA_ROI_EN_MIN MCA_ROI_EN_MAX 
global MCA_ROI_COUNTER 
global PS_WA PS_WB PS_WC MCA_ENERGY PS_EA PS_EB PS_EC PS_NOPEAKS
global MCA_ROI_ACH_MIN MCA_ROI_ACH_MAX

#======================================================================== SETUP
#%IU%
#%MDESC% Setup file service.
def mcaunsetup '{
  mcaoff
  cdef("","","_mca0","delete")
}'

#%UU% [adc] [tmode] [gsz] [g] [cal] [Xlbl] [Xun] [nclr] [sleep] [bgnd] [gui] [log] [dots] [lines] [ebars] [flag] [red] [synchr]
#%MDESC% Sets the MCA hardware and software up. 
# You can either give all the parameters on the command line or use the menu that shows up when typing "mcasetup" alone. 
#%UL% Input arguments description. [variable name, default value]
#%LI% %B%adc%B%: active adc number (1 or 2). [MCA_ADCNO, 1]       
#%LI% %B%tmode%B%: 1 if live time, 2 if real time. [MCA_TMODE, 2]
#%LI% %B%gsz%B%: MCA memory group size in channels. [MCA_MEMGRPSIZE, 8192]
#%LI% %B%g%B%: MCA selected memory group. [MCA_MEMGRP[1] , 0]          
#%LI% %B%cal%B%: 1 if spectrum is calibrated, 0 otherwise. [MCA_ENERGY, 0]
#%LI% %B%Xlbl%B%: X plot label for calibrated spectrum. [MCA_CP_XLBL, "Energy"]
#%LI% %B%Xun%B%: X unit for calibrated spectrum.        [MCA_CP_XUNT, "KeV"]  
#%LI% %B%nclr%B%: 0 for memory clearing prior to acquisition, 1 otherwise. [MCA_SAVEBUFFER, 0]
#%LI% %B%sleep%B%: number of  sec. sleeping between run plot updates. [MCA_DISP_SEC, 0]
#%LI% %B%bgnd%B%: 1 if you want background substraction in ROIs counts. [MCA_BACKSUB, 0]
#%LI% %B%gui%B%: 1 for gui plot.                   [MCA_GUI, 0]
#%LI% %B%log%B%: 1 for log plot.                   [MCA_LOG, 0]
#%LI% %B%dots%B%: 1 for large dots in plot.        [MCA_DOTS, 0]
#%LI% %B%lines%B%: 1 for lines plotting.           [MCA_LINES, 0]
#%LI% %B%ebars%B%: 1 for error bars plotting.      [MCA_EBARS, 0]
#%LI% %B%flag%B%: data saving flag		   [MCA_FLAG, 0]
#%UL%
#%LI% 0x01 save spectrum during scans to a file.
#%LI% 0x02 save spectrum after each other acquisition to a file.
#%LI% 0x04 save to specific MCA file, otherwise use scans file [DATAFILE]. 
#%XUL%
#%LI% %B%red%B%: data reduction coefficient, to be applied at saving.[MCA_REDUCTION, 1] 
#%LI% %B%synchr%B%: MCA acquisition is hard-synchronized with SPEC configured timer. [MCA_SYNCHRO, 0]
#%XUL%
#%BR%
#%B% NB : %B%
#%BR%
# It is possible to have the last acquisition elapsed times values reported in counters by simply configuring the counters you need out of %B%mcaLt%B%, %B%mcaRt%B% and %B%mcaDt%B% mnemonics, respectively standing for Live, Real and Dead times.
#%BR%
#%BR%

def mcasetup '{

  setup_tail ("mca")
  cdef("config_mac","mca_config; ","_mca0",0)

  mca_defaults
  mca_device
  mca_state () 

  if ($#) {
    local st1 st2
    st1="$6";st2="$7"
    mca_setup($1,$2,$3,$4,$5,st1,st2,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18)

  } else {
    MCA_MENULVL=0
    menu("\n  M U L T I   C H A N N E L   A N A L Y S E R   S E T U P",\
            "mca_setupmenu","mca_setupchk","mca_dosetup ()")
  } 
}'

#%IU% [mask]
#%MDESC% Sets default values to some global variables.
def mca_defaults '{
  local mask hardware_defaults software_defaults

  mask = $#?$1:3
  hardware_defaults = mask&1
  software_defaults = mask&2

  if (hardware_defaults) {
    if (MCA_ADCNO <= 0) MCA_ADCNO = 1
    if (MCA_MEMGRPSIZE <= 0) {
      MCA_MEMGRPSIZE = mca_max_channels (8192)
      MCA_MEMGRP[1]=0
    }
  } 

  if (software_defaults) {
    MCA_REDUCTION = MCA_REDUCTION>0?MCA_REDUCTION:1
    PS_EB = PS_EB?PS_EB:1
  }
}'

#%IU% (size) 
#%MDESC% Returns installed device full memory size. 
# If the device is disconneted, the size specified as input is returned, so that simulation mode or loaded data analysis are possible.

def mca_max_channels (wish) '{
  local ret
  ret = mca_io("max_channels")
  if (ret>0) return(ret)
  else if (wish>0) return(wish)
}'

#%IU%
#%MDESC% Checks wether a MCA is configured and reads in its device server name or its device type. If it appears that no device is configured, it makes that the mca macros detach themselves from the SPEC standard ones.

def mca_device '{
  local _fil _lin _fid _old
 
  _old=MCA_DEVNAME ; MCA_DEVNAME=""
  _fil=sprintf("%s/%s/config",SPECD,SPEC)
  getline(_fil,"open")
  while ((_lin=getline(_fil))!=-1) {
    split(_lin,_fid)
    if (index(_fid[0],"VM_MCA")) {
      MCA_DEVNAME=_fid[2]
      break
    } else if (index(_lin,"@mca")) {
      MCA_DEVNAME=_fid[0]
      break
    }
  }
  getline(_fil,"close")

  if (MCA_DEVNAME == "") mca_deldef()
}'

#%IU% ()
#%MDESC% Checks MCA State. (acquiring, idle, disconnected or not configured)
def mca_state () '{

  if (MCA_DEVNAME != "") \
    MCA_DEVOK = mca_par("max_channels")>0?(wait(0x24)?DEVRUN:DEVON):0
  else  MCA_DEVOK = -1
}'

#%IU% (adc,tm,sz,g,cal,lbl,un,nclr,slp,bgd,lg,dt,ln,eb,flag,red,syn) 
#%MDESC% Reads in setup parameters and do the setup. see "mcasetup" for details

def mca_setup (adc,tm,sz,g,cal,lbl,un,nclr,slp,bgd,gui,lg,dt,ln,eb,flag,red,syn) '{

  MCA_ADCNO 	= adc
  MCA_MEMGRPSIZE= sz
  MCA_TMODE 	= tm
  MCA_MEMGRP[1] = g
  MCA_ENERGY	= cal
  MCA_CP_XLBL   = lbl  
  MCA_CP_XUNT   = un
  MCA_SAVEBUFFER= nclr
  MCA_DISP_SEC  = slp
  MCA_BACKSUB   = bgd
  MCA_GUI       = gui
  MCA_LOG=lg;  MCA_DOTS=dt;  MCA_LINES=ln;  MCA_EBARS=eb ; 
  MCA_REDUCTION = red  
  MCA_SYNCHRO   = syn

  if ((flag&3) && !(MCA_SL)) {
    MCA_FLAG&=~3
    printf("MCA: Macros set \"saveload.mac\" not loaded.                              \n     Cannot save any data. \n")
  } else {
    MCA_FLAG=flag
  }

  if (cal && !(MCA_PS)) {
      MCA_ENERGY= 0
      printf("MCA: Energy mode not available.                                              \n     Macro set \"psearch.mac\" not loaded.\n")
  } else MCA_ENERGY = cal

  mca_dosetup ()
}'

#%IU% ()
#%MDESC% Does the actual setup, i.e. hardware setup, general operation setup and subsequent software setup.
def mca_dosetup () '{
  
#HDW
  mca_hdwsetup ()

#SOFT
  mca_defaults 2
  mca_cdef ()
  if (!whatis("MCA_DATA_PARAM")) mca_firstinit ()
  mca_softsetup()

#GUI
  if (MCA_GUI) { 
    mcaguion 
  } else { 
    mcaguioff 
  }

  print "MCA:",MCA_DEVNAME,MCA_DEVSTATE[MCA_DEVOK]
}'

#%IU%
#%MDESC% hardware setup, i.e. Adc selection, Memory initialisation, and operation setup, i.e. time mode and soft preset. 
def mca_hdwsetup () '{

  local maxi

  mca_wait()  
  MCA_ADCNO = mca_io("adc",MCA_ADCNO) 

  if ((MCA_MEMGRPSIZE != mca_io("group_size")) ||\
      (MCA_MEMGRP[1]  != mca_io("select_group"))) {

    maxi = mca_max_channels (MCA_MEMGRPSIZE)
    if (MCA_MEMGRPSIZE > maxi) \
      MCA_MEMGRPSIZE = mca_io("group_size",maxi)
    else MCA_MEMGRPSIZE = mca_io("group_size", MCA_MEMGRPSIZE)

    if (MCA_MEMGRPSIZE > 0) {
      MCA_MEMGRP[0]  = maxi/MCA_MEMGRPSIZE
      if ((MCA_MEMGRP[1]<0) || (MCA_MEMGRP[1]>=MCA_MEMGRP[0])) {
        MCA_MEMGRP[1] = 0
      }

      MCA_MEMGRP[1] = mca_io("select_group", MCA_MEMGRP[1])
    }
  }

  if (MCA_TMODE == 1) mca_io("live")
  else mca_io("real")
  if (MCA_SYNCHRO) mca_io("soft_preset",0)
  else mca_io("soft_preset",1)
}'

#%IU% () 
#%MDESC% loops printing a message till the acquisition is finished.
def mca_wait () '{

if (wait(0x24)) {
  while (wait(0x24)) {
    tty_move (0,-3,"waiting for MCA to stop ...")
    tty_move (0,-2,sprintf("MCA  Preset time:   %g sec.\n",COUNT_TIME))
    mcatimes
  }
  print;print
}
}'


#%IU%
#%MDESC% Does things that must or need only to be done once at startup. 
#%BR% Loads roi from file, Reset|Declare shared memory ...
def mca_firstinit () '{
    printf("MCA: Initialization ...\n")
    mcaloadroi
    MCA_old_channel[0] = MCA_old_channel[1] = -1
    shared double array MCA_DATA_PARAM [3]
    MCA_DATA_PARAM[1]=1
}'


#%IU%
#%MDESC% software setup, i.e. inits memory and assign newly set up parameters to the relevant globals.  
def mca_softsetup () '{
  local _type _oldsize _toks

  if (MCA_MEMGRPSIZE>0) {
    
    _type = whatis("MCA_DATA","string_output")
    _oldsize = _toks[split(substr(_type,0,index(_type,"-row")-1),_toks)-1]
    
    if (_oldsize != MCA_MEMGRPSIZE) {
      shared ulong array MCA_DATA [MCA_MEMGRPSIZE][2]

#      if ((MCA_GRP = groupinit (MCA_GRP, MCA_MEMGRPSIZE, 2)) < 0) { 
#        printf("MCA error: no data group memory left \n") 
#      }
    }

    MCA_REDUCTION = MCA_REDUCTION>0?MCA_REDUCTION:1
    ulong array MCA_DATARED[int(MCA_MEMGRPSIZE/MCA_REDUCTION)][2]

    array_op("fill",MCA_DATA[][0],1)
    array_op("fill",MCA_DATARED[][0], MCA_REDUCTION)
    MCA_DATARED[][0] += int(MCA_REDUCTION/2)

  }

  MCA_ROI_CH_MIN[0]=0; MCA_ROI_CH_MAX[0]=MCA_MEMGRPSIZE-1
  MCA_ROI_EN_MIN[0] = mca_calcE (MCA_ROI_CH_MIN[0])
  MCA_ROI_EN_MAX[0] = mca_calcE (MCA_ROI_CH_MAX[0])

  MCA_PLOTERASE = 1
  MCA_PLOTATTR=sprintf("%sylog %slines %sdots %sebars",                              MCA_LOG?"+":"-",MCA_LINES?"+":"-",MCA_DOTS?"+":"-",MCA_EBARS?"+":"-")
}'


#%UU%
#%MDESC% Disables the MCA.
#%BR% The MCA is no longer addressed during standard SPEC operation ("ct", scans ..), but still from "mcaacq".
def mcaoff '{
  mca_deldef () 
  mca_par ("auto_run",0) 
  MCA_AROFF = 1

# mca_io is wrong here as it returns 0 if no dev is connected.
}' 

#%UU%
#%MDESC% Enables back the MCA. 
def mcaon '{
  mca_par("auto_run",1)
  MCA_AROFF = 0
  mca_cdef()
}' 

#%IU%
#%MDESC% Un-hooks MCA operation from the standard macros.
def mca_deldef () '{
    cdef("","","_mca1","delete")
    cdef ("","","mcaLt","delete")
    cdef ("","","mcaRt","delete")
    cdef ("","","mcaDt","delete")
    mca_roideldef()
}'

#%IU% ()  
#%MDESC% Un-hooks ROI operation from the standard macros.
def mca_roideldef () '{

   local roi 

   for (roi=0;roi<=MCA_ROI_NO;roi++) {
     cdef ("","",MCA_ROI_COUNTER[roi],"delete")
   }
   MCA_ROI_GCH_MIN = MCA_ROI_ACH_MIN
   MCA_ROI_GCH_MAX = MCA_ROI_ACH_MAX
}'

#%IU%
#%MDESC% Hooks MCA operation to the standard macros.
def mca_cdef () '{

local _hook

if ((MCA_DEVNAME != "") && !MCA_AROFF) {

  cdef("user_countersrun","if(wait(0x24)) return(1);;","_mca1")

  cdef("user_getcounts", "mca_readbuffer;",     "_mca1",0x10)
  cdef("user_getcounts", "S[mcaLt]=MCA_LIVE_T;","mcaLt",2)
  cdef("user_getcounts", "S[mcaRt]=MCA_REAL_T;","mcaRt",2)
  cdef("user_getcounts", "S[mcaDt]=MCA_DEAD_T;","mcaDt",2)

  if (!MCA_SAVEBUFFER) \
    cdef("user_prepcount","mcaclear;","_mca1",0)
  else \
    cdef("user_prepcount","","_mca1","delete")

  if (MCA_FLAG&1) {
    cdef("measure2","mca_savescanhead (MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX);",                                                                           "_mca1")
    cdef("user_scan_loop","mca_savescandata(MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX);"                                                                      ,"_mca1")
  } else {
    cdef("Fheader","mca_saveroihead;","_mca1")
#    cdef("measure2","if (!NPTS) mca_saveroihead;","_mca1")
#    cdef("measure2","","_mca1","delete")
    cdef("user_scan_loop","","_mca1","delete")
  }

  if (MCA_FLAG&2) {
    cdef("user_handlecounts","mca_savectdata(MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX);                                                                     ","_mca1")
  } else {
    cdef("user_handlecounts","","_mca1","delete")
  }
  mca_roicdef() 
}
}'

#%IU%
#%MDESC% Saves to DATAFILE MCA ROIS description. 
def mca_saveroihead '{
  for (j=0; j<=MCA_ROI_NO ;j++) {
    if ((MCA_ROI_COUNTER[j]!="") && (-1!=cnt_num(MCA_ROI_COUNTER[j]))) {
      savemcaroi(DATAFILE,MCA_ROI_CH_MIN[j],MCA_ROI_CH_MAX[j],cnt_name(cnt_num(MCA_ROI_COUNTER[j])))
    }
  }
}'

#%IU% ()  
#%MDESC% Hooks ROI operation to the standard macros.
def mca_roicdef () '{

local roi cmd mne

MCA_ROI_GCH_MIN = MCA_ROI_CH_MAX[0]
MCA_ROI_GCH_MAX = 0

for (roi=0;roi<=MCA_ROI_NO;roi++) {
  if ((mne = MCA_ROI_COUNTER[roi])!="") {
    if (-1 != cnt_num(mne)) {

      if (MCA_ROI_GCH_MIN > MCA_ROI_CH_MIN[roi]) \
        MCA_ROI_GCH_MIN=MCA_ROI_CH_MIN[roi]
      if (MCA_ROI_GCH_MAX < MCA_ROI_CH_MAX[roi]) \
        MCA_ROI_GCH_MAX=MCA_ROI_CH_MAX[roi]

      cmd = sprintf("mca_getcounts %s %d %d;",mne,MCA_ROI_CH_MIN[roi],\
                                                MCA_ROI_CH_MAX[roi])
      cdef("user_getcounts",cmd,mne,2)
    }
  }
}

if (MCA_ROI_GCH_MIN > MCA_ROI_CH_MIN[MCA_ROIACTIVE]) \
  MCA_ROI_GCH_MIN = MCA_ROI_CH_MIN[MCA_ROIACTIVE]
if (MCA_ROI_GCH_MAX < MCA_ROI_CH_MAX[MCA_ROIACTIVE]) \
   MCA_ROI_GCH_MAX = MCA_ROI_CH_MAX[MCA_ROIACTIVE]

MCA_ROI_ACH_MIN = MCA_ROI_CH_MIN[MCA_ROIACTIVE]
MCA_ROI_ACH_MAX = MCA_ROI_CH_MAX[MCA_ROIACTIVE]

mca_resize_to_roi 0 MCA_ROI_ACH_MIN  MCA_ROI_ACH_MAX 
mca_resize_to_roi 0 MCA_ROI_GCH_MIN  MCA_ROI_GCH_MAX 
}'


#%UU%
#%MDESC% Initialises the MCA macros and hardware.
#Can be called at startup to re-setup things without giving any parameter, nor calling any menu. The current or default parameters are then set. Default are mensionned together with %B%mcasetup%B% description.

def mcainit '{

  setup_tail("mca")
  cdef("config_mac","mca_config; ","_mca0",0)

  mca_defaults
  mca_device
  mca_state ()

  if ((flag&3) && !(MCA_SL)) {
    MCA_FLAG&=~3
    printf("MCA: Macros set \"saveload.mac\" not loaded.                              \n     Cannot save any data. \n")
  } else {
    MCA_FLAG=flag
  }

  mca_hdwsetup()
  mca_cdef ()
  mca_firstinit() 
  mca_softsetup()

  if (MCA_ENERGY && !(MCA_PS)) {
      MCA_ENERGY = 0
      printf("MCA: Energy mode not available.                                              \n     Macro set \"psearch.mac\" not loaded.\n")
  } 

  if (MCA_GUI) { 
    mcaguion 
  } else { 
    mcaguioff 
  }

  print "MCA:",MCA_DEVNAME,MCA_DEVSTATE[MCA_DEVOK]

}'

#%IU%
#%MDESC% "config" / "reconfig" service.
#Hooked to "config_mac".
def mca_config '{

  if (MCA_AROFF) { mcaoff }  

  mca_defaults
  mca_device
  mca_state ()
  mca_hdwsetup ()
  mca_cdef ()

  if (!whatis("MCA_DATA_PARAM")) mca_firstinit()
  mca_softsetup()
  print "MCA:",MCA_DEVNAME,MCA_DEVSTATE[MCA_DEVOK]
}'

#=================================================================== SETUP MENU


#%IU%
#%MDESC% MCA menu.
def mca_setupmenu '{

  global MCA_MENULVL

  if (MCA_MENULVL) {
    mca_cpmenu
  } else {
    mca_menu
  }
}'


#%IU%
#%MDESC% Display MCA General menu. (page 1)
def mca_menu '{

  menuprint(0,MCA_DEVSTATE[MCA_DEVOK],"DEVICE",MCA_DEVNAME);print;print

  menuoptval(-35,"|\n","ADC",MCA_ADCNO,"A") 
  menuvargetv("MCA_ADCNO") 
  menuaction("if (MCA_ADCNO <= 0) MCA_ADCNO = 1")

  menuoptval(-35,"| ","GROUP size",MCA_MEMGRPSIZE,"G")
  menuaction("mca_calgrp")
  menuprint(-36,"\n","active",MCA_MEMGRP[1]+1)

  menuoptval(-35,"| ","TIME mode",MCA_TMODE==1?"Live":"Real","T")
  menuvartogg("MCA_TMODE",2,1)

  menuoptval(-36,"\n","SYNCHRO",MCA_SYNCHRO?"External":"Internal","S")
  menuvartogg("MCA_SYNCHRO")

  print
  menuoptval(-35,"| ","AUTO-RUN in ct/scan",MCA_AROFF?"disabled":"enabled","R")
  menuaction("if (MCA_AROFF) { mcaon } else { mcaoff }")
  
  menuoptval(-36,"\n","BACKGROUND substraction",MCA_BACKSUB?"ON":"OFF","B")
  menuvartogg("MCA_BACKSUB")

  menuoptval(-35,"| ","AUTO-MEMORY-CLEAR",MCA_SAVEBUFFER?"OFF":"ON","M")
  menuvartogg("MCA_SAVEBUFFER")

  menuoptval(-36,"\n","PLOT update interval in sec.",MCA_DISP_SEC,"P")
  menuvargetv("MCA_DISP_SEC")

  print 
  menuoptval(-35,"| ","SAVE spectrum during scans",MCA_FLAG&1?"YES":"NO","sc")
  menuvarbitw("MCA_FLAG",1)

  menuoptval(-36,"\n","after ct or mcaacq",MCA_FLAG&2?"YES":"NO","ct")
  menuvarbitw("MCA_FLAG",2)

  menuoptval(-35,"| ","     binning factor",MCA_REDUCTION,"bi")
  menuvargetv("MCA_REDUCTION")
  menuaction ("MCA_REDUCTION=MCA_REDUCTION>0?MCA_REDUCTION:1")
  
  menuoptval(-36,"\n","data format",MCA_FMT,"da")
  menuvargetv("MCA_FMT")

  if (MCA_FLAG&4) {
    menuoptval(0,0,"SAVE to",mca_filename(MCA_PREFIX1,MCA_N,MCA_SUFFIX),"to")
    menuprint (0,"(mca files types)\n","and",mca_filename(MCA_PREFIX2,0,MCA_SUFFIX))
  } else {
    menuoptval(0,"(standard scan file)\n","SAVE to",DATAFILE,"to")
  }
  menuvarbitw("MCA_FLAG",4)
  menuaction ("if (MCA_FLAG&4) {\
           print \"The alternative saves one spectrum per MCA private file.\";          \nprintf(\"Enter here the \");mcanewfile }")

  print
  menuoptval (0,0,"GUI",MCA_GUI?"ON":"OFF","GUI")
  menuvartogg("MCA_GUI")

  if (!MCA_GUI) {
    printf(", ")
    menuoptval(0,", ","PLOT: log",(MCA_LOG)?"YES":"NO","l")
    menuvartogg("MCA_LOG")

    menuoptval(0,", ","dots",(MCA_DOTS)?"YES":"NO","d")
    menuvartogg("MCA_DOTS")

    menuoptval(0,"\n","lines",(MCA_LINES)?"YES":"NO","n")
    menuvartogg("MCA_LINES")

#    menuoptval(0,0,"err bars",(MCA_EBARS)?"YES":"NO","e")
#    menuvartogg("MCA_EBARS")
  } 
  menusep
  menuoptbutton (70,"\n","go to cplot menu","cp")
  menuvartogg ("MCA_MENULVL")
}'

#%IU%
#%MDESC% Prepares MCA memory group setting.
def mca_calgrp '{

  local maxi 
  
  maxi = mca_max_channels (8192)

  MCA_MEMGRPSIZE = getval(sprintf("Channels per memory group (%d - %d)",                                                             512,maxi),MCA_MEMGRPSIZE)

  if (MCA_MEMGRPSIZE > maxi)  MCA_MEMGRPSIZE = maxi
  if (MCA_MEMGRPSIZE < 512)  MCA_MEMGRPSIZE = 512

  MCA_MEMGRP[0] = maxi/MCA_MEMGRPSIZE

  for (i=0.75;i<=32;i*=2) {
    if (MCA_MEMGRP[0]<i) {
      MCA_MEMGRP[0]=i-i/3
      break
    }
  }

  MCA_MEMGRPSIZE = maxi/MCA_MEMGRP[0]
  MCA_MEMGRP[1]=getval(sprintf("Memory group active (max %d):",                                            MCA_MEMGRP[0]) ,MCA_MEMGRP[1]+1)-1

  if ((MCA_MEMGRP[1]<0) || (MCA_MEMGRP[1]>=MCA_MEMGRP[0])) MCA_MEMGRP[1] = 0
}'

#%IU%
#%MDESC% Display MCA CPLOT menu. (page 2)
def mca_cpmenu '{

  global MCA_CP

#  menuoptval (-40,"\n","plot from file",MCA_CP["FROMF"]?"YES":"NO","pl")
#  menuvartogg ("MCA_CP[\"FROMF\"]")
#  menuaction ("menuwarning(\"Plot from file to be implemented soon...\")") 
#  print

  menuoptval (-50,0,"global title",MCA_CP["GLOBTITLE"],"gl")
  menuvargetv("MCA_CP[\"GLOBTITLE\"]")
  menuoptval (-30,"\n","get cpsetup:",substr(CP_PAR["GLOBTITLE"],1,15),"g")
  menuaction ("MCA_CP[\"GLOBTITLE\"]=CP_PAR[\"GLOBTITLE\"]")
  menuoptval (-50,0,"title",MCA_CP["PTITLE"],"ti")
  menuvargetv("MCA_CP[\"PTITLE\"]")
  menuoptval (-30,"\n","get cpsetup:",substr(CP_PAR["PTITLE"],1,15),"e")
  menuaction ("MCA_CP[\"PTITLE\"]=CP_PAR[\"PTITLE\"]")
  menuoptval (-50,0,"comment",MCA_CP["COMMENT"],"co")
  menuvargetv("MCA_CP[\"COMMENT\"]")
  menuoptval (-30,"\n","get cpsetup:",substr(CP_PAR["COMMENT"],1,15),"t")
  menuaction ("MCA_CP[\"COMMENT\"]=CP_PAR[\"COMMENT\"]")
  print
  menuoptval (-40,"\n","fwhm etc.. on plot",MCA_CP["FLAGS"]&0x10000?"YES":"NO","fw")
  menuvarbitw ("MCA_CP[\"FLAGS\"]",0x10000)
  if (MCA_GUI) {
    menuoptval (-40,"\n","log Y",MCA_LOG?"YES":"NO","l")
    menuvartogg ("MCA_LOG")
    menuoptval (-40,"\n","lines",MCA_LINES?"YES":"NO","n")
    menuvartogg ("MCA_LINES")
    menuoptval (-40,"\n","dots",MCA_DOTS?"YES":"NO","d")
    menuvartogg ("MCA_DOTS")
    menuoptval (-40,"\n","point size",MCA_CP["PSIZE"],"po")
#    menuprint (-40,"\n"," cpsetup:",CP_PAR["PSIZE"])
    menuvargetv ("MCA_CP[\"PSIZE\"]")
  }

 menusep
 menuoptbutton (70,"\n","back to mca menu","mca")
 menuvartogg ("MCA_MENULVL")
}'

#%IU%
#%MDESC% Checks availability of some menu options.
def mca_setupchk '{
  if (MCA_FLAG&0x3 && !(MCA_SL)) {
    MCA_FLAG&=~0x3
    menuerror("MCA: Macros set \"saveload.mac\" not loaded.                                 \n     Cannot save any data. ")
  }
}'


#========================================================================== I/O

#%IU% (command,argument,flag) 
#%MDESC% Management of input/output to the MCA. %BR%
# flag 0: returns what mca_par() returns or argument if error occured (cheat a bit)%BR%
# flag 1: returns really what mca_par() returns.
def mca_io (command,argument,flag) '{

  local ret 
  
  if (MCA_DEVOK>0) {

    if (length(argument)) {
      ret = mca_par(command,argument)
      if (ret<0) ret = mca_par(command)
    } else ret = mca_par(command)

    if (-1 == ret) {
      mca_state() 
    } 
  } else ret = -1
  
  if (!flag && (ret<0)) ret = argument

  return(ret)
}'

#=========================================================== BASIC ACQUISITION

#%UU% [preset_seconds] [roi | first] [last] 
#%MDESC% Acquires data with the MCA only. The rest of counters configured in SPEC are not addressed by this command. If you need it, use standard %B%ct%B% command. (don't forgot, %B%mcasetup%B% set %B%AUTO-RUN mode <ON>%B%, or %B%mcaon%B%).
#%BR% %B%mcaacq%B%consists in the following sequence:
#%UL%
#%LI% %B%stopping%B% any already running acquisition.
#%LI% %B%clearing%B% (if setup) the active MCA memory group.
#%LI% %B%preseting%B% the time. 
#%LI% %B%starting%B% the acquisition.
#%LI% %B%polling%B% the device till time is over.
#%UL% meanwhile:
#%LI% %B%reading%B% the MCA buffer.
#%LI% %B%plotting%B% the data spectrum.
#%XUL%
#%LI% %B%saving%B% (if setup) the acquired spectrum to disk file.
#%XUL%
#%BR% The MCA memory is read within the range specified, or if none, the active ROI .
#%BR%If the requested preset time is 0 or un-specified, the acquisition is started "for ever"; press "control-C" or "s" or "q" to stop it. 
#%BR% Pressing "c" would clear the memory on the fly. If the GUI is not active, you can also change the plot update intervals (press "u"), change the plot x or y ranges (press "x" or "y"), integrate counts on region (press "i"), toggles plot attributes such as lines (press "l"), large dots ("d") and log y("g"). Meanwhile, the acquisition goes on.

def mcaacq '{ 

  if (!(whatis("MCA_DATA")&0x10004)) {
    printf ("MCA: You MUST run ")
    tty_cntl("so");printf("mcasetup ")
    tty_cntl("se");printf("or ")
    tty_cntl("so");printf("mcainit ")
    tty_cntl("se");print "first." 
    exit
  }
}
{
   local xmin xmax ymin ymax chmin chmax roi 

   ymin = ymax = MCA_AUTO
   MCA_PLOTERASE=1
   COUNT_TIME = $1 

   if ($# == 3) {
     xmin = chmin = $2
     xmax = chmax = $3
     if (MCA_ENERGY) {   
       chmin = mca_calcch(xmin)
       chmax = mca_calcch(xmax)
     }
   } else {
     if ($#==2) roi = $2
     else       roi = MCA_ROIACTIVE
     xmin = chmin = MCA_ROI_CH_MIN [roi]
     xmax = chmax = MCA_ROI_CH_MAX [roi] 
     if (MCA_ENERGY) {
       xmin = MCA_ROI_EN_MIN [roi]
       xmax = MCA_ROI_EN_MAX [roi]
     }
   } 

   mcastop
   if (!MCA_SAVEBUFFER) {
      mcaclear 
   }
   mcastart COUNT_TIME 
   mca_waitcounts 
   mca_read chmin chmax

   mca_plotit xmin xmax ymin ymax

   mcatimes 
   print

   if (MCA_FLAG&2 && (MCA_DEVNAME != "")) {
     waitmove ; get_angles
     mca_saveacqdata(chmin, chmax, "$0 $*") 
   }
}'


#%IU%  
#%MDESC% Plots and prints out times while waiting for the acquisition to complete. This is used by "mcaacq" macro.
def mca_waitcounts '{
  local disp key 
  local min max
  
  if (COUNT_TIME>0) 
    disp=(MCA_DISP_SEC<COUNT_TIME)?MCA_DISP_SEC:COUNT_TIME
  else disp=MCA_DISP_SEC

  while (wait(0x24)) {
    mcatimes 
    mca_read chmin chmax
    mca_plotit xmin xmax ymin ymax

    mca_user_waitcounts

    key=input(0)
    if (key!="" && key != "\004") { mca_key key }
    mca_user_key

    sleep(disp) 
  }  
}'

#%IU% <key>   
#%MDESC% Manages a menu which is callable using input keys. see "mcaacq".
def mca_key '{

  local cy

  if ($1=="s" || $1=="q") {
    mcastop
    print "\nMCA  STOPPED"
  } else {
 
    clscreen()

    cy = -18
    tty_move (0,cy++,"MCA MENU")
    tty_move (5,cy++,"   s: Stop acquisition")
    tty_move (5,cy++,"   c: Clear Memory and restart acquisition")
    if (!MCA_GUI) {
      tty_move (5,cy++,"   u: Modify plot Update Intervals" )
      tty_move (5,cy++,"   x: Modify X-range" )
      tty_move (5,cy++,"   y: Modify Y-range")
      tty_move (5,cy++,"   i: Integrate counts on region")
      tty_move (5,cy++,sprintf("   l:%s Connect points with Lines\n",                                                               (MCA_LINES)?" do not":""))
      tty_move (5,cy++,sprintf("   d:%s Draw large Dots\n",                                                                        (MCA_DOTS)?" do not":"") )
      tty_move (5,cy++,sprintf("   g:%s Plot in loG scale\n",                                                                     (MCA_LOG)?" do not":" do") )
      tty_move (5,cy++,"   r: Refresh plot")
    }
    tty_move(0,-1)

    if ($1=="c") {
      if (yesno("Really clear memory",1)) {
        mcastop; mcaclear; mcastart COUNT_TIME
        t0=time()
        tty_move (0,-3, "MCA MEMORY CLEARED - ACQ RESTARTED")
        tty_move(0,-1)
      }

    } else if (!MCA_GUI) {
      if ($1=="x") {
        tty_move(0,-5,"MCA New X-range:\n")
        xmin = getval("Min",xmin)
        xmax = getval("Max",xmax)
        tty_move(0,-1)

      } else if ($1=="y") {
        tty_move(0,-5,"MCA New Y-range:\n")
        ymin=getval("Min",ymin)
        ymax=getval("Max",ymax)
        tty_move(0,-1)

      } else if ($1=="u") {
        tty_move(0,-4)
        MCA_DISP_SEC=getval("\nNew update intervals in second",MCA_DISP_SEC)
        disp=MCA_DISP_SEC
        tty_move(0,-1)

      } else if ($1=="r") {
        MCA_PLOTERASE=1
        mca_plotit chmin chmax ymin ymax
        tty_move(0,-3,"MCA PLOT REFRESHED")
        tty_move(0,-1)

      } else if ($1=="i") {
        local integral xmn xmx cmn cmx no st
        tty_move(0,-6,"Integrate counts on range :\n")
        xmn = getval(" Min",min)
        xmx = getval(" Max",min)
        if (!MCA_ENERGY) {
         cmn = xmn ; cmx = xmx
        } else {
         cmn = mca_calcch(xmn)
         cmx = mca_calcch(xmx)
        }
        st = mca_getoffset( MCA_DATA, 0, cmn)
        no = mca_getnpts  ( MCA_DATA, 0, cmn, cmx)
        if (no) {
         integral=mca_integrate(st,no+st-1)
         printf("MCA counts from %s %g to %g (%s):  [ %d ]",                                                      MCA_ENERGY?MCA_CP_XLBL:"Channel",xmn,xmx,                                      MCA_ENERGY?MCA_CP_XUNT:"",integral)
        } else  printf("Sorry, no acquisition was made in that range")
        tty_move(0,-1)

      } else if ($1=="l") {
        MCA_LINES=!MCA_LINES
        tty_move (5,-10);tty_cntl("ce")
        printf("   l:%s Connect points with Lines\n",(MCA_LINES)?" do not":"")
        tty_move(0,-1)

      } else if ($1=="d") {
        MCA_DOTS=!MCA_DOTS
        tty_move (5,-9);tty_cntl("ce")
        printf("   d:%s Draw large Dots\n",(MCA_DOTS)?" do not":"") 
        tty_move(0,-1)

      } else if ($1=="g") {
        MCA_LOG=!MCA_LOG
        tty_move (5,-8);tty_cntl("ce")
        printf("   g:%s Plot in loG scale\n",(MCA_LOG)?" do not":" do") 
        tty_move(0,-1)
      }
      MCA_PLOTATTR=sprintf("%sylog %slines %sdots %sebars",                            MCA_LOG?"+":"-",MCA_LINES?"+":"-",MCA_DOTS?"+":"-",MCA_EBARS?"+":"-")
    }
    MCA_PLOTERASE=1
  }
}'

#%UU%  
#%MDESC% Clears the active MCA memory group.  
def mcaclear '{

  mca_io("clear")
  if (whatis("MCA_DATA")&0x10000) MCA_DATA[][1] = 0
}'

#%UU% [preset_seconds]
#%MDESC% Presets and starts an acquisition.
def mcastart '{
  if (mca_preset($1)<0) {
    printf("!! MCA STATUS : %s; could not start.\n\n",MCA_DEVSTATE[MCA_DEVOK])
    exit
  }
  mca_io("run")
  mca_user_start
  printf("MCA STATUS : %s\n\n",MCA_DEVSTATE[DEVRUN])
}'

#%IU% (seconds)
#%MDESC% Sets the preset time value for the next acquisition.
def mca_preset (_preset) '{
  if (mca_io("preset",_preset,1)<0) return -1
  COUNT_TIME = fabs(_preset)
  return COUNT_TIME
}'

#%UU%  
#%MDESC% Stops acquisition if running.
def mcastop '{if (wait(0x24)) mca_io("halt")}'

#%UU%  
#%MDESC% Send "stop acquisition" signal whatever is the status of the device. It might happen that the device server gives a meaningless error message, if the status is already "IDLE".
def mcahalt 'esrf_io(MCA_DEVNAME,"DevMcaStopAcq")'

#%UU%  [roi|first] [last]
#%MDESC% Reads the MCA memory within the range specified.
def mcaread '{
  local ch0 ch1 

  if (!(whatis("MCA_DATA")&0x10004)) {
    printf ("MCA: You MUST run ")
    tty_cntl("so");printf("mcasetup ")
    tty_cntl("se");printf("or ")
    tty_cntl("so");printf("mcainit ")
    tty_cntl("se");print "first."
    exit
  }
}
{
  if ($# == 0) {
    ch0 = MCA_ROI_CH_MIN[MCA_ROIACTIVE]
    ch1 = MCA_ROI_CH_MAX[MCA_ROIACTIVE]
  } else if ($# == 1) {
    mca_getroi $1 0 ch0 ch1
  } else { 
    if (MCA_ENERGY) {   
      ch0 = mca_calcch($1)
      ch1 = mca_calcch($2)
    } else { 
      ch0 = $1
      ch1 = $2 
    }
  } 

  mca_read ch0 ch1
}'

#%IU%  [first_ch] [last_ch]
#%MDESC% Read the MCA memory within the channel range specified. Default reads the whole memory.
def mca_read '{

   global MCA_old_channel 
   local channel0 channel1

   channel0=$1 ; channel1=$2
   mca_resize_to_roi 0 channel0 channel1

   MCA_FRED[0]=0

   if (MCA_DEVOK>0) {
     mca_get(MCA_DATA[channel0:channel1][1],channel0,channel1)
     mca_times()
     MCA_IN_GROUP = 0
#     if (MCA_DATA[MCA_ROI_CH_MAX[0]][0]!=MCA_ROI_CH_MAX[0]) {
#       array_op("fill",MCA_DATA[][0],1)
#     }
     if ((MCA_old_channel[0]!=channel0)||(MCA_old_channel[1]!=channel1)) {
       MCA_PLOTERASE=1
       MCA_old_channel[0]=channel0  ; MCA_old_channel[1]=channel1
     }
  }
}'

#%UU% 
#%MDESC% Reports the MCA elapsed live , real and dead times.
def mcatimes '
  mca_times()
  printf("\rMCA  Elapsed times: live %4.2f real %4.2f sec. dead time %3.2f %%",            MCA_LIVE_T,MCA_REAL_T,MCA_DEAD_T)
'

#%IU% ()
#%MDESC% Reads in times elapsed. (Live, Real and Dead time).
def mca_times () '{
  global MCA_LIVE_T MCA_REAL_T MCA_DEAD_T

  MCA_LIVE_T = mca_io("elapsed_live")
  MCA_REAL_T = mca_io("elapsed_real")
  MCA_DEAD_T = mca_io("dead")
}'

#%UU% 
#%MDESC% Prints out a detailed status of the SPEC MCA registers.

def mcastat '{
   mca_state()
   printf("MCA STATUS : %s\n\n",MCA_DEVSTATE[MCA_DEVOK])
   printf("Current ADC             : %d\n", mca_io("adc"))
   printf("Group size              : %d K \n", mca_io("group_size"))
   printf("Group selected          : %d \n", mca_io("select_group")+1)
   printf("Elapsed live time       : %.2f s \n", mca_io("elapsed_live"))
   printf("Elapsed real time       : %.2f s \n", mca_io("elapsed_real"))
}'

#============================================================= AUTO RUN

#%IU% 
#%MDESC% Reads in MCA spectrum and plots it. 
#That macro is hooked to "user_getcounts".

def mca_readbuffer '{
  local armin armax

  mca_read MCA_ROI_GCH_MIN MCA_ROI_GCH_MAX

  if (!chk_count) MCA_PLOTERASE = 1

  if (MCA_ENERGY) {
    armin = MCA_ROI_EN_MIN[MCA_ROIACTIVE]
    armax = MCA_ROI_EN_MAX[MCA_ROIACTIVE]
  } else {
    armin = MCA_ROI_CH_MIN[MCA_ROIACTIVE]
    armax = MCA_ROI_CH_MAX[MCA_ROIACTIVE]
  }

  mca_plotit armin armax MCA_AUTO MCA_AUTO
}'

#%IU%  <ROI_counter_mnemonic> <channel_min> <channel_max>
#%MDESC% Integrates counts on ROIs and updates SPEC counters register.
# This is hooked to "user_getcounts", one hook per counter-assigned ROI.

def mca_getcounts ' S[$1] = mca_integrate ($2, $3) '

#%IU%  (channel_min,channel_max) 
#%MDESC% Integrates counts on channels region.
#This is called by "mca_getcounts". Does a backgroung substraction if that option is turned on in "mcasetup".

def mca_integrate (channel_min,channel_max) '{

  local integral nopt

  mca_resize_to_last_read channel_min channel_max
  integral = array_op("sum",MCA_DATA[channel_min:channel_max][1])

  if (MCA_BACKSUB) { 
    nopt = channel_max-channel_min+1
    integral-=(MCA_DATA[channel_min][1]+MCA_DATA[channel_max][1])/2*nopt
  }
  return(integral)
}'

#======================================================================= R.O.I.
#%UU% [no|name] [<first> <last>] [name]
#%MDESC% ROIs definition.
#%DL% detail of usage: 
#%DT% mcaroi no first last counter 
#%DD% modifies ROI number "no".
#%DT% mcaroi no                    
#%DD% sets ROI "no" as the active one.
#%DT% mcaroi no counter            
#%DD% associates name "counter", which is eventually a counter mnemonic in config, with ROI number "no".
#%DT% mcaroi
#%DD% calls the ROI menu.
#%XDL%
# Each ROI is referrenced to by a number that is set by the software. You can use the ROI names to referrence them as well.
# The active ROI is used as the default operation range when no other range is specified. ROIs which names are configured counter mnemonics are automatically set as pseudo counters to report integrated counts value over the corresponding ROI.

def mcaroi '{

  global MCA_ROI_NO MCA_ROIACTIVE 

  local errmsg no

  errmsg=""

  if (!whatis("MCA_DATA_PARAM")) mca_firstinit ()
  mca_roideldef()

  if ($#) {

    no = mca_roinum("$1")

    if ((no>=0) && (no <= MCA_ROI_NO)) {

      if (1==$#) {
        MCA_ROIACTIVE = no 
      
      } else if (2==$#) {
        errmsg = mca_roisetname(no,"$2")

      } else if (no>0) {
        if (3==$#) {
          errmsg = mca_roisetrange(no,$2,$3)

        } else if (4==$#) {
          errmsg = mca_roisetrange(no,$2,$3)
          errmsg = errmsg "\n" mca_roisetname(no,"$4")
        }
      } else {
        errmsg = "cannot modify Roi 0 range\n" 
      }
    } else {
      errmsg = "Roi $1 unknown\n"
    }

    mca_roidisp()

    if (errmsg!="") { 
      beep 
      print "MCA:",errmsg 
    }

    if ((MCA_DEVNAME != "") && !MCA_AROFF) {
      mca_roicdef()
    } 

    mcasaveroi

  } else {

    local menuend menuupd
    menuupd = ""
    menuend = "if ((MCA_DEVNAME != \"\") && (!MCA_AROFF)) { mca_roicdef() }"
    menuend = menuend ";mcasaveroi"  

    menu("\n R O I - MCA Region Of Interests .","mca_roimenu",menuupd,menuend)
  }
}'


#%IU%
#%MDESC% re-loads ROI definition from disk.
def mcaloadroi '{

global MCA_ROI_NO 

if (!unix(sprintf("test -r %s",MCA_ROI_DEFAULT_FILE))) {

   local line tok 
   for (i=0, line=getline (MCA_ROI_DEFAULT_FILE); line != -1; line = getline (MCA_ROI_DEFAULT_FILE)) {
     split (line,tok)
     if (tok[0] == "") continue
     else if (tok[0] == "#N") MCA_ROI_NO = tok[1]
     else if ((substr(tok[0],1,1) != "#") && (i <= MCA_ROI_NO)) {
       if (i>0) {
         MCA_ROI_CH_MIN[i] = tok[1]
         MCA_ROI_CH_MAX[i] = tok[2]
         MCA_ROI_EN_MIN[i] = mca_calcE (MCA_ROI_CH_MIN[i])
         MCA_ROI_EN_MAX[i] = mca_calcE (MCA_ROI_CH_MAX[i])
       }
       MCA_ROI_COUNTER[i] = tok[3] 
       i++
     }
   }
   getline(MCA_ROI_DEFAULT_FILE,"close")
 }
}'


#%IU%
#%MDESC% saves ROI definition to disk.
def mcasaveroi '{

if (0 == unix(sprintf("test -w %s/%s/userfiles",SPECD,SPEC))) {
  
  if (0 == unix(sprintf("test -w %s",MCA_ROI_DEFAULT_FILE))) \
         unix(sprintf("rm -f %s",MCA_ROI_DEFAULT_FILE))

  on (MCA_ROI_DEFAULT_FILE) ; offt
  
  printf ("#F mcaroifile\n")
  printf ("#D %s\n",date())
  printf ("#C %s User = %s\n",SPEC,USER)
  printf ("#S 1 $0\n")
  printf ("#N %d\n",MCA_ROI_NO)
  printf ("#L roi no  ch min  ch max  counter\n")

  for (i=0;i<=MCA_ROI_NO;i++) {
    printf ("%d  %d  %d  %s \n",                                                             i,MCA_ROI_CH_MIN[i],MCA_ROI_CH_MAX[i],MCA_ROI_COUNTER[i])
  }
  
  ont ; close (MCA_ROI_DEFAULT_FILE)
}
}'

#%IU% (roi_id)
#%MDESC% Returns ROI number, or -1 if not found. "roi_id" is a ROI name or a ROI number.
def mca_roinum(rid) '{
  local rn num

  for (rn=0;rn<=MCA_ROI_NO;rn++) 
    if (rid == MCA_ROI_COUNTER[rn]) {
      return rn
    }   

  num = rid + 0
  if ((num==rid) && (num<=MCA_ROI_NO)) return rid

  return -1
}'

#%IU% ()  
#%MDESC% Prints out ROI definition table.

def mca_roidisp () '{

  local roi

  printf("\nROI       |   Channels    | %-27s | ROI  | Roi ",                                                  (MCA_CP_XLBL!="")?MCA_CP_XLBL:"calibration   ")
  printf("\nnames     | first | last  | min          | max          |ACTIVE| numbers\n")
  print "---------------------------------------------------------------------"

  for (roi=0;roi<=MCA_ROI_NO;roi++) {
    if (roi==MCA_ROIACTIVE) tty_cntl("so")
    printf("%-10s| %-5d | %-5d | %-12.4f | %-12.4f | %-4s | %d\n",\
          MCA_ROI_COUNTER[roi],\
          MCA_ROI_CH_MIN[roi],MCA_ROI_CH_MAX[roi],MCA_ROI_EN_MIN[roi],\
          MCA_ROI_EN_MAX[roi],(MCA_ROIACTIVE==roi)?" X":" -",roi)
    tty_cntl("se")
  }
  print
}'


#%IU% (no,name)
#%MDESC% Assigns ROI number <no> with name <name>.
def mca_roisetname (no,name) '{
  local roi err

  err = ""

  if (no<=MCA_ROI_NO) {
    if (name!="") MCA_ROI_COUNTER[no]=name
    if (MCA_ROI_COUNTER[no] != "" && (MCA_ROI_COUNTER[no] != "n")) {
      for (roi=0;roi<=MCA_ROI_NO;roi++) 
        if ((roi != no) && (MCA_ROI_COUNTER[no] == MCA_ROI_COUNTER[roi])) {
          MCA_ROI_COUNTER[roi]=""
          err=sprintf("%s     roi %d was taken off name %s\n",                                                 err,roi,MCA_ROI_COUNTER[no])
          break
        }
    }
    MCA_ROIACTIVE=no
  }
  return(err)
}'


#%IU% (no,min,max)
#%MDESC% Assigns ROI number <no> with specified range.
def mca_roisetrange (no,min,max) '{

  global MCA_ROI_EN_MIN MCA_ROI_EN_MAX
  local roi err

  err = ""

  if (no<=MCA_ROI_NO) {
    if (MCA_ENERGY) {
      MCA_ROI_EN_MIN[no]=min
      MCA_ROI_EN_MAX[no]=max
    } else {
      MCA_ROI_CH_MIN[no]=min
      MCA_ROI_CH_MAX[no]=max
    }
    mca_Ech MCA_ENERGY MCA_ROI_EN_MIN[no] MCA_ROI_CH_MIN[no]
    mca_Ech MCA_ENERGY MCA_ROI_EN_MAX[no] MCA_ROI_CH_MAX[no]
    MCA_ROIACTIVE=no
  }
  return(err)
}'


#%IU%  
#%MDESC% ROI edition menu.
def mca_roimenu '{

  mca_roidisp()

  menupru("keys:\n")
  menuoptbutton(0,", ","  add","a")
  menuaction ("_mca_roiadd")
  if (MCA_ROI_NO) {
    menuoptbutton(0,", ","delete","d")
    menuaction ("_mca_roidel")
  }
  printf("or modify:  ")
  for (i=0;i<=MCA_ROI_NO;i++) {
    if (MCA_ROI_COUNTER[i]!="") {
      if (i>0) {
        menuoptbutton(0,"| ","",i)
        menuaction(sprintf("_mca_roichange %d",i))
      }
      menuoptbutton(0,"| ","",MCA_ROI_COUNTER[i])
    } else {
      menuoptbutton(0,"| ","",i)
    }
    menuaction(sprintf("_mca_roichange %d",i))
  }
  print;  print
}'


#%IU%
#%MDESC% New ROI input.
def _mca_roiadd '{
  MCA_ROI_NO++
  _mca_roiname MCA_ROI_NO
  _mca_roirange MCA_ROI_NO
}'

#%IU%
#%MDESC% ROI name input.
def _mca_roiname '{
  local no asw err

  err=""
  no = $1
  asw = getval("Name",MCA_ROI_COUNTER[no])
  if ((err = mca_roisetname(no,asw))!="") menuerror(err)
}'

#%IU%
#%MDESC% ROI range input.
def _mca_roirange '{
  local asw arr err min max

  asw = $1
  err = ""

  if (MCA_ENERGY) {
    min=getval(sprintf("From %s: ",MCA_CP_XLBL),MCA_ROI_EN_MIN[asw])
    if (1==split (min,arr)) {
      max=getval(sprintf("To   %s: ",MCA_CP_XLBL),MCA_ROI_EN_MAX[asw])
    } else {
      min = arr[0]
      max = arr[1]
    }
  } else {
    min=getval("From channel: ",MCA_ROI_CH_MIN[asw])
    if (1==split(min,arr)) {
      max=getval("To   channel: ",MCA_ROI_CH_MAX[asw])
    } else {
      min = arr[0]
      max = arr[1]
    }
  }
  err = mca_roisetrange(asw, min, max)
  if (err!="") menuerror(err)
}'
 
#%IU%
#%MDESC% ROI deletion.

def _mca_roidel '{

   local rqs nn arr no_str na_str ii jj
   
   rqs = getval("which one(s)",MCA_ROI_COUNTER[MCA_ROIACTIVE])

   nn = split (rqs,arr)

   for (no_str=na_str="",ii=0;ii<nn;ii++) {
     if ((jj = mca_roinum (arr[ii])) < 0) \
        menuwarning (sprintf("%s: %s unknown",rqs,arr[ii]))
     else if (index(no_str,jj)) \
        menuwarning (sprintf("%s: %s and %d were the same",rqs,MCA_ROI_COUNTER[jj],jj))
     else {
       no_str = jj " " no_str
       na_str = MCA_ROI_COUNTER[jj] " " na_str
     }
   }

   nn = split (na_str,arr)

   for (ii=0;ii<nn;ii++) {

      jj = mca_roinum (arr[ii])

      if (jj > 0) {

        MCA_ROI_EN_MIN[jj] = MCA_ROI_EN_MIN[MCA_ROI_NO]
        MCA_ROI_EN_MAX[jj] = MCA_ROI_EN_MAX[MCA_ROI_NO]
        MCA_ROI_CH_MIN[jj] = MCA_ROI_CH_MIN[MCA_ROI_NO]
        MCA_ROI_CH_MAX[jj] = MCA_ROI_CH_MAX[MCA_ROI_NO]
        MCA_ROI_COUNTER[jj]= MCA_ROI_COUNTER[MCA_ROI_NO]

        if (MCA_ROIACTIVE == jj) MCA_ROIACTIVE=0
        else if (MCA_ROI_NO == MCA_ROIACTIVE) MCA_ROIACTIVE=jj

        MCA_ROI_NO--

      } else if (0==jj) {
        menuerror("cannot delete roi 0")

      } 
   }
}'

#%IU%
#%MDESC% ROI modification.
def _mca_roichange '{

  if ($1) {
    _mca_roirange $1
  }
  _mca_roiname $1
}'

#==================================================================== SAVE/LOAD

#%UI% ()
#%MDESC% Opens next MCA private file, and writes header on it.

def mca_fileheader (file) '{
# ?? mca_fileheader (file) sh be repl by a call to savefileheader(file) !!
# ??                       in mcasave and mca_save_data funcs.
# ??                       pb is EPOCH .

  local i j

  if (file == "" || file == "0" || open(file)) return -1
  fprintf(file,"#F %s\n", file)
  fprintf(file,"#E %d\n",EPOCH)
  fprintf(file,"#D %s\n",date())
  fprintf(file,"#C %s  User = %s\n",TITLE,USER)

  for (i = 0; i < MOTORS; i += 8) {
    fprintf(file,"#O%d ", i/8)
    for (j = i; j < i + 8 && j < MOTORS; j++)
      if (motor_name(mA[j])!="unused") fprintf(file,"%8s  ", motor_name(mA[j]))
    fprintf(file,"\n")
  }
  return 0
}'

#%UU% [file_name]
#%MDESC% Sets a new file prefix and initialises the spectrum run number, which appears in the file name as e.g. PREFIX_001.mca. But when spectrum was taken during a scan, the file name changes for PREFIX_001_000.mca, where first number is the scan number (SCAN_N) and second one the point number in the scan. 
def mcanewfile '{

  global MCA_PREFIX MCA_PREFIX1 MCA_PREFIX2 MCA_N MCA_SUFFIX 
  local tmpfile a1 a2

  if ($# > 0)  
    MCA_PREFIX = "$1"
  else 
    MCA_PREFIX = getval("MCA File Prefix",MCA_PREFIX)

  MCA_SUFFIX = ".mca"

  if ($# > 1) 
    MCA_N = $2
  else
    MCA_N = 0

  if (MCA_PREFIX == "0")    MCA_PREFIX=""
  if (MCA_PREFIX == "null") MCA_PREFIX="/dev/null"
  if (MCA_PREFIX == "tty")  MCA_PREFIX="/dev/tty"

  if ((MCA_PREFIX != "") && (MCA_PREFIX != "/dev/null") && \
    (MCA_PREFIX != "/dev/tty") ) {

    if (!index(MCA_PREFIX, "/") && !unix(sprintf("test -d %s",DATA_DIR)))\
      MCA_PREFIX = sprintf("%s/%s",DATA_DIR,MCA_PREFIX)
    
    if ($# < 2) {
      tmpfile = sprintf("/tmp/mcatmp_%s_%s",SPEC,USER)
      unix(sprintf("/bin/ls -r %s*%s 2>/dev/null > %s",MCA_PREFIX,\
				MCA_SUFFIX,tmpfile))
      if ((line=getline(tmpfile))!=-1) {
        sscanf(line,sprintf("%s%%d%s",MCA_PREFIX,MCA_SUFFIX),MCA_N)
        getline(tmpfile,"close") 
      }  
      unix(sprintf("/bin/rm -f %s",tmpfile))  

      MCA_N = getval("Last run number",MCA_N)
    }
  }

  MCA_PREFIX1 = MCA_PREFIX "_#r3"
  MCA_PREFIX2 = MCA_PREFIX "_#n3_#p3"

  a1 = mca_filename(MCA_PREFIX1,MCA_N+1,MCA_SUFFIX)
  a2 = mca_filename(MCA_PREFIX2,MCA_N+1,MCA_SUFFIX)
  if (a1!="" || a2!="") {
    printf("Using prefix \"%s\". Next run number is %d. Next scan is %d\n\n",\
                                MCA_PREFIX,MCA_N+1,SCAN_N+1)
    printf("-> single acquisition to files of type: \"%s\"\n",a1)
    printf("-> scans to files of type: \"%s\"\n",a2)
  } else {
    printf("Not a valid MCA prefix\n")
  }
}'

#%IU% (prefix, number, suffix)
#%MDESC% Returns MCA private file name.
def mca_filename (prefix, number, suffix) '{
  local ch dig fname fmt ix

  if ((MCA_PREFIX=="/dev/null") || (MCA_PREFIX=="/dev/tty")) return MCA_PREFIX
  if ((MCA_PREFIX == "") || (MCA_PREFIX == "0")) return 0

  fname = prefix suffix

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

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

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

  return (fname)
}'


#%IU%
#%MDESC% Returns true when the saveload package macros are loaded.
def MCA_SL '((whatis("savemcadata")&2)&&(whatis("savemcadata")>>16>3))'

#%IU% [string]
#%MDESC% Checks if saveload macro package is loaded.

def mca_sl_test '{

if (!(MCA_SL)) {
  printf("MCA: Macros set \"saveload.mac\" not loaded.\n")
  print "     (..Typing \"jdo savelaod.mac\" may help..)"

  if ($#) {
    printf("     For now, cannot execute %s\n","$*")
    exit
  }     
}
}'  

#%UI% ()
#%MDESC% Applies data reduction on data in SPEC memory. 
#%BR% The reduction consists of:
#%UL%
#%LI% averaging counts every "factor" points.
#%LI% multiplying by "factor" each integer average to get an integrated value.
#%XUL%
def mca_data_red () '{
  MCA_DATARED[][1] = MCA_REDUCTION*array_op("contract",MCA_DATA[][1],MCA_REDUCTION)
}'
 
 
#%UU% [roi|min] [max] [-silent]
#%MDESC% Saves acquired data to disk file.
#%BR% If a range is specified, the data are saved within that range, otherwise the whole spectrum is dumped to the file. The file is either the standard scanfile or a private MCA file, depending on "mcasetup" entries. %BR%
# If standard scanfile is used, each spectrum originated from out of a scan (ct or mcaacq) is nevertheless referenced to a "scan number". (SCAN_N is incremented).%BR%
# If a private file is used, it must have been set a prefix using "mcanewfile" command. Then each spectrum is saved to a different file. The file name extensions gives the information on its origin. see%B% mcanewfile%B%.
#%BR% The file syntax is standard and MCA mixed. MCA syntax is described below:
#%BR% Each MCA related line holds the character "@".
#%DL% MCA file syntax:
#%DT% #@MCA %%16C 
#%DD% Format string passed to data_dump() function. This format string is held by the global variable "MCA_FMT" and can then been adapted to particular needs. "%%16C" is the default. It dumps data on 1 line, cut every 16 points:
#%PRE%
#@A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\
# 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\
# 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\
# 0 0 0 0 0 0 0 0 0 0 0 ...
#%PRE% 
# "%%16" would do the same without any backslash, "1" would dump 1 point per line, ...
#%DT% #@CHANN 1024 0 1023 1 
#%DD% number of data points, first MCA channel, last one, reduction factor.
#%DT% #@CTIME 1 17 17 
#%DD% Time preset, MCA elapsed live time, MCA elapsed real time.
#%DT% #@CALIB  0 1 0
#%DD% Calibration parameters as "a b c", in "E = a + b*ch + c*ch^2".
#%DT% @A 0 0 0....
#%DD% MCA data. Each value is the content of one channel, or an integrated value over several channels if a reduction was applied. 
#%XDL%
# Data reduction is useful in some cases to minimize file sizes, which might grow very fast and eventually fill up the disk.
#%BR% It consists of:
#%UL%
#%LI% averaging counts every "factor" points.
#%LI% multiplying by "factor" each integer average to get an integrated value.
#%XUL%
#When "-silent" the macro does not ask for a user comment.
def mcasave '
mca_sl_test "$0"  
{

  local file cmin cmax 
  local reduc rnpts first k

  _cols = 0
  if (MCA_FLAG&4) {
    file = mca_filename (MCA_PREFIX1,MCA_N+1,MCA_SUFFIX)
  } else {
    file = DATAFILE
  }

  FPRNT = ""
  HEADING = "$0 $*"
  DATE = date()

  if ($2) {
    if (MCA_ENERGY) {   
      cmin = mca_calcch($1)
      cmax = mca_calcch($2)
    } else { cmin=$1; cmax=$2 }
  } else {
     mca_getroi $1 0 cmin cmax
  } 
  mca_resize_to_last_read cmin cmax

  if (cmin<=cmax)  { 
    if (MCA_REDUCTION>1) {
      reduc = MCA_REDUCTION
      if (MCA_FRED[0]>1) {
        printf("MCA: Those data were already reduced by a factor of %g\n",                       MCA_FRED[0])
        if (yesno(sprintf("     Do you want to apply factor %g again",                                           MCA_REDUCTION),0)) {
          reduc *= MCA_FRED[0]
          mca_data_red()
        } else reduc = MCA_FRED[0]
        rnpts = int((cmax-cmin  )/reduc) + 1
      } else {
        rnpts = int((cmax-cmin+1)/reduc)
        mca_data_red()
      }
    } else {
      reduc = (MCA_FRED[0]>1)?MCA_FRED[0]:1
      rnpts = int((cmax-cmin  )/reduc) + 1
    }
    
    if (rnpts>0) {
      if (MCA_FLAG&4) {
        if (mca_fileheader(file)<0) exit
        MCA_N += savestdheader( file, 3, 0)      # 3 means save motor pos.
      } else {
        SCAN_N = savestdheader( file, 3, SCAN_N)
        if (SCAN_N<0) {
          SCAN_N=-SCAN_N
          exit
        }
      }
      savemcaheader(file,MCA_FMT,rnpts,cmin,cmax,reduc,COUNT_TIME,MCA_LIVE_T,MCA_REAL_T)
      mca_tops
      savemcacalib(file,PS_EA,PS_EB,PS_EC)

      for (k=0 ; k<=MCA_ROI_NO ; k++) {
        if ((MCA_ROI_COUNTER[k]!="0") && (-1!=cnt_num(MCA_ROI_COUNTER[k]))) {
          savemcaroi(file, MCA_ROI_CH_MIN[k],MCA_ROI_CH_MAX[k],cnt_name(cnt_num(MCA_ROI_COUNTER[k])))
        }
      }
      savecntheader(file)

      if (!index("$*","-silent")) {
        local comment
        comment = getval ("Comment","")
        if (comment!="") fprintf(file,"#@C %s.  \n", comment)
      }

      savecounters(file)

      if (MCA_REDUCTION>1) {
        first = mca_getoffset( MCA_DATARED, 0, cmin)
        savemcadata (file,MCA_DATARED[first:first+rnpts-1][1],rnpts, MCA_FMT)
      } else {
        first = mca_getoffset( MCA_DATA, 0, cmin)
        savemcadata (file,MCA_DATA[first:first+rnpts-1][1],rnpts, MCA_FMT)
      }

      printf("MCA: %d datapoints written to file %s\n",rnpts,file)
      if (MCA_FLAG&4) {
        close(file)
        printf("     spectrum number %d\n",MCA_N)
      } else printf("     scan number %d\n",SCAN_N)
      
    } else {
      printf("MCA ERROR: 0 datapoints saved. Binning too large.\n")
      if (MCA_FLAG&4) printf("     spectrum number %d\n",MCA_N)
      else printf("     scan number %d\n",SCAN_N)
    }
  } else {
    printf("MCA ERROR: 0 datapoints saved. Wrong data range\n")
    if (MCA_FLAG&4) printf("     spectrum number %d\n",MCA_N)
    else printf("     scan number %d\n",SCAN_N)
  }
}'


#%UU%  <file> <scan_no> [scanpt_no] [0|1] 
#%MDESC% Loads spectrum from a file.
#%BR%The loaded spectrum is stored into WS memory as if it would have just been acquired. 
#If file is a standard scan file, spectra are referrenced to by their "scan" number, and eventually their "scan_point" number. 
#Both numbers must be 0 when loading data from private MCA files. 4th argument to 1 means that the calibration parameters are to be loaded from the file as well. In that case any other current calibration is overwritten. 
#To avoid it, "mcasave" it with the current spectrum, before "mcaload"ing. %BR%
#Reduced data channel numbering starts from the first channel value (prior to reduction) added integer part of half the "factor", every next point incremented by "factor" .....

def mcaload '

mca_sl_test "$0"

{
  global MCA_SNO MCA_SPNO MCA_LOADF MCA_CALFF

  global MCA_FRED MCA_old_channel
  local calpar dsize doffset 
  local ulong array tmpdata [16384][1]

  if (!$#) {
    MCA_LOADF = getval("file to load data from",MCA_LOADF)
    MCA_SNO = getval("scan number",MCA_SNO?MCA_SNO:1)
    MCA_SPNO = getval("scan point",MCA_SPNO?MCA_SPNO:1)
    MCA_CALFF = yesno("load calibration parameters",MCA_CALFF)
  } else {
    MCA_LOADF = "$1"
    MCA_SNO = $2?$2:1
    MCA_SPNO = $3?$3:1
    MCA_CALFF = $4
  }

  if (MCA_CALFF && !(MCA_PS)) {
    printf("MCA: Energy mode not available. Macro set psearch.mac not loaded.\n")
    MCA_CALFF = 0
  }

  loadmcadata \'"MCA_LOADF"\' tmpdata 0 MCA_SNO MCA_SPNO MCA_CALFF MCA_old_channel[0] MCA_old_channel[1] MCA_FRED[0] calpar

  if (MCA_FRED[0]<1) MCA_FRED[0]=1
  MCA_FRED[1]=MCA_SNO

  dsize = int ((MCA_old_channel[1]+1)/MCA_FRED[0])
  doffset = int (MCA_old_channel[0]/MCA_FRED[0])

  if (dsize > MCA_MEMGRPSIZE) {
    shared ulong array MCA_DATA [dsize][2]
#    if (MCA_GRP) data_grp(MCA_GRP,dsize,2)
  }
  if ((dsize > MCA_MEMGRPSIZE)||(MCA_FRED[0] > 1)) {
    ulong array MCA_DATARED [int(dsize/MCA_REDUCTION/MCA_FRED[0])][2]
    array_op("fill",MCA_DATARED[][0],MCA_REDUCTION*MCA_FRED[0])
    MCA_DATARED[][0]+=int( MCA_REDUCTION*MCA_FRED[0]/2 )
  }

  MCA_DATA[doffset:][1] = tmpdata
  array_op ("fill", MCA_DATA[][0], MCA_FRED[0])
  MCA_DATA[][0] +=int(MCA_FRED[0]/2)

  MCA_IN_GROUP = 0

  MCA_EA=MCA_EC=PS_WA=PS_WB=PS_WC=0
  MCA_EB=1

  if (MCA_CALFF) {
    local calarr
    split (calpar,calarr)
    MCA_EA=calarr[0]
    MCA_EB=calarr[1]
    MCA_EC=calarr[2]
  } else if (MCA_ENERGY) { 
    MCA_ENERGY=0
    MCA_PLOTERASE=1
  }
  printf ("      Now in %s mode\n",MCA_ENERGY? "ENERGY": "CHANNEL")
  mca_roi_Ech
}'

#%IU% (ch_min,ch_max)
#%MDESC% Save file header during scans. Hooked to "measure2".
def mca_savescanhead (ch_min,ch_max) '{

  local npts saveit file privfile

  saveit   = (MCA_FLAG&1)
  privfile = (MCA_FLAG&4)

  if (!saveit) return(-1)

  mca_resize_to_last_read ch_min ch_max
  npts     = int( (ch_max-ch_min+1) / (MCA_REDUCTION>0?MCA_REDUCTION:1) )
  if (npts<=0) return (-1)

  if (privfile) {
    file = mca_filename (MCA_PREFIX2,0,MCA_SUFFIX)
    if (mca_fileheader(file)<0) return(-1)
  } else file = DATAFILE

#  if (privfile) MCA_N += savestdheader ( file, 3, 0)
  if (privfile) savestdheader ( file, 3, 0)

  if (privfile || !NPTS) {
    savemcaheader(file,MCA_FMT,npts,ch_min,ch_max,MCA_REDUCTION,COUNT_TIME,MCA_LIVE_T,MCA_REAL_T)
    mca_tops
    savemcacalib(file,PS_EA,PS_EB,PS_EC)
    for (j=0; j<=MCA_ROI_NO ;j++) {
      if ((MCA_ROI_COUNTER[j]!="") &&                                                    (-1!=cnt_num(MCA_ROI_COUNTER[j]))) {
        savemcaroi(file,MCA_ROI_CH_MIN[j],MCA_ROI_CH_MAX[j],cnt_name(cnt_num(MCA_ROI_COUNTER[j])))
      }
    }
  }
}'

#printf("MCA file: ") 
#print ccdfilename (MCA_PREFIX "_#n3",SCAN_N,"_*" MCA_SUFFIX) 

#%IU% (ch_min,ch_max)
#%MDESC% Save MCA data during scans. Hooked to "user_scan_loop".

def mca_savescandata (ch_min,ch_max) '{

  local npts first saveit file privfile

  saveit   = (MCA_FLAG&1)
  privfile = (MCA_FLAG&4)

  if (!saveit) return(-1)

  mca_resize_to_last_read ch_min ch_max
  npts     = int( (ch_max-ch_min+1) / (MCA_REDUCTION>0?MCA_REDUCTION:1) )
  if (npts<=0) return (-1)

  if (privfile) file = mca_filename (MCA_PREFIX2,0,MCA_SUFFIX)
  else          file = DATAFILE

  if (MCA_REDUCTION>1) {
    mca_data_red()
    first = mca_getoffset( MCA_DATARED, 0, ch_min)
    savemcadata (file, MCA_DATARED[first:first+npts-1][1],npts, MCA_FMT)
  } else {
    savemcadata (file, MCA_DATA[ch_min:ch_max][1],npts, MCA_FMT)
  }

  if (privfile) close(file)
}'

#%IU% (ch_min,ch_max)
#%MDESC% Save header and data to file after a "ct". Hooked to "user_handlecounts".
def mca_savectdata (ch_min,ch_max) '{

  local npts first file privfile saveit

  saveit   = (MCA_FLAG&2) 
  privfile = (MCA_FLAG&4)

  if (!saveit) return(-1)

  mca_resize_to_last_read ch_min ch_max
  npts     = int( (ch_max-ch_min+1) / (MCA_REDUCTION>0?MCA_REDUCTION:1) )

  if (npts<=0) return (-1)

  if (privfile) {
    file = mca_filename(MCA_PREFIX1,MCA_N+1,MCA_SUFFIX)
    if (mca_fileheader(file)<0) return(-1)
  } else file = DATAFILE

  HEADING = sprintf("ct %g",COUNT_TIME)
  DATE = date()
  if (privfile) {
    MCA_N += savestdheader( file, 1, 0)
  } else {
    SCAN_N = savestdheader( file, 1, SCAN_N)
    if (SCAN_N<0) {
      SCAN_N=-SCAN_N
      return(-1)
    }
  }

  savemcaheader(file,MCA_FMT,npts,ch_min,ch_max,MCA_REDUCTION,COUNT_TIME,MCA_LIVE_T,MCA_REAL_T)
  mca_tops
  savemcacalib(file,PS_EA,PS_EB,PS_EC)
  for (j=0; j<=MCA_ROI_NO ;j++) {
    if ((MCA_ROI_COUNTER[j]!="") &&                                                    (-1!=cnt_num(MCA_ROI_COUNTER[j]))) {
      savemcaroi(file,MCA_ROI_CH_MIN[j],MCA_ROI_CH_MAX[j],cnt_name(cnt_num(MCA_ROI_COUNTER[j])))
    }
  }
  
  FPRNT=""
  savecntheader(file)
  savecounters(file)

  if (MCA_REDUCTION>1) {
    mca_data_red()
    first = mca_getoffset( MCA_DATARED, 0, ch_min)
    savemcadata (file, MCA_DATARED[first:first+npts-1][1],npts, MCA_FMT)
  } else {
    savemcadata (file, MCA_DATA[ch_min:ch_max][1],npts, MCA_FMT)
  }

  printf("MCA: %d datapoints written to file %s\n",npts,file)
  if (privfile) printf("     spectrum number %d\n",MCA_N)
  else printf("     scan number %d\n",SCAN_N)

  if (privfile) close(file)
}'

#%IU% (ch_min, ch_max, headline)
#%MDESC% Save header and data to file after a "mcaacq". Called from "mcaacq".

def mca_saveacqdata (ch_min, ch_max, headline) '{

  local npts first file privfile

  privfile = (MCA_FLAG&4)

  mca_resize_to_last_read ch_min ch_max
  npts     = int( (ch_max-ch_min+1) / (MCA_REDUCTION>0?MCA_REDUCTION:1) )
  if (npts<=0) return (-1)

  if (privfile) {
    file = mca_filename(MCA_PREFIX1,MCA_N+1,MCA_SUFFIX)
    if (mca_fileheader(file)<0) return(-1)
  } else file = DATAFILE

  if (length(headline)) HEADING = headline
  DATE = date()
  if (privfile) {
    MCA_N += savestdheader( file, 3, 0)
  } else {
    SCAN_N = savestdheader( file, 3, SCAN_N)
    if (SCAN_N<0) {
      SCAN_N=-SCAN_N
      return(-1)
    }
  }

  savemcaheader(file,MCA_FMT,npts,ch_min,ch_max,MCA_REDUCTION,COUNT_TIME,MCA_LIVE_T,MCA_REAL_T)
  mca_tops
  savemcacalib(file,PS_EA,PS_EB,PS_EC)

  if (MCA_REDUCTION>1) {
    mca_data_red()
    first = mca_getoffset( MCA_DATARED, 0, ch_min)
    savemcadata (file, MCA_DATARED[first:first+npts-1][1],npts, MCA_FMT)
  } else {
    savemcadata (file, MCA_DATA[ch_min:ch_max][1],npts, MCA_FMT)
  }

  printf("MCA: %d datapoints written to file %s\n",npts,file)
  if (privfile) printf("     spectrum number %d\n",MCA_N)
  else printf("     scan number %d\n",SCAN_N)

  if (privfile) close(file)
}'





#=========================================================== ENERGY CALIBRATION

#%IU% <array1> <col1> <array2> <col2>
#%MDESC% Same as ps_chtoE from psearch.mac package. i.e., converts all the channels in array1[][col1] to energies and puts these values into destination array2[][col2]. The calibration function  E=a+b ch + c ch^2 is used.

def mca_chtoE '{
  mca_tops
  ps_chtoE ($1[][$2],$3[][$4])
  MCA_IN_GROUP = 0
}'

#%IU%
#%MDESC% Reads in parameters from shared memory (GUI).
def mca_tops '
  if (MCA_EB==0) MCA_EB=1
  PS_EA = MCA_EA ; PS_EB = MCA_EB ; PS_EC = MCA_EC
'


#%IU%
#%MDESC% calibration parameter A.(Shared memory)
def MCA_EA 'MCA_DATA_PARAM[0]'
#%IU%
#%MDESC% calibration parameter B.(Shared memory)
def MCA_EB 'MCA_DATA_PARAM[1]'
#%IU%
#%MDESC% calibration parameter C.(Shared memory)
def MCA_EC 'MCA_DATA_PARAM[2]'

#%IU% <mode> <energy> <channel>
#%MDESC% Converts calibrated value into channels (mode 1) or reverse (mode 0)
#and returns the result.
def mca_Ech '{

  if ($1) { 
    $3 = mca_calcch($2)
  } else { 
    $2 = mca_calcE ($3)
  }
}'


#%IU% 
#%MDESC% Calculated the channel from the given Energy
def mca_calcE (x) '{
  mca_tops
  return ps_calcE (x)
}'

#%IU% 
#%MDESC% Calculated the channel from the given Energy
def mca_calcch (en) '{
  mca_tops
  return ps_calcch (en)
}'
  

#%UU% 
#%MDESC% Shows calibration fit parameters or inputs new parameters. 
def mcapar '
mca_ps_test "$0"
{
   mca_tops
   ps_parinput
   mca_fromps
   mca_roi_Ech
   MCA_IN_GROUP = 0
}'
  

#%IU%
#%MDESC% Writes out parameters to shared memory (GUI).
def mca_fromps '
   if (PS_EB==0) PS_EB=1
   MCA_EA = PS_EA ; MCA_EB = PS_EB ; MCA_EC = PS_EC ; 
'


#%UU%
#%MDESC% Toggles between channel (uncalib) and calibrated mode.
def mcaE '{
global MCA_ENERGY

MCA_ENERGY=!MCA_ENERGY

if (MCA_ENERGY && !(MCA_PS)) {
  printf("MCA: Energy mode not available.                                              \n     Macro set \"psearch.mac\" not loaded. \n")
  MCA_ENERGY = 0
} else {
  MCA_PLOTERASE=1
  MCA_IN_GROUP =0
  printf ("MCA: Now in %s mode\n",MCA_ENERGY? "ENERGY": "CHANNEL")
  if (MCA_ENERGY) {	
    MCA_CP_XLBL=getval("X Label",(MCA_CP_XLBL!="")?MCA_CP_XLBL:"Energy")
    MCA_CP_XUNT=getval("X Units",(MCA_CP_XUNT!="")?MCA_CP_XUNT:"KeV")
  }
}
}'


#%IU% 
#%MDESC% Returns non 0 value if psearch macro package is loaded.
def MCA_PS 'whatis("ps_dump")&2'

#%IU% [string]
#%MDESC% Check if psearch macro package is loaded.

def mca_ps_test '{

if (!(MCA_PS)) {
  printf("MCA: Macros set \"psearch.mac\" not loaded.  \n")
  print "      (..Typing \"jdo psearch.mac\" may help..)"

  if ($#) {
    printf("     For now, cannot execute %s\n","$*")
    exit
  }     
}
}'  

#%UU%  
#%MDESC% Computer aided energy calibration of the MCA. 
def mcacal '
mca_ps_test "$0"
{
   mca_tops
   ps_calib(MCA_DATA[][1],0,MCA_MEMGRPSIZE)
   mca_fromps
   mca_roi_Ech
   MCA_IN_GROUP=0
}'

#%UU%
#%MDESC% Manual calibration of the MCA.
def mcacalm '
mca_ps_test "$0"
{
  global PS_NOPEAKS 
  array PS_PEAKS[200][7]
  local ii

  PS_NOPEAKS = getval("Enter number of peaks",PS_NOPEAKS)
  for (ii=0;ii<PS_NOPEAKS;ii++) {
    PS_PEAKS[ii][1] = getval(sprintf("Peak pos. in ch for peak %d",ii+1),                                            PS_PEAKS[ii][1])
    PS_PEAKS[ii][0] = ii+1
  }
  mca_tops
  ps_dump
  ps_calibration
  mca_fromps
  mca_roi_Ech
  MCA_IN_GROUP = 0
}'


#%UU% 
#%MDESC% Peak search on the current spectrum.
def mcapeak '
mca_ps_test "$0"
{
   mca_tops
   pssearch (MCA_DATA[][1],0,MCA_MEMGRPSIZE)
}'

#%UU%  
#%MDESC% Shows peaks found.
def mcashow '
mca_ps_test "$0"
{
   mca_tops
   ps_show
}'


#==================================================================== PLOT

#---------------------------------------------------------------- CPLOT

#%UU%  [first|roi] [last]
#%MDESC% A screen plot of the current MCA data in cplot format.
#Part of the plot parameters are taken from "mcasetup", rest from "cpsetup" settings.
def mcacplot '
if (0==(whatis("cpsetup")&2)) {
  print "MCA: Macros set \"cplot.mac\" not loaded."
  print "     (..Typing \"jdo cplot.mac\" may help..)"
  print "     For now, cannot execute $0"
  exit
}
 
cp_setx11   
mca_cplot $*
'

#%UU%  [first|roi] [last]
#%MDESC% A printer plot of the current MCA data in cplot format.
# That follows the same rules as "mcacplot" macro.
def mcapplot '
if (0==(whatis("cpsetup")&2)) {
  print "MCA: Macros set \"cplot.mac\" not loaded."
  print "     (..Typing \"jdo cplot.mac\" may help..)"
  print "     For now, cannot execute $0"
  exit
}
cp_setprinter
mca_cplot $*
'

#%IU%
#%MDESC% Decides between data in memory or in files for cplot.
def mca_cplot '{
  if (MCA_CP["FROMF"]) {
    mca_fplot $*
  } else {
    mca_mplot $*
  }
}'


#%UI% [first|roi] [last]
#%MDESC% Arranges cplot parameters for MCA private needs and calls cplot program. 
#Recover previous cpsetup settings when finished.

def mca_mplot '{

  local oldpar 

  for (i in CP_PAR)   oldpar[i]=CP_PAR[i]

  if ((CP_PAR["GLOBTITLE"] = getval ("Global title",MCA_CP["GLOBTITLE"]))!="")\
       CP_PAR["FLAGS"] |= 0x20000
  else CP_PAR["FLAGS"] &= ~0x20000

  CP_PAR["PTITLE"] = getval ("Title",MCA_CP["PTITLE"])

  if ((CP_PAR["COMMENT"] = getval ("Comment",MCA_CP["COMMENT"]))!="") \
       CP_PAR["FLAGS"] |= 0x80000
  else CP_PAR["FLAGS"] &= ~0x80000

#  CP_PAR["LINES"]=CP_PAR["COLS"]=1			# 1 per page

  CP_PAR["FLAGS"] &= ~0x10				# landscape

  if (!MCA_LOG) CP_PAR["FLAGS"] &= ~0x1000		# y dec
  else CP_PAR["FLAGS"] |= 0x1000			# y log

  if (!MCA_LINES) {
    CP_PAR["FLAGS"] &= ~1				# no lines
    CP_PAR["FLAGS"] |= 2				# points
    if (!MCA_DOTS) CP_PAR["PSIZE"]=1			# small ones
  } else {
    CP_PAR["FLAGS"] |= 1				# lines
    if (!MCA_DOTS) CP_PAR["FLAGS"] &= ~2		# no points	
    else CP_PAR["FLAGS"] |= 2				# points
  }

  if (MCA_ENERGY) {
    CP_PAR["PXLABEL"]=MCA_CP_XLBL			# X labelling
    CP_PAR["PXUNITS"]=MCA_CP_XUNT
  } else {
    CP_PAR["PXLABEL"]="Channel "
    CP_PAR["PXUNITS"]=""  
  }  
  CP_PAR["PYLABEL"]="Intensity"  			# Y labelling
  CP_PAR["PYUNITS"]="Counts"

  if ($#) {
    local roi y _xmin _xmax _ymin _ymax
    
    roi = (($#==1)||($#==3))
    y = (($#==3)||($#==4))
    _ymin = _ymax = MCA_AUTO
    if (roi) {
      mca_getroi $1 MCA_ENERGY _xmin _xmax
      if (y) { _ymin = $2 ; _ymax = $3 }
    } else {
      _xmin=$1;_xmax=$2
      if (y) { _ymin = $3 ; _ymax = $4 }
    } 

    CP_PAR["FLAGS"] &= ~0xc
    CP_PAR["MINX"]=_xmin ; CP_PAR["MAXX"]=_xmax ; 
    CP_PAR["MINY"]=_ymin ; CP_PAR["MAXY"]=_ymax ;

  } else if ((MCA_XMIN||MCA_XMAX) && (MCA_YMIN||MCA_YMAX)) {

    CP_PAR["MINX"]=MCA_XMIN ; CP_PAR["MAXX"]=MCA_XMAX ; 
    CP_PAR["MINY"]=MCA_YMIN ; CP_PAR["MAXY"]=MCA_YMAX ;

    CP_PAR["FLAGS"] &= ~0xc

  } else {
    CP_PAR["FLAGS"] |= 12  
  }

  if (MCA_AUTO==CP_PAR["MINX"]) CP_PAR["FLAGS"] |= 4
  if (MCA_AUTO==CP_PAR["MAXX"]) CP_PAR["FLAGS"] |= 4 
  if (MCA_AUTO==CP_PAR["MINY"]) CP_PAR["FLAGS"] |= 8
  if (MCA_AUTO==CP_PAR["MAXY"]) CP_PAR["FLAGS"] |= 8 
  
#########################################################

#  if (!MCA_IN_GROUP) { mca_sharedarray_to_group }
  cp_mplot MCA_DATA 0 1 

  for (i in CP_PAR) CP_PAR[i]=oldpar[i]
}'


#%IU%
#%MDESC% not implemented yet. foreseen for c-plotting MCA data from a file.
def mca_fplot '{
#$*
}'



#---------------------------------------------------------------- SCREEN PLOT
#%UU%
#%MDESC% Turns MCA Graphical Interface on.
def mcaguion '{
  global MCA_GUI
  MCA_GUI=1
  mca_guirun
}'

#%UU% 
#%MDESC% Turns MCA Graphical Interface off.
def mcaguioff '{

local file pid
file = sprintf("/tmp/mcagui_%s_%s.pid",SPEC,USER)

if (MCA_PID) unix(sprintf("kill -9 %d 2>/dev/null",MCA_PID)) 
if (!unix(sprintf("test -r %s", file))) {
  pid = getline(file)
  getline(file,"close")  
  if (pid!=MCA_PID) unix(sprintf("kill -9 %d 2>/dev/null",pid))
  unix(sprintf("/bin/rm -f %s",file))
}
MCA_GUI=0
MCA_PID=0
}'

#%IU%
#%MDESC% Checks wether the GUI is running, otherwise starts it.
def mca_guirun '{
  global MCA_PID

  if (!MCA_PID || unix(sprintf("kill -0 %d 2>/dev/null",MCA_PID))) {
    MCA_PID =  mca_guistart()
  }
}'

#%IU% ()
#%MDESC% Starts the Graphical Interface and returns its PID number.
def mca_guistart () '{
  local pid file guicmd

  file = sprintf("/tmp/mcagui_%s_%s.pid",SPEC,USER)
  if (ostype() == "linux"){
    #guicmd = sprintf("newplot -s %s --shm=MCA_DATA -display %s",SPEC, DISPLAY)
    guicmd = sprintf("PyMca --spec=%s --shm=MCA_DATA",SPEC)
  }else{
    guicmd = sprintf("mcatcl -ver %s -shm MCA_DATA -display %s",SPEC, DISPLAY)
  }
  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("/bin/rm -f %s",file))
  unix(sprintf("%s >/dev/null 2>&1 & echo \$! > %s",guicmd,file))
  pid = getline(file)
  getline(file,"close")  
  return (pid)
}'


#%IU% 
#%MDESC% Just an indirection for mca_plot1 for the sake of the GUI.
def mca_plotit '{

if (MCA_GUI) {
  mca_guirun
} else {
#  if (!MCA_IN_GROUP) { mca_sharedarray_to_group } 
  mca_plot1 (MCA_DATA, 0, 1, $1, $2, $3, $4)
}
}'

#%IU% (group,xelem,yelem,xmin,xmax,ymin,ymax)
#%MDESC% MCA running plot.

def mca_plot1 (group,xelem,yelem,xmin,xmax,ymin,ymax) '{

plot_cntl("filter2")

if (PLOT_MODE&128) {
  plot_cntl(sprintf("colors=%s",splot_col))
  plot_cntl("open")
  plot_cntl(MCA_PLOTATTR)
}

if (MCA_PLOTERASE) {
  plot_cntl("erase")
  plot_move(0,1,sprintf("MCA ACQ SPECTRUM %s",MCA_FLAG?(MCA_FRED[0]?MCA_FRED[1]:(MCA_FLAG&4?MCA_N:SCAN_N)):""))
  plot_move(0,2,"Counts")
  if (MCA_ENERGY) plot_move(0,-1,sprintf("%.8s", MCA_CP_XLBL)) 
  else plot_move(0,-1,sprintf("%.8s", "Channels")) 
  MCA_PLOTERASE=0
}

plot_range(xmin,xmax,ymin,ymax)

{
  local n1 nn res1 res2

#  _pl_arg group xelem yelem
  
  pl_a="MCA_DATA"
  pl_x=xelem
  pl_y=yelem

  plot_cntl("mca") 
  array_plot(MCA_DATA[][0], MCA_DATA[][1])

  n1 = mca_getoffset( MCA_DATA, xelem, xmin)
  nn = mca_getnpts  ( MCA_DATA, xelem, xmin, xmax)

  if (nn>1) {
    res1 = sprintf("Peak at %.5g is %.5g.  COM at %.5g.   ",                            MCA_DATA[array_op("row_at_max",MCA_DATA[n1:nn+n1-1][1])][xelem],                  array_op("max",MCA_DATA[n1:nn+n1-1][1]),                                      array_op("com",MCA_DATA[n1:nn-1+n1][xelem],MCA_DATA[n1:nn-1+n1][1]))
    res2 = sprintf("FWHM is %.5g at %.5g.  Total counts are %g",                      array_op("fwhm",MCA_DATA[n1:nn-1+n1][xelem],MCA_DATA[n1:nn-1+n1][1]),            array_op("cfwhm",MCA_DATA[n1:nn-1+n1][xelem],MCA_DATA[n1:nn-1+n1][1]),            array_op("sum",MCA_DATA[n1:n1+nn-1][1]))
  }

  plot_move(-50,0,res1)
  plot_move(-50,1,res2)
}

plot_cntl("filter1")
}'
  
#%UU%  [xmin] [xmax] [ymin] [ymax]
#%MDESC% Plots the current MCA data spectrum. Does nothing when using GUI.
#%DL% Detail of usage:
#%DT%  mcasplot first last [ymin ymax]
#%DD%  plots acquired spectrum between the limits specified.
#	Eventually, "ymin" and "ymax" are Y limits values so that you may 
#	Y-rescale your plot.
#%DT%  mcasplot roino [ymin ymax]
#%DD%  plots acquired spectrum within ROI specified.
#%DT%  mcasplot
#%DD%  plots the whole acquired spectrum
#%XDL%
def mcasplot '{

global MCA_XMIN MCA_XMAX MCA_YMIN MCA_YMAX

  local _xmin _xmax _ymin _ymax roi y 

  MCA_PLOTERASE=1
  
  roi = (($#==0)||($#==1)||($#==3))
  y = (($#==3)||($#==4))
  _ymin = _ymax = MCA_AUTO
  if (roi) {
    mca_getroi $1 MCA_ENERGY _xmin _xmax
    if (y) { _ymin = $2 ; _ymax = $3 }
  } else {
    _xmin=$1;_xmax=$2
    if (y) { _ymin = $3 ; _ymax = $4 }
  } 

  MCA_XMIN=_xmin ; MCA_XMAX=_xmax ; MCA_YMIN=_ymin ; MCA_YMAX=_ymax ;

  mca_plotit _xmin _xmax _ymin _ymax
}'


#=============================================================== MISCELLANEOUS 

#%IU% <roi> <channel_min> <channel_max>
#%MDESC% Resises specified range to the specified roi. (in channels)
def mca_resize_to_roi '
  $2=($2<MCA_ROI_CH_MIN[$1])?MCA_ROI_CH_MIN[$1]:$2
  $3=($3>MCA_ROI_CH_MAX[$1])?MCA_ROI_CH_MAX[$1]:$3
'

#%IU% <channel_min> <channel_max>
#%MDESC% Resises specified range to the last read spectrum range. (in channels)
def mca_resize_to_last_read '
  $1=($1<MCA_old_channel[0])?MCA_old_channel[0]:$1
  $2=($2>MCA_old_channel[1])?MCA_old_channel[1]:$2
'

#%IU% 
#%MDESC% Transfers data spectrum held in the shared memory into SPEC data group.
def mca_sharedarray_to_group '{
  global MCA_IN_GROUP MCA_CALIBRATED
  data_read(MCA_DATA,MCA_GRP,0,0)
  if (MCA_ENERGY) {
    float array MCA_CALIBRATED [MCA_MEMGRPSIZE][1]
    mca_chtoE MCA_DATA 0 MCA_CALIBRATED 0
    data_read(MCA_CALIBRATED,MCA_GRP,0,0)
  } 
  MCA_IN_GROUP = 1
}'


#%IU% (seconds)
#%MDESC% loops printing dots for the specified time (sec.).
def mca_msgw (seconds)'{
local tps
for (tps=time();time()<tps+seconds;) {
  sleep(seconds/10);
  printf(".")
}
}'


#%IU% (name,column,xmin) 
#%MDESC% Returns array row number of first "xmin" value occurence in the specified array column.
def mca_getoffset (name,column,xmin) '{

  local offset fch 

  if (column==2) {
    fch = mca_calcch(xmin)
  } else fch=xmin

  offset = array_op("i_<=_value",name[][column],xmin)
  offset -= ((offset*MCA_FRED[0]-fch>0)?1:0)

  return(offset)
}'

#%IU% (name,column,xmin,xmax) 
#%MDESC% Returns number of points between first occurences of "xmin" and "xmax" in the specified array column.
def mca_getnpts (name,column,xmin,xmax) '{

  local npt 

  npt = array_op("i_<=_value",name[][column],xmax) -                                  mca_getoffset(name,column,xmin) + 1

  if (npt<0) npt=0

  return(npt)
}'

#%IU%
#%MDESC% Macro which is run once at mca.mac file loading to prepare things up.
def mca_const_utils_and_rdef '{

#======================================================================= CONST

global DEVRUN DEVON DEVFAULT MCA_DEVSTATE
global MCA_ROI_DEFAULT_FILE MCA_AUTO MCA_FMT 

DEVRUN=14; DEVON=2; DEVFAULT=23
MCA_DEVSTATE[-1] = "none configured"
MCA_DEVSTATE[0] = "disconnected"
MCA_DEVSTATE[-2] = "simulation (idle)"
MCA_DEVSTATE[-14] = "simulation (acquiring)"
MCA_DEVSTATE[2] = "idle"
MCA_DEVSTATE[14] = "acquiring"
MCA_DEVSTATE[23] = "FAULT"
MCA_DEVOK=0

MCA_AUTO = "auto"
if (MCA_FMT=="") MCA_FMT = "%16C"
MCA_ROI_DEFAULT_FILE = sprintf("%s/%s/userfiles/mcaroi.def.%s",SPECD,SPEC,USER) 

PLOT_MODE|=128
GTERM="x11"

if (!(MCA_PS)) {
   rdef ps_chtoE () \'{ }\'
}
if (!(whatis("mca_user_waitcounts")&2)) {
  rdef mca_user_waitcounts \'\'
  rdef mca_user_start \'\'
}
if (!(whatis("mca_user_key")&2)) {
  rdef mca_user_key \'\'
}

#if (whatis("MCA_LIVE_T")&2) { undef MCA_LIVE_T }
#if (whatis("MCA_REAL_T")&2) { undef MCA_REAL_T }
#if (whatis("MCA_DEAD_T")&2) { undef MCA_DEAD_T }

}'
mca_const_utils_and_rdef

#%MACROS%
#%IMACROS%
#%INTERNALS%
#%B%MCA macro user hook: %BR%%B%
#Users can hook their own macro to those macros, using "cdef()".
#%DL% 
#%DT% mca_user_waitcounts
#%DD% called when looping in "mca_waitcounts", i.e. "mcaacq".
#%DT% mca_user_start
#%DD% called at the end of "mcastart", i.e. just after device startup.
#%DT% mca_user_key
#%DD% called from "mcaacq", while waiting for the acquisition is over, and after keyboard input ("mca_key").
#%XDL% 
#%DEPENDENCIES%
#%UL% those macros use: 
#%LI% the binary %B%psearch%B%, that must be in PATH
#%LI% the macros:
#%UL%
#%LI% 		%B%psearch.mac%B%   for spectrum calibration
#%LI%		%B%cplot.mac%B%	    for cplot
#%LI%		%B%saveload.mac%B%  for data saving	
#%LI%		%B%stlocal.mac%B%   for crying and various things
#%LI%		%B%pseudo.mac%B%    for pseudo counting
#%LI%		%B%menu.mac%B%      for menu handling
#%XUL% that must be loaded together with the %B%mca.mac%B% file.
#%XUL%
#%AUTHOR%
#  MCA.MAC - Marie Claire LAGIER 21/02/94 changed by Elke RAABE 04/01/95%BR%
#%PRE%
#         - last modified  03/96: to use macros functions, shared arrays, GUI.
#         -                01/96: to use mca_par() and saveload.mac.        
#%PRE%
#%TOC%


##############################################################################

def mcatcp '{

if (MCA_DEVOK>0) {
  esrf_io( MCA_DEVNAME, "tcp")
  esrf_io( MCA_DEVNAME, "timeout", 10)
}
}'
  
  
def mcadsstat '{
   local curstat curtime _txt stret

#   mcaiotest
   if (MCA_DEVOK>0) {

       esrf_io(MCA_DEVNAME, "DevMcaGetStatus", curstat)
       esrf_io(MCA_DEVNAME, "DevMcaGetAdcInfo", curtime)
        
       if (ESRF_ERR==0) {
          if (curstat[1]==1) _txt="stopped due to preset live time elapsed"
          else if (curstat[1]==2) \
            _txt="stopped due to preset real time elapsed"
          else if (curstat[1]==3) \
            _txt="stopped due to total preset number of counts reached"
          else if (curstat[1]==4) _txt="stopped by command DevMcaStopAcq"
          else _txt=""
          printf("DEVICE STATUS : %s\n",curstat[0]?"acquiring data":"idle")
          printf("                %s\n",_txt)
          printf("Current ADC             : %d\n", curtime[0])
          printf("First channel           : %d \n", curtime[1])
          printf("Last channel            : %d \n", curtime[2])
          printf("Preset live time        : %.2f \n", curtime[3])
          printf("Preset real time        : %.2f \n", curtime[4])
          printf("Preset number of counts : %d \n", curtime[5])
          printf("Elapsed live time       : %.2f s \n", curtime[6])
          printf("Elapsed real time       : %.2f s \n", curtime[7])
        }
   }
}'

def mcacry '{
  local separat descr 
  global MCA_CRYLAST MCA_OTHER

  separat="\n-------------------------------------------------------\n"

  if ((time()/60-MCA_CRYLAST)<CRYMAXFREQ) {
    printf("A little patience, please - You cried only %d Minutes ago\n",	time()/60-MCA_CRYLAST)
    printf("Retry in %d minutes\n",1+CRYMAXFREQ-(time()/60-MCA_CRYLAST))
    exit
  }

  print "This macro mails a cry for help to Marie Claire."
  MCA_OTHER=getval("others addresses",(MCA_OTHER!="")?MCA_OTHER:"")
  descr=getval("Tell here why you are crying","")
  if (descr == "") {
    if (!yesno("Really send cry for help with no description",0)) {
      exit
    }
  }
  if (!CRYBL) { crysetup }
  if ("0"==MCA_OTHER) MCA_OTHER=""
  unix("echo MCA CRY FOR HELP >/tmp/,xx")
  fprintf("/tmp/,xx","\nfrom %s (%s,%s) on %s at %s\n%suser message:\n%s%s\n",USER,SPEC,TERM,CRYBL,date(),separat,descr,separat)
  
  fprintf ("/tmp/,xx","Tel: %s\n\n",CRYTEL)
  unix("echo hostname: `hostname` >>/tmp/,xx")
  unix("echo id: `id` >>/tmp/,xx")
  on("/tmp/,xx");offt
  mca_dump
  close("/tmp/,xx");ont
  if (unix(sprintf("cat /tmp/,xx | rmail -t %s %s","lagier@esrf.fr",MCA_OTHER))) {
    print "Something went wrong, could not send mail"
  } else {
    print "I will try to get some help for you"
    MCA_CRYLAST=time()/60
  }
}
'

def mca_dump '{
  print "------------------------------------------------------------------"
  print date(),"running",SPEC,"revision",VERSION
  print "------ status mca_par() ------------------"
  mcastat
  print "------ status esrf_io() ------------------"
  mcadsstat 
  print "------ data groups ------------------"
  data_grp(-1,0,0)
  print "------ VARIABLES -----------------"
  print "------ device settings ------------------" 
  print "device server:		",MCA_DEVNAME    
  print "adc active:		",MCA_ADCNO
  print "time mode:		",MCA_TMODE==1?"Live":"Real"
  print "memory group size:	",MCA_MEMGRPSIZE	
  print "memory group active:	",MCA_MEMGRP[0]	
  print "memory groups:		",MCA_MEMGRP[1]	
  print "device status:		",MCA_DEVSTATE[MCA_DEVOK]
  print "hard synchro:		",MCA_SYNCHRO
  print "------ data files ----------------"
  print "saving mode flag:	",MCA_FLAG
  print "Scan file:		",DATAFILE
  print "Scan number:		",SCAN_N
  print "Mca file:		",MCA_PREFIX
  print "Spectrum number:	",MCA_N
  print "Roi file:		",MCA_ROI_DEFAULT_FILE	
  print "data dump format:	",MCA_FMT		
  print "binning factor:        ",MCA_REDUCTION
  print "Loaded spectrum file:	",MCA_LOADF	
  print "its binning factor:	",MCA_FRED[0]
  print "its scan number:	",MCA_FRED[1]
  print "                 req:	",MCA_SNO 
  print "its scan point number: ",MCA_SPNO 
  print "load calib from file:	",MCA_CALFF
  print "------ plot settings ------------------"
  print "plot attributes: 	",MCA_PLOTATTR,MCA_LOG,MCA_LINES,MCA_DOTS,MCA_EBARS
  print "calib X label:		",MCA_CP_XLBL     
  print "calib X unit:		",MCA_CP_XUNT
  print "sleep time:		",MCA_DISP_SEC	
  print "cplot xmin:		",MCA_XMIN
  print "cplot xmax:		",MCA_XMAX
  print "cplot ymin:		",MCA_YMIN
  print "cplot ymax:		",MCA_YMAX
  print "use GUI:		",MCA_GUI
  print "GUI process id:        ",MCA_PID
  print "data group		",MCA_GRP
  print "------ roi ------------------"
  mca_roidisp()
  print "number:		",MCA_ROI_NO
  print "active:		",MCA_ROIACTIVE
  print "------ calibration ------------------"
  print "fit a parameter:	",MCA_EA
  print "fit b parameter:	",MCA_EB
  print "fit c parameter:	",MCA_EC
  print "peaks found number:	",PS_NOPEAKS
  print "fit order:		",PS_NOFIT
  print "------ exec ------------------"
  print "last read chan range:	",MCA_old_channel [0],MCA_old_channel[1]
  print "data group up to date:	",MCA_IN_GROUP
  print "mca auto run off:	",MCA_AROFF
  print "last esrf_err:		",ESRF_ERR 
  print "global channel range:	",MCA_ROI_GCH_MIN,MCA_ROI_GCH_MAX 
  print "calibration:		",MCA_ENERGY 
  print "live time:		",MCA_LIVE_T 
  print "real time:		",MCA_REAL_T
  print "dead time: 		",MCA_DEAD_T,"%"
  print "plot erase flag:       ",MCA_PLOTERASE
  print "data has been saved    ",MCA_SAVED
  print "------ others settings ------------------"
  print "save buffer:		",MCA_SAVEBUFFER
  print "substracts background:	",MCA_BACKSUB
  print "simulation:		",(MCA_DEVOK<-1)
  print "auto string:           ",MCA_AUTO
  print "other receivers:       ",MCA_OTHER
}'




def mcasimon '{
  
global MCA_SIMCUR_T MCA_SIMOLD_T MCA_SIMDATA
global MCA_SIM

MCA_SIM["spec_onsim"] = set_sim(-1)
MCA_SIM["devname"] = MCA_DEVNAME

MCA_DEVNAME = "Simulation of "MCA_DEVNAME

printf("MCA Simulate was %s, is now ON\nGEN ",(MCA_DEVOK<-1)?"on":"off")
onsim; 

MCA_DEVOK=-2 

cdef("user_prepcount","mcastart;","mcasim")
cdef("user_postcount","mcastop ;","mcasim")
cdef("user_countersrun","if (mca_simuwait()) return(1);;","mcasim")
cdef("user_cleanup2","mcastop; ","mcasim")

savmac mca_state "/tmp/mca_simu"
savmac mcastat "/tmp/mca_simu"
savmac mca_times "/tmp/mca_simu"
savmac mcastart "/tmp/mca_simu"
savmac mcaclear "/tmp/mca_simu"
savmac mcastop "/tmp/mca_simu"
savmac mca_waitcounts "/tmp/mca_simu"
savmac mca_read "/tmp/mca_simu"

rdef mcastat \'{
   printf("MCA STATUS : %s\n\n",MCA_DEVSTATE[MCA_DEVOK])
   printf("Current ADC             : %d\n", MCA_ADCNO)
   printf("Group size              : %d \n", MCA_MEMGRPSIZE)
   printf("Group selected          : %d \n", MCA_MEMGRP[1])
   printf("Elapsed live time       : %.2f s \n", MCA_LIVE_T)
   printf("Elapsed real time       : %.2f s \n", MCA_REAL_T)
}\'

def mca_simuwait () \'{
  if (COUNT_TIME<=0) return 0
  if ((time()-MCA_SIMOACQ_T)<=COUNT_TIME) return 1
  return 0
}\'


def mca_state () \'{ }\'

def mca_times () \'{

 global MCA_LIVE_T MCA_REAL_T MCA_DEAD_T

  MCA_LIVE_T=(MCA_DEVOK==-14)?(MCA_SIMCUR_T=time()-MCA_SIMOLD_T):MCA_SIMCUR_T
  MCA_REAL_T=MCA_LIVE_T 
  MCA_DEAD_T=0
}\'

rdef mcaclear \'
  global MCA_NEWDATA
  MCA_DATA[][1] = 0
  MCA_SIMOLD_T=0
  MCA_NEWDATA=0
\'
  
rdef mcastart \'
  #\$*
  global MCA_SIMOLD_T MCA_SIMCUR_T
  if (MCA_DEVOK==-2) { 
    MCA_DEVOK=-14
    MCA_SIMOACQ_T=time()
    if (!MCA_SIMOLD_T) MCA_SIMOLD_T=MCA_SIMOACQ_T
    else MCA_SIMOLD_T = MCA_SIMOACQ_T-MCA_SIMCUR_T
    COUNT_TIME=\$1
  } else {
    print "Cannot start MCA; it is",MCA_DEVSTATE[MCA_DEVOK]
    exit
  }
\'

rdef mcastop \'
  if (MCA_DEVOK==-14) {
    MCA_SIMCUR_T=time()-MCA_SIMOLD_T
  }
  MCA_DEVOK=-2
\'

rdef mca_waitcounts \'{

  local disp key ptime iold
 
  iold=time()
   
  if (COUNT_TIME<=0) ptime=999999
  else ptime=COUNT_TIME
  disp=(MCA_DISP_SEC<ptime)?MCA_DISP_SEC:ptime

  while ((MCA_DEVOK==-14) && (time()-iold)<=ptime) {
    mcatimes 
    key=input(0)
    if (key!="") { mca_key key }
    mca_read chmin chmax
    mca_plotit xmin xmax ymin ymax
    mca_user_waitcounts
    sleep(disp) 
  }
  MCA_DEVOK=-2  
  MCA_SIMCUR_T=time()-MCA_SIMOLD_T
}\'

rdef mca_read \'{
  global MCA_old_channel 
  local channel0 channel1

   channel0=\$1 ; channel1=\$2
   mca_resize_to_roi 0 channel0 channel1

   MCA_FRED[0]=0

   if (MCA_NEWDATA) MCA_DATA[][1] *= MCA_SIMCOEFF
   else {
     MCA_NEWDATA = -1
     MCA_DATA[][1] = MCA_SIMDATA
   }

   MCA_IN_GROUP = 0
##   if (MCA_DATA[MCA_ROI_CH_MAX[0]][0]!=MCA_ROI_CH_MAX[0]) {
#     array_op("fill",MCA_DATA[][0],1)
#   }
   mca_times()
   if ((MCA_old_channel[0]!=channel0)||(MCA_old_channel[1]!=channel1)) {
     MCA_PLOTERASE=1
     MCA_old_channel[0]=channel0  ; MCA_old_channel[1]=channel1
   }
}\'


global MCA_SIMCOEFF
ulong array MCA_SIMDATA [MCA_MEMGRPSIZE][1]

MCA_NEWDATA  = 0
MCA_IN_GROUP = 0
if ($#) {
  loadmcadata "$1" MCA_SIMDATA 0 $2?$2:1 $3?$3:1 0 junk junk junk junk
} else {
  for (i=0;i<MCA_MEMGRPSIZE;i+=256) MCA_SIMDATA [i] = 100
}

MCA_SIMCOEFF = array_op("max",MCA_SIMDATA)
MCA_SIMCOEFF = MCA_SIMCOEFF ? (1 + 1 / MCA_SIMCOEFF) : 1
}'

def mcasimoff '{
 
  printf("MCA Simulate was %s, is now OFF\n",(MCA_DEVOK<-1)?"on":"off")

  if (!MCA_SIM["spec_onsim"]) { printf("GEN ");offsim }

  if (MCA_DEVOK<-1) {
    qdo "/tmp/mca_simu"
    sleep(1)
    cdef("","","mcasim","delete")
    reconfig
  }
}'


## DATE Fri May 30 09:50:42 METDST 1997 REV 5.7;
#%IU%  <roi_number|roi_name> <mode> <first> <last>
#%MDESC% Converts ROI into <first> and <last> range limit.
def mca_getroi '{
local rn
rn = mca_roinum ("$1")

if ($2) {
  $3 = MCA_ROI_EN_MIN [rn]
  $4 = MCA_ROI_EN_MAX [rn]
} else {
  $3 = MCA_ROI_CH_MIN [rn]
  $4 = MCA_ROI_CH_MAX [rn]
}
}'

#%IU%  
#%MDESC% Converts channels into calibrated value all over the defined ROI.
def  mca_roi_Ech '{

  local _roi 
  for (_roi=0;_roi<=MCA_ROI_NO;_roi++) {
    MCA_ROI_EN_MIN[_roi] = mca_calcE(MCA_ROI_CH_MIN[_roi]) 
    MCA_ROI_EN_MAX[_roi] = mca_calcE(MCA_ROI_CH_MAX[_roi])
  }
}'


## DATE Wed Jun  4 08:59:31 METDST 1997 REV 5.8;
## DATE Tue Dec  2 09:22:34 MET 1997 REV 5.10;


#cleanup mcaacq
#        ------
#   mca_read chmin chmax
#   mca_plotit xmin xmax ymin ymax
#   mcatimes 
#   print
#   if (MCA_FLAG&2 && MCA_DEVNAME) {
#     mca_saveacqdata(chmin, chmax, "$0 $*") 
#   }
#
#cleanup ct/scan
#        -------
#  "user_getcounts"
#  "measure2","mca_savescanhead (MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX);"
#  "user_scan_loop","mca_savescandata(MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX)"
#  ou "measure2","mca_saveroihead;","_mca1")
#  "user_handlecounts","mca_savectdata(MCA_ROI_ACH_MIN,MCA_ROI_ACH_MAX)