esrf

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

#%TITLE% ccdbpm.mac
#%NAME% Macro to use the "beam-positioning-monitor" interface of the
# ccd device servers when it is available.
#
#%CATEGORY% Detection, ccd
#
#%DESCRIPTION%
# The following servers support the BPM interface: %BR%
#%UL%
#%LI% meteor2
#%LI% frelon
#%LI% sensican
#%LI%
#%XUL%
#   The Meteor2 device server can be accessed via SPEC as a standart CCD
#   camera. All standart functionality is implemented.
#   Several extra features are available which are accessible via this
#   set of macros as well as ccdmenu.
#   The main features are:
#%UL%
#%LI% Counters on calculated beam parameters (spot center, size, ...)
#%LI% Manual and automatic image intensity calibration
#%LI% Live mode for monitoring
#%LI% Intensity threshold on image
#%XUL%
#
#%EXAMPLE%
#%DL%
#%DT%  ccdbpmsetup device_name min_intensity max_intensity threshold %DD%
#    It will set default calibration parameters for the active BPM CCD camera.
#    You can add this setup into the SPEC setup.
#
#%DT%  ccdbpmshow %DD%
#    Shows all readable parameters for the active BPM camera with their index
#    and actual values. The actual BPM camera set-up is:
#%DL%
#%DD%   [index] : description : value
#%DD%   -----------------------------------------
#%DD%   [0]  : Exposure time             : 0.000000
#%DD%   [1]  : Threshold                 : 0
#%DD%   [9]  : Live mode                 : 0
#%DD%   [30] : Auto calibration mode     : 0
#%DD%   [2]  : Calibrated max. Intensity : 0
#%DD%
#%DD%   [3]  : Full image size X         : 0
#%DD%   [4]  : Full image size Y         : 0
#%DD%
#%DD%   [5]  : ROI start X               : 0
#%DD%   [6]  : ROI start Y               : 0
#%DD%   [7]  : ROI end X                 : 0
#%DD%   [8]  : ROI end Y                 : 0
#%DD%
#%DD%   [10] : Number of beam spots      : 0
#%DD%   [11] : Beam intensity            : 0
#%DD%   [29] : Normalized beam intensity : 0
#%DD%        : (Beam intensity/Exposure time)
#%DD%
#%DD%   [12] : Beam center X             : 0.00
#%DD%   [13] : Beam center Y             : 0.00
#%DD%   [14] : Beam size FWHM X          : 0
#%DD%   [15] : Beam size FWHM Y          : 0
#%DD%   [16] : Beam size full X          : 0
#%DD%   [17] : Beam size full Y          : 0
#%DD%
#%DD%   [18] : Max. pixel value          : 0
#%DD%   [19] : Max. pixel X              : 0
#%DD%   [20] : Max. pixel Y              : 0
#%DD%
#%DD%   [21] : Beam spot start X         : 0
#%DD%   [22] : Beam spot start Y         : 0
#%DD%   [23] : Beam spot end X           : 0
#%DD%   [24] : Beam spot end Y           : 0
#%DD%   [25] : Beam spot FWHM start X    : 0
#%DD%   [26] : Beam spot FWHM start Y    : 0
#%DD%   [27] : Beam spot FWHM end X      : 0
#%DD%   [28] : Beam spot FWHM end Y      : 0
#%DD%
#%DT%  ccdbpm_counter_add inten "d05/meteor2/eh1" beam_intensity 1 %DD%
#    Configures the counter inten with the beam intensity value (index = 11)
#
#%DT%  ccdbpm_counter_add cenx  "d05/meteor2/eh1" y_beam_center 1 %DD%
#    Configures the counter cenx with the beam center Y value (index = 12)
#
#%DT%  ccdbpm_counter_add ceny  "d05/meteor2/eh1" z_beam_center 1 %DD%
#    Configures the counter ceny with the beam center Z value (index = 13)
#
#%DT%  ccdbpmon %DD%
#    Switches on the configured counters during ct and scans.
#
#%DT%  ccdbpmoff %DD%
#    Switches off the configured counters during ct and scans.
#
#
#%XDL%
#
#%LOG%
#
#   $Revision: 1.11 $
#
#   $Log: ccdbpm.mac,v $
#   Revision 1.11  2017/06/26 14:34:12  witsch
#   The array CCD_DS_CONTR was handled inconsistently by the lima macros and
#   the good old ccd and ccdbpm macros. 
#   ccdbpm will recognise both strings LIMA and LIMATACO.
#   Change error messages where necessary.
#
#   Revision 1.10  2011/07/12 13:21:52  petitdem
#   Add Bpm LimaTaco
#
#   Revision 1.9  2011/02/08 12:24:56  claustre
#   Added support for Prosilica camera
#
#   Revision 1.8  2008/02/27 12:58:56  claustre
#   documentation changes
#
#Revision 1.7  2007/09/21 13:25:00  claustre
#fix bug with option 61 of the private config menu, and clean it up
#
#Revision 1.6  2006/09/18 13:30:21  claustre
#meteor_read_beam_center() now return a result even if more than spots are detected.
#
#Revision 1.5  2006/02/07 13:34:02  claustre
#replace tty_cntl() with clscreen()
#
#Revision 1.4  2005/09/28 13:43:21  claustre
#fixed bug + checked CCD_ON.
#
#Revision 1.3  2005/08/23 14:36:11  claustre
#now ccdbpm_counter_add accepts a signalbname as parameter rather than a index number. That's fixed a bug too.
#
#Revision 1.2  2005/07/20 15:35:08  claustre
#added meteor_undef macro
#
#%END%
#

