esrf

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

#%TITLE% millitron196.mac
#%NAME% 
#   Millitron read through Wago or ICV196 
#%CATEGORY% Positioning
#
#%DESCRIPTION% 
#    The millitron sensor can be read by cabling 16 digital inputs on
#    a corresponding I/O card.  This macro set allows to read a millitron
#    as a counter in spec by using either an ICV196 or a wago module.
#%BR% %BR%
#    The %B%millitron%B% output is a DB25 connector where pins are 
#    defined as follow:
#%PRE%
#         pin 1 :
#         pin 2 :
#         pin 3   : overflow
#         pin 4   : x1000
#         pin 5   : ready for measurement = 1
#         pin 6   : ready for measurement = 0
#         pin 7   : digital point 0.01
#         pin 8   : digital point 0.1
#         pin 9   : 0v DC
#         pin 10  : 0v DC
#         pin 11  : 
#         pin 12  : sign 0->+ 1->-
#         pin 13  : x800
#         pin 14  : x400
#         pin 15  : x100
#         pin 16  : x80
#         pin 17  : x40
#         pin 18  : x20
#         pin 19  : x10
#         pin 20  : x8
#         pin 21  : x8
#         pin 22  : x4
#         pin 23  : x2
#         pin 24  : x1
#         pin 25  : 
#%PRE%
#%SETUP% 
#%BR% %BR%
#    %B%WAGO%B% : 
#%BR% %BR%
#    The macro counter method is used. 
#%UL%
#    %LI%The macro set %B%wagocore%B% has to be loaded in spec. 
#    %LI%Use spec config editor to setup a macro counter controller with 
#    prefix %B%millitron%B% . 
#    %LI% Set the ADDR field to the wago controller name.  Ex.: wcid51d.   
#    %LI% Set the NUM field to a value holding as many counters
#    as you will defined
#    %LI% In the scaler configuration window add individiual counters
#    on that controller (type MAC_CNT) and assign corresponding unit number. 
#    The channel number is arbitrary but it must be unique and be coherent
#    with the NUM value of the controller
#    %LI% Still in that window, set the cursor on top of the line of your
#    counter. Hit the key "p" to add an extra parameter
#    to the counter. This parameter must have its name set to "key" and
#    the value corresponds to the wago key associated with the 16 
#    digital input values.
#    %LI% Finally you can add an optional parameter with name "average" and
#    value set to "1". The reading will then be averaged during counting.
#    The default is set to 0 (= no average).
#%XUL%
#%BR% %BR%
#    %B%ICV196%B% : 
#%BR% %BR%
#    The old pseudo counter method is used:
#%BR% %BR%
#    Three counters must be defined in spec
#    to get the readings.  Use the macro %B%millitronsetup%B% (see usage
#    below) to configure the card and assign the counters
#
#    When using an ICV196 this macro set supposes that the millitron is 
#    cabled using 1 connector (J1, J2 or J3) by device. Each connector 
#    is clabed as follows :
#%PRE%
#         bit 0  (mod 32) : x1
#         bit 1  (mod 32) : x2
#         bit 2  (mod 32) : x4
#         bit 3  (mod 32) : x8
#         bit 4  (mod 32) : x10
#         bit 5  (mod 32) : x20
#         bit 6  (mod 32) : x40
#         bit 7  (mod 32) : x80
#         bit 8  (mod 32) : x100
#         bit 9  (mod 32) : x200
#         bit 10 (mod 32) : x400
#         bit 11 (mod 32) : x800
#         bit 12 (mod 32) : x1000
#         bit 13 (mod 32) : val x 0.1
#         bit 14 (mod 32) : val x 0.01
#         bit 15 (mod 32) : sign
#         bit 16 (mod 32) : ready
#         bit 17 (mod 32) : overflow
#%PRE%
#   In the case of ICV196:
#   up to 3 millitron devices can be read. There is on cable per device 
#   connected to a Icv196 connector.
#   We associate a pseudo counter per each Icv196 connector even if there no 
#   millitron device connected. 
#
#%END% 

#%UU% wagokey
#%MDESC%  Reads a millitron on a wago system. Prints the value on the screen
def milwagoread  '{
   print _milwagoread("$1")
}'

#%IU%
#%MDESC%  Called by spec at config time. 
def millitron_config(mne, type) '{
     if (mne == "..") {
        print "Configuring millitron on wago " millitron_ADDR
        _dowagosetup ( millitron_ADDR )
     }
}'