#%UU%
#%MDESC% has to be called at once to undef the obsolate meteor macros.
def meteor_undef '{
  if (whatis("meteorshow") != 0) {
    cdef("","","meteor_ct_","delete")
    undef meteor_autocal_off
    undef meteor_autocal_on
    undef meteor_calibrate_intensity
    undef meteor_counter_add
    undef meteor_counter_remove
    undef meteor_ct_add
    undef meteor_ct_read
    undef meteor_ct_remove
    undef meteor_getsignals
    undef meteor_getthreshold
    undef meteor_is_ready
    undef meteor_is_running
    undef meteor_live_off
    undef meteor_live_on
    undef meteor_liveoff
    undef meteor_liveon
    undef meteor_pixelsize
    undef meteor_private_setup
    undef meteor_private_show
    undef meteor_read_beam_center
    undef meteor_read_intensity
    undef meteor_setthreshold
    undef meteorcalibrate
    undef meteoroff
    undef meteoron
    undef meteorsetup
    undef meteorshow
  }
}'

global CCD_BPM_LIST
global  BPM_CT_LIST BPM_SIG_LIST

list_test BPM_CT_LIST
list_test CCD_BPM_LIST

#%IU%
#%MDESC%
#
def ccdbpm_private_show '
  if (_ccdbpm_check(_ccd_u)) {
    ccdbpm_initpar(CCD_DS[_ccd_u],_ccd_u)
        printf("\n   2 -  Define BPM Counters. . . . . . . . . :")
    tty_cntl("md")
    printf("< %s >\n",(list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"on"))? "YES": "NO")
    tty_cntl("me")
    if (list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"on")) {
      printf("           %8.8s:   %16.16s:   %8.8s (counter=signal/factor):\n", "Counter", "Signal", "Factor")
      local _counters _ct_num _index _mne _factor _ccdds
      _counters = list_n (BPM_CT_LIST)
      for (i=1; i <= _counters; i++) {
        _mne = list_item (BPM_CT_LIST, i)
        _ccdds =  list_getpar (BPM_CT_LIST, _mne, "ccd_ds")
        if (_ccdds != CCD_DS[_ccd_u]) continue
        _index = list_getpar (BPM_CT_LIST, _mne, "index")
        _factor = list_getpar (BPM_CT_LIST, _mne, "factor")
        printf ("           %8.8s    %16.16s    %8.8s\n", \
        _mne,list_item(BPM_SIG_LIST, _index), _factor)
      }
    }
        if (CCD_DS_CONTR[_ccd_u]=="METEOR"){
          meteor_initpar(CCD_DS[_ccd_u])

        printf("   3 -  Meteor Setup . . . . . . . . . . . . :")
        printf("\n            Live Mode                   -> ")
        tty_cntl("md")
        printf("%s\n",(list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"live"))? "ON": "OFF")
        tty_cntl("me")
        printf("            Calibration                 -> ")
        tty_cntl("md")
        printf("%s\n",(list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"auto"))? "Auto": "Manual")
        tty_cntl("me")
        printf("            Threshold                   -> ")
        tty_cntl("md")
        printf("%d\n", list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"thres"))
        tty_cntl("me")
        printf("            Calibration min. Intensity  -> ")
        tty_cntl("md")
        printf("%d\n", list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"min"))
        tty_cntl("me")
        printf("            Calibration max. Intensity  -> ")
        tty_cntl("md")
        printf("%d\n", list_getpar(CCD_BPM_LIST,CCD_DS[_ccd_u],"max"))
        tty_cntl("me")
        }
    }


'

#%IU%
#%MDESC%
def _ccdbpm_check(u) '{
  local controller
  controller = image_par(u,"controller")
      return (controller == "CCD_PC" && \
            (CCD_DS_CONTR[u]=="METEOR" || \
             CCD_DS_CONTR[u]=="SENSI" || \
             CCD_DS_CONTR[u]=="PROSILICA" || \
             CCD_DS_CONTR[u]=="FRELON" || \
             CCD_DS_CONTR[u]=="LIMA" || \
             CCD_DS_CONTR[u]=="LIMATACO"))? 1: 0
}'

#%IU%
#%MDESC%
#
def ccdbpm_private_setup '
  local  __ccd_u cam
  if ($#)
    __ccd_u=$1
  else
    __ccd_u=CCD_U
  if (_ccdbpm_check(__ccd_u)) {
    ccdbpm_initpar(CCD_DS[__ccd_u],__ccd_u)

    if (option == 3 && CCD_DS_CONTR[__ccd_u]=="METEOR") { # special setup for the Meteor2 ccd server
            meteor_initpar(CCD_DS[__ccd_u])
      (yesno("            Start live",list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"live")))? meteor_live_on(__ccd_u): meteor_live_off(__ccd_u)

      (yesno("            Automatic calibration",list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"auto")))? meteor_autocal_on(): meteor_autocal_off()

      list_setpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"thres",getval ("            Threshold        :", list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"thres")))
      meteor_setthreshold(list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"thres"))
      list_setpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"min",getval ("            Min. Intensity   :", list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"min")))
      list_setpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"max",getval ("            Max. Intensity   :", list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"max")))
    }
    else if (option == 2) {
      if (yesno("            Enable BPM Counters during ct/scans",list_getpar(CCD_BPM_LIST,CCD_DS[__ccd_u],"on"))){
        _ccdbpm_on(__ccd_u)
        local _opt
        for(;;) {
          printf("\t")
          tty_cntl("md"); printf("a"); tty_cntl("me")
          printf ("dd / ")
          tty_cntl("md"); printf("d"); tty_cntl("me")
          printf("elete counter or ")
          tty_cntl("md"); printf("q"); tty_cntl("me")
          printf ("uit:")
          _opt = getval("(a/d/q)", "q")
          if (_opt == "q") break
          else if (_opt == "a") {
            local _cnt _pos _factor _ccdds

            if(CCD_DS[__ccd_u]=="?") {
              printf ("CCD unit %d is unusable, you cannot add new counters\n",__ccd_u)
              input("\tHit \"Enter\" to continue: ")
              continue
            }

            _cnt = getval ("\tCounter mnemonic",0)
            if (cnt_num(_cnt) ==-1) {
              print "\tUndefined counter mnemonic !"
              input("\tHit \"Enter\" to continue: ")
              continue
            }
            _ccdds = list_getpar(BPM_CT_LIST,_cnt,"ccd_ds")
            if (list_item (BPM_CT_LIST, _cnt)!=-1 && CCD_DS[__ccd_u]!=_ccdds) {
               tty_cntl("md")
               printf ("\tCounter \"%s\" is already used by the CCD device \"%s\" !\n",_cnt,_ccdds)
                tty_cntl("me")
               if (!yesno("\tDo you want to redefine it",1)) continue
            }
            printf("\tSignal number :\n\t\t")
            tty_cntl("us");tty_cntl("md")
            printf ("0");tty_cntl("me");tty_cntl("ue")
            printf(" y_beam_center   ")
            tty_cntl("us");tty_cntl("md")
            printf ("1");tty_cntl("me");tty_cntl("ue")
            printf(" z_beam_center\n\t\t")
            tty_cntl("us");tty_cntl("md")
            printf ("2");tty_cntl("me");tty_cntl("ue")
            printf(" beam_intensity  ")
            tty_cntl("us");tty_cntl("md")
            printf ("3");tty_cntl("me");tty_cntl("ue")
            printf(" More...\n")
            _pos = getval ("",0)
            if (_pos!=3) {
              if (_pos == 0) _pos = list_item(BPM_SIG_LIST,"y_beam_center")
              else if (_pos == 1) _pos = list_item(BPM_SIG_LIST,"z_beam_center")
              else if (_pos == 2) _pos = list_item(BPM_SIG_LIST,"beam_intensity")
            } else _pos = _ccdbpm_signal_menu()
            _factor = getval ("            Factor (counter=signal/factor)",1)

            ccdbpm_ct_add(_cnt, CCD_DS[__ccd_u], _pos, _factor)
          }
          else if (_opt == "d") {
            local _counters _mne i _ccdds _cnt
            _counters = list_n (BPM_CT_LIST)
            printf("\tDefined counter(s) = ")
            for (i=1; i <= _counters; i++) {
              _mne = list_item (BPM_CT_LIST, i)
              _ccdds = list_getpar(BPM_CT_LIST, _mne,"ccd_ds")
              if (_ccdds != CCD_DS[__ccd_u]) continue
              printf("%s ",_mne)
            }
            print ""
            _cnt = getval ("\tCounter mnemonic",_mne)
            ccdbpm_ct_remove(_cnt)
          }
        }
      }
      else {
         _ccdbpm_off(__ccd_u)
      }
    }
  }
'

#%UU% [ccd unit]
#%MDESC%
# Switches on the configured counters during ct and scans.
#
def ccdbpmon '
  local __ccd_u
  if ($#) __ccd_u = $1
  else __ccd_u=CCD_U
  _ccdbpm_on(__ccd_u)
'

cdef ("user_getcounts", "ccdbpm_ct_read\n", "ccdbpm_ct_", 0x20)

def _ccdbpm_on (u)'{
  local str1 str2
  if (!_ccdbpm_check(u)) {
    print "Cannot switch on this CCD unit !!"
    print "CCD unit "u" is not of type METEOR/SENSI/FRELON/PROSILICA/LIMA."
  } else
        if (!_ccdbpm_listchk(CCD_DS[u]))
            print "Run \"ccdmenu\" at once before using ccdbpm macros !"
        else
        list_setpar(CCD_BPM_LIST,CCD_DS[u],"on",1)
}'