#%IU%
#%MDESC%  Called by spec to read values
def millitron_cmd(mne, cmd, p1,p2) '{

   # This macro will read as many times as possible during
   # the counting time. But only the last one will be used.
   # Not so efficient but users wanted the last value and not
   # an average for example. This could added as an extra parameter

   local key

   if (mne == "..") return

   key = counter_par( mne, "key")

   if (cmd == "start_one") {
      if  ( counter_par(mne, "average") == 1 ) {
          counter_par(mne, "accumulator",0, "add")
          counter_par(mne, "nbcnts",     0, "add")
      }
   }

   if (cmd == "counts") {
      local _cnts accum nbcnts
      _cnts = _milwagoread(key)
      if  ( counter_par(mne, "average") == 1 ) {
          accum  = counter_par(mne, "accumulator") + _cnts
          nbcnts = counter_par(mne, "nbcnts") + 1
          accum  = counter_par(mne, "accumulator",accum)
          nbcnts = counter_par(mne, "nbcnts",nbcnts)
          S[mne] = accum / nbcnts
      } else {   # no average
          S[mne] = _milwagoread(key)
      }
   }

}'

#%IU%
#%MDESC% Perform the actual reading on wago and convert values
def _milwagoread(key) '{

    local i j n value
    short array milwagovals[16]

    # read

    wago_readch( key, milwagovals )


    # algorithm to convert to user readings
    value = 0
    n     = 0

    for (j = 0; j < 3; j++) {
       for (i = 0; i < 4; i++) {
          value += milwagovals[i + n] * pow(2,i) * exp10(j)
       }
       n += 4
    }

    value += 1000 * milwagovals[12]

    if (milwagovals[13] == 1) {
       value *= -1
    }

    if (milwagovals[14] == 0) {
       value *= 0.01
    } else if (milwagovals[15] == 0) {
       value *= 0.1
    }

    return(value)
}'

#%IU% 
#%MDESC%
def millitron_globals  '{
  global ESRF_ERR, ESRF_ERR_MSG  
  global MIL_DEV        ;# Icv196 device name
  global MIL_MNE[]      ;# Counters names
  global MIL_FACT[]     ;# The weight of each bit (see above).
  global MILLITRON_ON    ;# As usual
  global MIL_DBG        ;# As usual
}'


#%UU% 0 | 1
#%MDESC% Activates / Inactivates debuggin (ICV196)
def millidbg  '{
  millitron_globals
  MIL_DBG=($1?1:0) 
}'


#%UU% icv196_device_name cntj1 cntj2 cntj3
#%MDESC% setup macro for ICV196
def millitronsetup  '{
  millitron_globals 
  if($# != 4) {
    printf("millitronsetup usage: millitronsetup icv196_device_name cntj1 cntj2 cntj3\n")
    millitronoff
    exit
  } 
  MIL_FACT[0] = 1     ; MIL_FACT[1] = 2   ; MIL_FACT[2] =  4    ; MIL_FACT[3] =  8
  MIL_FACT[4] = 10    ; MIL_FACT[5] = 20  ; MIL_FACT[6] =  40   ; MIL_FACT[7] =  80
  MIL_FACT[8] = 100   ; MIL_FACT[9] = 200 ; MIL_FACT[10] = 400  ; MIL_FACT[11] = 800
  MIL_FACT[12] = 1000  
  
  MIL_DEV     = "$1"
  MIL_MNE[0]  = "$2" ; MIL_MNE[1]  = "$3" ; MIL_MNE[2]  = "$4"
  cdef("user_getcounts", "_millitronread()\n", "millitron")
}'

#%UU% 
#%MDESC% Activates pseudo counters (for ICV196)
def millitronon  '{
  millitron_globals 
  local ii, mil_num
  for (ii=0 ; ii<3 ; ii++) {
    mil_num = cnt_num(MIL_MNE[ii])
    counter_par(mil_num, "disable", 0)
  } 
  MILLITRON_ON = 1 
}'

#%UU% 
#%MDESC% Inactivates pseudo counters (for ICV196)
def millitronoff  '{
  millitron_globals
  local ii, mil_num
  for (ii=0 ; ii<3 ; ii++) {
    mil_num = cnt_num(MIL_MNE[ii])
    counter_par(mil_num, "disable", 1)
  }
  MILLITRON_ON = 0
}'