#%UU% [ccd unit]
#%MDESC%
# Disables the configured counters during ct and scans.
#
def ccdbpmoff '
  local __ccd_u
  if ($#) __ccd_u = $1
  else __ccd_u=CCD_U
    _ccdbpm_off(__ccd_u)
'

def _ccdbpm_off (u) '{
  local _mne
  local _ct_num
  local _counters str1
  if (!_ccdbpm_check(u)) {
    print "Cannot switch on this CCD unit !!"
    print "CCD unit "u" is not of type METEOR/SENSI/FRELON/PROSILICA/LIMA."
  } else {
        if (!_ccdbpm_listchk(CCD_DS[u])) {
            print "Run \"ccdmenu\" at once before using ccdbpm macros !"
        }else {
        list_setpar(CCD_BPM_LIST,CCD_DS[u],"on",0)

        _counters = list_n (BPM_CT_LIST)
        for (i=1; i <= _counters; i++) {
        _ct_num = cnt_num (_mne = list_item (BPM_CT_LIST, i))
        S[_ct_num] = 0
        }
        }
  }
}'

#%UU%
#%MDESC%
#    Shows all readable parameters for the camera with their index
#     and actual values.
#

def ccdbpmshow '{
  local _val idx n __ccd_u

  if ($#) __ccd_u = $1
  else __ccd_u = CCD_U
  _val = ccdbpm_getsignals(CCD_DS[__ccd_u])
  if (_val[0]==-1) {
    print ESRF_ERR_MSG
    exit
  }
  n = list_n(BPM_SIG_LIST)
  printf ("The current BPM camera %d set-up is:\n\n",__ccd_u)
  tty_cntl("md")
  printf ("[%16.16s] %5s: %31.31s : %s\n","Name","Index","Description","Value")
  tty_cntl("me")
  for (idx=1; idx!=n+1;idx++) {
    str=sprintf("[%16.16s] %5d: %31.31s : %s\n", \
    list_item(BPM_SIG_LIST,idx), idx-1, \
    list_getpar(BPM_SIG_LIST,idx,"descr"),\
    list_getpar(BPM_SIG_LIST,idx,"format"))
    printf(str, _val[idx-1])
  }
}'

#%IU%
#%MDESC%
#
def _ccdbpm_signal_menu ()'{
  local idx n choice

  n = list_n(BPM_SIG_LIST)
  while (1) {

    clscreen()
    tty_move(5,0,"\[us]\[md]BPM camera Signal list:\[me]\[ue]")

    for (idx=1; idx!=n+3;idx+=3) {
      tty_move(1,2+idx/3,sprintf("\[us]\[md]%d\[me]\[ue]:",idx))
      tty_move(6,2+idx/3,sprintf("%s",list_item(BPM_SIG_LIST,idx)))
      if (idx+2 <=n) {
        tty_move(26,2+idx/3,sprintf("\[us]\[md]%d\[me]\[ue]:",idx+1))
        tty_move(31,2+idx/3,sprintf("%s",list_item(BPM_SIG_LIST,idx+1)))
        if (idx+3 <=n) {
          tty_move(52,2+idx/3,sprintf("\[us]\[md]%d\[me]\[ue]:",idx+2))
          tty_move(57,2+idx/3,sprintf("%s",list_item(BPM_SIG_LIST,idx+2)))
        }
      }
    }
    printf("\n\nChoose a signal number: "); choice = input()
    if (list_item (BPM_SIG_LIST, choice)!=-1) break
  }

  return choice
}'