#%IU%()
#%MDESC%  For ICV196 / Reads  J1, J2 and J3 and set the corresponding 
#  counters (32 channels per connector)
#  If en error occurs (not_ready or overflow) the corresponding counter 
#  is set to -88888
#  If the millittron is disabled (cmd millitronoff) the 3 counters are 
#  set to -99999
#  The command DevMultipleChannelRead returns 12 values of 8 bits 
#  (12*8=96 channels).
def _millitronread() '{
  millitron_globals
  local ret, ii, mil_num[]
  local short array rel_tab[11]  
  if(MIL_DBG) {p "Enter _millitronread()\n"}
  if(!MILLITRON_ON) {
    for (ii=0 ; ii<3 ; ii++) {
      if(cnt_num(MIL_MNE[ii]) != -1) {S[cnt_num(MIL_MNE[ii])] = -99999}
    }
    if(MIL_DBG) {p "millitronoff activated"}
    return(0)
  }
  ESRF_ERR=-1
  ret = esrf_io(MIL_DEV, "DevMultipleChannelRead", rel_tab)
  if(ESRF_ERR!=0) {
    printf("Error reading Icv196: %s\n",ESRF_ERR_MSG)
    return(0)
  }
  for (ii=0 ; ii<3 ; ii++) {
    if ((mil_num[ii] = cnt_num(MIL_MNE[ii])) != -1) {
      if (_millitron_ready(rel_tab, ii)) {
        if (!_millitron_overflow(rel_tab, ii)) {
          S[mil_num[ii]] = _millitron_getval(rel_tab, ii)
        } else {
          printf("millitron %s overflow \n",MIL_MNE[ii])
          S[mil_num[ii]] = -88888
        }
      } else {
        print "millitron ",MIL_MNE[ii]," not ready"
        S[mil_num[ii]] = -88888
      }
    }
  }  
  
}'

#%IU%(tabval,conn)
#%MDESC% Returns the decimal value of one millitron (one connector) (ICV196 only)
def _millitron_getval(tabval,conn) '{
  millitron_globals
  local ii val
  if(MIL_DBG) {printf("Enter  _millitron_getval(tabval,%d)\n",conn)}
  for (ii=0,val=0 ; ii<16 ; ii++) {
    if (ii<13) {
      val = val + _millitron_getbit(tabval, ii, conn) * MIL_FACT[ii]
    } else if ((ii == 13) && (!_millitron_getbit(tabval, ii, conn))) {
      val = val * 0.1
    } else if ((ii == 14) && (!_millitron_getbit(tabval, ii, conn))) {
      val = val * 0.01
    } else if ((ii == 15) && (!_millitron_getbit(tabval, ii, conn))) {
      val = -val
    }
  }
  if(MIL_DBG) {printf("val=%d\n",val)}
  return(val)  
}'


#%IU%(tabval,conn)
#%MDESC%
def _millitron_ready(tabval,conn) '{
  millitron_globals
  return(_millitron_getbit(tabval, 16, conn))
}'

#%IU%(tabval,conn)
#%MDESC%
def _millitron_overflow(tabval,conn) '{
  millitron_globals
  return(!_millitron_getbit(tabval, 17, conn))
}'

#%IU%(tabval,bit,conn)
#%MDESC% returns the value of one bit 
def _millitron_getbit(tabval,bit,conn) '{
  millitron_globals
  local shift ind
  shift = bit%8
  ind   = int(bit/8) + 4*conn
  return(~(tabval[ind]>>shift) & 0x01)  
}'


#%UU% Connector_number [0-2]
#%MDESC% (ICV196 only)
def millprint  '{
  millitron_globals
  local ret, str
  local short array rel_tab[11]
  ESRF_ERR=-1
  ret = esrf_io(MIL_DEV, "DevMultipleChannelRead", rel_tab)
  if(ESRF_ERR!=0) {
    printf("Error reading Icv196: %s\n",ESRF_ERR_MSG)
    exit
  }  
  printf("   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   29   20   21   22   23 \n")
  printf("   1    2    4    8   10   20   40   80  100  200  400  800 1000  0.1 0.01 sign READ  OVR \n")
  printf("------------------------------------------------------------------------------------------------------------------------\n")
  for (str="",ii=0 ; ii<24 ; ii++) {
    str = sprintf("%s%4d ", str, _millitron_getbit(rel_tab, ii))
  }
  printf("%s\n", str)
  printf("val = %g\n", _millitron_getval(rel_tab, $1))  
}'


#%MACROS% 
#%IMACROS% 
#%AUTHOR% Original: G. Berruyer . Commented and generalized: G. Pepellin / V.Rey for the wago version
#%TOC%