#%IU%
#%MDESC%
#
def _ccdbpm_init_siglist () '{
  if (list_check (BPM_SIG_LIST,"exposure_time") == -1) {
    list_init BPM_SIG_LIST

    list_add(BPM_SIG_LIST,"exposure_time")
    list_setpar(BPM_SIG_LIST, "exposure_time", "descr", "Exposure time (sec.)")
    list_setpar(BPM_SIG_LIST, "exposure_time", "format", "%4.5f")

    list_add(BPM_SIG_LIST, "threshold")
    list_setpar(BPM_SIG_LIST, "threshold", "descr", "Pixel Threshold")
    list_setpar(BPM_SIG_LIST, "threshold", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "calib_intensity")
    list_setpar(BPM_SIG_LIST, "calib_intensity", "descr", "Calibrated max. Intensity")
    list_setpar(BPM_SIG_LIST, "calib_intensity", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_image_size")
    list_setpar(BPM_SIG_LIST, "y_image_size", "descr", "Full image size in Y")
    list_setpar(BPM_SIG_LIST, "y_image_size", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_image_size")
    list_setpar(BPM_SIG_LIST, "z_image_size", "descr", "Full image size in Z")
    list_setpar(BPM_SIG_LIST, "z_image_size", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_roi_start")
    list_setpar(BPM_SIG_LIST, "y_roi_start", "descr", "ROI start in Y")
    list_setpar(BPM_SIG_LIST, "y_roi_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_roi_start")
    list_setpar(BPM_SIG_LIST, "z_roi_start", "descr", "ROI start in Z")
    list_setpar(BPM_SIG_LIST, "z_roi_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_roi_end")
    list_setpar(BPM_SIG_LIST, "y_roi_end", "descr", "ROI end in Y")
    list_setpar(BPM_SIG_LIST, "y_roi_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_roi_end")
    list_setpar(BPM_SIG_LIST, "z_roi_end", "descr", "Roi end in Z")
    list_setpar(BPM_SIG_LIST, "z_roi_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "is_live")
    list_setpar(BPM_SIG_LIST, "is_live", "descr", "Live mode (1-on/0-off)")
    list_setpar(BPM_SIG_LIST, "is_live", "format", "%4d")

    list_add(BPM_SIG_LIST, "num_of_beam_spots")
    list_setpar(BPM_SIG_LIST, "num_of_beam_spots", "descr", "Number of beam spots")
    list_setpar(BPM_SIG_LIST, "num_of_beam_spots", "format", "%4d")

    list_add(BPM_SIG_LIST, "beam_intensity")
    list_setpar(BPM_SIG_LIST, "beam_intensity", "descr", "Beam intensity")
    list_setpar(BPM_SIG_LIST, "beam_intensity", "format", "%g")

    list_add(BPM_SIG_LIST, "y_beam_center")
    list_setpar(BPM_SIG_LIST, "y_beam_center", "descr", "Beam center in Y")
    list_setpar(BPM_SIG_LIST, "y_beam_center", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_beam_center")
    list_setpar(BPM_SIG_LIST, "z_beam_center", "descr", "Beam cernter  in Z")
    list_setpar(BPM_SIG_LIST, "z_beam_center", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_size_fwhm")
    list_setpar(BPM_SIG_LIST, "y_size_fwhm", "descr", "Beam size FWHM in Y")
    list_setpar(BPM_SIG_LIST, "y_size_fwhm", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_size_fwhm")
    list_setpar(BPM_SIG_LIST, "z_size_fwhm", "descr", "Beam size FWHM in Z")
    list_setpar(BPM_SIG_LIST, "z_size_fwhm", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_size")
    list_setpar(BPM_SIG_LIST, "y_size", "descr", "Beam size full in Y")
    list_setpar(BPM_SIG_LIST, "y_size", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_size")
    list_setpar(BPM_SIG_LIST, "z_size", "descr", "Beam size full in Z")
    list_setpar(BPM_SIG_LIST, "z_size", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "max_pixel_value")
    list_setpar(BPM_SIG_LIST, "max_pixel_value", "descr", "Maxe pixel value")
    list_setpar(BPM_SIG_LIST, "max_pixel_value", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_max_pixel")
    list_setpar(BPM_SIG_LIST, "y_max_pixel", "descr", "Max pixel in Y")
    list_setpar(BPM_SIG_LIST, "y_max_pixel", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_max_pixel")
    list_setpar(BPM_SIG_LIST, "z_max_pixel", "descr", "Max pixel in Z")
    list_setpar(BPM_SIG_LIST, "z_max_pixel", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_spot_start")
    list_setpar(BPM_SIG_LIST, "y_spot_start", "descr", "Beam spot start in Y")
    list_setpar(BPM_SIG_LIST, "y_spot_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_spot_start")
    list_setpar(BPM_SIG_LIST, "z_spot_start", "descr", "Beam spot start in Z")
    list_setpar(BPM_SIG_LIST, "z_spot_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_spot_end")
    list_setpar(BPM_SIG_LIST, "y_spot_end", "descr", "Beam spot end in Y")
    list_setpar(BPM_SIG_LIST, "y_spot_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_spot_end")
    list_setpar(BPM_SIG_LIST, "z_spot_end", "descr", "Beam spot end in Z")
    list_setpar(BPM_SIG_LIST, "z_spot_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_fwhm_start")
    list_setpar(BPM_SIG_LIST, "y_fwhm_start", "descr", "Beam spot FWHM start in Y")
    list_setpar(BPM_SIG_LIST, "y_fwhm_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_fwhm_start")
    list_setpar(BPM_SIG_LIST, "z_fwhm_start", "descr", "Beam spot FWHM start in Z")
    list_setpar(BPM_SIG_LIST, "z_fwhm_start", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "y_fwhm_end")
    list_setpar(BPM_SIG_LIST, "y_fwhm_end", "descr", "Beam spot FWHM end in Y")
    list_setpar(BPM_SIG_LIST, "y_fwhm_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "z_fwhm_end")
    list_setpar(BPM_SIG_LIST, "z_fwhm_end", "descr", "Beam spot FWHM end in Z")
    list_setpar(BPM_SIG_LIST, "z_fwhm_end", "format", "%4.0f")

    list_add(BPM_SIG_LIST, "norm_beam_intensity")
    list_setpar(BPM_SIG_LIST, "norm_beam_intensity", "descr", "Normalized beam intensity (I/T)")
    list_setpar(BPM_SIG_LIST, "norm_beam_intensity", "format", "%g")

    list_add(BPM_SIG_LIST, "is_auto_calibration")
    list_setpar(BPM_SIG_LIST, "is_auto_calibration", "descr", "Auto calibration (0-off/1-on)")
    list_setpar(BPM_SIG_LIST, "is_auto_calibration", "format", "%4d")
  }
}'


_ccdbpm_init_siglist()


#%UU% [ counter_mnemonic ccd_ds signal_name factor ]
#%MDESC%
# Adds the counter with the given mnemonic which reads the ccd_ds device value
# specified by the signal_name signal . The signal name can be found by executing "ccdbpmshow"!
#
def ccdbpm_counter_add '{
  local factor

  if (($# == 3) || ($# == 4)) {
    factor = ($# == 4) ? $4 : 1
        #check the signal exist
        if (list_check(BPM_SIG_LIST,"$3") == 0) {
          printf ("ccdbpm_counter_add:  %s is not a valid signal name", "$3")
            exit
      }
    ccdbpm_ct_add  ("$1", "$2", "$3" , factor)
  } else {
    printf("    Usage: ");
    tty_cntl("md");print "ccdbpm_counter_add  counter_mnemonic ccd_ds signal_index signal_factor";tty_cntl("me")
    exit
  }
}'

#%UU% [ counter_mnemonic ]
#%MDESC%
# Removes the counter with the given mnemonic.
#
def ccdbpm_counter_remove '{

  if ($# == 1) {
    ccdbpm_ct_remove  ("$1")
  } else {
    printf("    Usage: ");
    tty_cntl("md");print "ccdbpm_counter_remove counter_mnemonic";tty_cntl("me")
    exit
  }
}'

#%IU% (counter_mnemonic ccd_ds signal_index signal_factor)
#%MDESC%
# Adds the counter with the given mnemonic which reads the ccd_ds camera value
# specified by the index. The index can be found by executing "ccdbpmshow"!
#
def ccdbpm_ct_add (counter_mnemonic, ccd_ds, signal_index, signal_factor) '{
  list_add (BPM_CT_LIST, counter_mnemonic)
  list_setpar(BPM_CT_LIST, counter_mnemonic, "ccd_ds", ccd_ds)
  list_setpar(BPM_CT_LIST, counter_mnemonic, "index", signal_index)
  list_setpar(BPM_CT_LIST, counter_mnemonic, "factor", signal_factor)
}'

#%IU% (counter_mnemonic)
#%MDESC%
# Removes the counter with the given mnemonic.
#
def ccdbpm_ct_remove (counter_mnemonic) '{
  local _ct_num

  list_remove(BPM_CT_LIST, counter_mnemonic)

  _ct_num = cnt_num (counter_mnemonic)
  S[_ct_num] = 0
}'

float array ccdbpm_sig_arr[10][31]
#%IU%
#%MDESC%
# Reads all counters specified for the camera if the reading was eanabled
# by "ccdbpmon"!
#
def ccdbpm_ct_read '{
  global ESRF_ERR ESRF_ERR_MSG
  local _mne _ndev _item
  local _index _factor
  local _ct_num i
  local _counters _factor _ccdds _met_ds
  local devs_stat[] devs_num[] _ccd_u

  _ndev = list_n(CCD_BPM_LIST)
  for(_item=1;_item!=_ndev+1;_item++) {
    local ds
    ds =  list_item(CCD_BPM_LIST,_item)
    devs_num[ds]=_item
    _ccd_u = list_getpar(CCD_BPM_LIST,_item, "ccd_u")
    #read the sigvalues if ccd and ccdpbm are both on !
    if (list_getpar(CCD_BPM_LIST,_item, "on") && CCD_ON[_ccd_u]) {
      devs_stat[ds]=1
      ESRF_ERR=-1
      esrf_io (ds, "DevReadSigValues", ccdbpm_sig_arr[_item])
      # the frelon ds returns an error if no beam is detected !
      # so make sure counters get 0 as value
      if (ESRF_ERR!=0 && ESRF_ERR!=202899469) print ESRF_ERR_MSG
      else if (ESRF_ERR==202899469) {devs_stat[ds]=0}
    } else
      devs_stat[ds]=0
  }
  _counters = list_n (BPM_CT_LIST)
  for (i=1; i <= _counters; i++) {
    _ct_num = cnt_num (_mne = list_item (BPM_CT_LIST, i))
    _ccdds = list_getpar (BPM_CT_LIST, _mne, "ccd_ds")
    if (devs_stat[_ccdds]==0) { S[_ct_num]=0;continue}
    _item = list_getpar (BPM_CT_LIST, _mne, "index")
    _index = list_check(BPM_SIG_LIST,_item)
    _factor = list_getpar (BPM_CT_LIST, _mne, "factor")

    if ((_factor == -1) || (_factor == 0))  _factor=1
    S[_ct_num] = ccdbpm_sig_arr[devs_num[_ccdds]][_index-1]/_factor
  }

}'

#%IU%
#%MDESC%
#
def ccdbpm_is_running(dev) '{
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]
  #state == DevCcdTaking
  return (esrf_io (_dev,"DevState") == 202899458)
}'

#%IU%
#%MDESC%
#
def ccdbpm_is_ready(dev) '{
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]
  return (esrf_io (_dev,"DevState") == 202899457)
}'

#%IU%
#%MDESC%
#
def ccdbpm_getsignals(dev) '{
  local _param _dev
  global ESRF_ERR ESRF_ERR_MSG
  _param[0]=0
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]
  ESRF_ERR=-1
  ESRF_ERR_MSG=""
  esrf_io (_dev, "DevReadSigValues", _param)
  # the frelon ds returns an error if no beam is detected !
  if (ESRF_ERR==202899469) _param[0]=-1
  return (_param)
}'

#%IU%
#%MDESC%
# Initialise the local parameters with the current camera setting.
def ccdbpm_initpar(dev,unit) '{
  local _param _dev  _thr

  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]
  if (_dev =="?") return
  list_add(CCD_BPM_LIST,_dev)
  if (!_ccdbpm_listchk(dev)) {
    list_setpar(CCD_BPM_LIST,_dev,"on",0)
  }
  list_setpar(CCD_BPM_LIST,_dev,"ccd_u",unit)
}'

#%IU%
#%MDESC%
# Check the list array has been initialised for the dev device.
def _ccdbpm_listchk (dev) '{
    return (list_getpar(CCD_BPM_LIST,dev,"on")==-1)? 0:1
}'
#################
#
# Here start Meteor special macros
#
#################

# for backword compatiblity with the meteor.mac macro set
#
def meteor_counter_add 'ccdbpm_counter_add $*'
def meteor_counter_remove 'ccdbpm_counter_remove $*'
def meteoron 'ccdbpmon $*'
def meteoroff 'ccdbpmoff $*'

#%UU% <device-name> <minimum_intensity> <maximum_intensity> <threshold>
#%MDESC%
# Setup default parameters of the Meteor2 camera.One can add this setup into the SPEC setup to save
# the default setting of the camera calibration.
#
def meteorsetup '
  local param
  if ($#!=4) {
    print "usage: $0 <device-name> <minimum_intensity> <maximum_intensity> <threshold>"
  } else {
    #first get current setting from the camera
    meteor_initpar("$1")
    list_setpar(CCD_BPM_LIST,"$1","min",$2)
    list_setpar(CCD_BPM_LIST,"$1","max", $3)
    list_setpar(CCD_BPM_LIST,"$1","thres", $4)
    #then apply the new values
    meteor_setthreshold($4,"$1")

  }
'

#%IU%
#%MDESC%
# Initialise the local parameters with the current camera setting.
def meteor_initpar(dev) '{
  local _param _dev  _thr

  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]
  if (_dev =="?") return
  _param =  ccdbpm_getsignals(_dev)
  list_setpar(CCD_BPM_LIST,_dev,"live",_param[9])
  list_setpar(CCD_BPM_LIST,_dev,"auto",_param[30])
  list_setpar(CCD_BPM_LIST,_dev,"thres",_thr)
  if (!_ccdbpm_listchk(dev))  list_setpar(CCD_BPM_LIST,_dev,"min",240)
  if (!_ccdbpm_listchk(dev)) list_setpar(CCD_BPM_LIST,_dev,"max",250)
}'

#%UU% [ccd-unit]
#%MDESC%
# Start the camera live mode
# The "Take an image during ct/scan" feature of ccdmenu is disabled because
# it is incompatible with the live mode.
#

def meteor_liveon '
  local __ccd_u
  if(!$#) __ccd_u = CCD_U
  else __ccd_U = $1
  meteor_live_on(__ccd_u)
'
#%IU%
#%MDESC%
#
def meteor_live_on (u) '{
  esrf_io(CCD_DS[u], "DevCcdLive", 1)
  list_setpar(CCD_BPM_LIST,CCD_DS[u],"live",1)
  if (CCD_ON[u]) {
    ccdoff u
    tty_cntl("md")
    printf ("            \"Take image during ct/scans\" is now disabled\n")
    tty_cntl("me")
  }
}'

#%UU% [ccd-unit]
#%MDESC%
# Stop the camera live mode
#
def meteor_liveoff '
  local __ccd_u
  if(!$#) __ccd_u = CCD_U
  else __ccd_U = $1
  meteor_live_off(__ccd_u)
'

#%IU%
#%MDESC%
#
def meteor_live_off (u) '{
  esrf_io(CCD_DS[u], "DevCcdLive", 0)
  list_setpar(CCD_BPM_LIST,CCD_DS[u],"live",0)

  while( ccdbpm_is_running(CCD_DS[u]) ) {
    sleep(.1)
  }
}'

#%UU%  ()
#%MDESC%
# Switch on the intensity calibration for every image aquired.
# The camera calibrates the image intensity using the specified range
# before taking an image by changing the exposure time.
# see ccdbpmsetup.
#
def meteor_autocal_on () '{
  local argin
  argin[0] = 1
  argin[1] = list_getpar(CCD_BPM_LIST,CCD_DS[CCD_U],"min")
  argin[2] = list_getpar(CCD_BPM_LIST,CCD_DS[CCD_U],"max")
  esrf_io (CCD_DS[CCD_U], "DevCalibration", argin)
  list_setpar(CCD_BPM_LIST,CCD_DS[CCD_U],"auto",1)
}'

#%UU% ()
#%MDESC%
# Switch off the intensity calibration for every image aquired.
#
def meteor_autocal_off ()'{
  local argin
  argin[0] = 0
  esrf_io (CCD_DS[CCD_U], "DevCalibration", argin)
  list_setpar(CCD_BPM_LIST,CCD_DS[CCD_U],"auto",0)
}'


#%UU%
#%MDESC%
# start calibration of the Meteor2 CCD camera exposure time.
# Apply the min and max intensity set by ccdbpmsetup macro.
#
def meteorcalibrate '
  local min max
  min = list_getpar(CCD_BPM_LIST,CCD_DS[CCD_U],"min")
  max = list_getpar(CCD_BPM_LIST,CCD_DS[CCD_U],"max")
  meteor_calibrate_intensity min max
'

#%UU% minimum_intensity maximum_intensity
#%MDESC%
# start calibration of the Meteor2 CCD camera exposure time then return
# the calibrated maximum intensity and the calibrated exposure time.
#
def meteor_calibrate_intensity '{
  local ret_values

  if ($# != 2) {
    printf ("Usage: calibrate_intensity minimum_intensity maximum_intensity\n")
    exit
  }

  ret_values = _meteor_calibrate_intensity ($1, $2)

  printf ("Maximum Intensity = %3.0f\n", ret_values[0])
  printf ("Exposure Time     = %f\n",    ret_values[1])
}'

#%IU% (minimum_intensity, maximum_intensity)
#%MDESC%
# start calibration of the Meteor2 CCD camera exposure time.
#
def _meteor_calibrate_intensity (min, max, dev) '{
  local inp
  local state
  local calib_values
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]

  calib_values[0] = -1.0
  calib_values[1] = -1.0
  inp[0] = min
  inp[1] = max

  esrf_io (CCD_DS[CCD_U],"DevSetCalib", inp)

  # state == DevCcdTaking
  while ( ccdbpm_is_running() ) {
    sleep(0.2)
  }

  # state == DevCcdReady
  if (ccdbpm_is_ready()) {
    esrf_io(CCD_DS[CCD_U], "DevGetCalib", calib_values)
  } else {
    p "Calibration did not finish correctly!"
    p esrf_io(CCD_DS[CCD_U], "DevCcdGetLstErrMsg")
  }

  return (calib_values)
}'

#%IU% (threshold)
#%MDESC%
# set the threshold.
#
def meteor_setthreshold (threshold, dev) '{
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]

  esrf_io(_dev, "DevCcdSetThreshold", threshold)
}'

#%IU%
#%MDESC%
# Return the threshold.
#
def meteor_getthreshold (dev) '{
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]

  return esrf_io(_dev, "DevCcdGetThreshold")
}'


#%IU% ()
#%MDESC%
# return Y and Z beam position + Y Fwhm and Z Fwhm
#
def meteor_read_beam_center (dev) '{
  local state
  local center
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]

  center[0] = -1.0
  center[1] = -1.0

  param_values[0] = -1

  esrf_io(_dev, "DevReadValues", param_values)

# at least one spot is enough to trust in the server bpm
  if ( param_values[0] != 0 ) {
    center[0] = param_values[2]
    center[1] = param_values[3]
    center[2] = param_values[4]
    center[3] = param_values[5]
  }

  return (center)
}'


#%IU%
#%MDESC%
#
def meteor_read_intensity (dev) '{
  local param_values
  local _dev
  if (dev) _dev = dev
  else _dev = CCD_DS[CCD_U]

  intensity = -1.0

  param_values[0] = -1

  esrf_io(_dev, "DevReadValues", param_values)

  if ( param_values[0] == 1 ) {
    intensity = param_values[1]
  }

  return (intensity)
}'


#%UU% <Y pixelsize> <Z pixelsize>
#%MDESC%
# store the pixel size in Y and Z into the database through the device server
def meteor_pixelsize '{
  local data[] controller
  data[0]=1; data[1]=1
  if ($# != 0 && $# != 2) {
    print "Usage: $0 <Y pixelsize> <Z pixelsize>"
    print "       um/pixel as unit."
    exit
  }
    controller = image_par(CCD_U,"controller")

  if (controller != "CCD_PC" || CCD_DS_CONTR[CCD_U]!="METEOR") {
      beep; sleep(.2); beep
        print "\nSorry but the Active CCD is not a valid Meteor CCD camera !"
    print "Please, set active a Meteor CCD camera within the \"ccdmenu\" macro."
        exit
    }
  esrf_io(CCD_DS[CCD_U],"DevRestore", data)
  if(!$#) {
    printf("Actual pixel-size is (Y,Z): (%.2f, %.2f) um/pixel\n", 1000*data[0],1000*data[1])
    data[0] = getval("Y pixel-size (um/pixel)", 1000*data[0])
    data[1] = getval("Z pixel-size (um/pixel)", 1000*data[1])
  } else {
    data[0] = $1; data[1] = $2
  }
  if (data[0]==0 || data[1]==0){
    print "Pixelsize must be not null, exit !!"
    exit
  }
    data[0]/=1000; data[1]/=1000
  esrf_io(CCD_DS[CCD_U],"DevStore", data)
}'

#%MACROS%
#%IMACROS%
#%AUTHOR% BLISS (L.Claustre) / ESRF 2004
#%TOC%