esrf

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

#%TITLE% MAXEENC.MAC
#%NAME% 
# Using encoder readings from a maxe server as pseudo counters 
#
#%CATEGORY% Positioning
#
#%DESCRIPTION%
#  Encoders which are configured can be used as counters. This allows
#  you to do scans to measure encoder ratio ( specially useful if
#  it is not linear). The encoder readings will also be written to the 
#  scanfile to allow off-line analysis. %BR%.
#  The encoder will be read during counting and the result will be
#  the average of all these readings.
#  You have to define a counter with controller set to NONE and call
#  encsetup . If you do not want to use the encoder pseudo counter any
#  more, just delete it with specs configuration editor.
#  
#%EXAMPLE%
#%DL%
#%DT% encsetup inch "ID18/spec_maxe/1" 1 %DD%
#    This sets up the inch pseudo counter to read from Maxe device
#    ID18/spec_maxe/1 , channel 1. This is usually be done in the
#    idxxxsetup.mac 
#%XDL%        
#%SETUP%
#  The resource files of the Maxe server have to be configured for
#  encoders.
#%END%
#

# encsetup [counter-mne device channel] [counter-mne device channel] ...
#%UU%  [counter-mne device channel] [counter-mne device channel] ...
#%MDESC%

#    This macro defines the pseudo counters. The counter will read
#    the encoder value from mxe device <device> channel <channel>.
def encsetup '
{
  global ENC_DEV ENC_CHA ENC_NO ENC_MNE ENC_AVER ENC_NOREADS
  local _args

  encoff

  if ($#) {
    ENC_NO = split("$*",_args) 	/3
    for (ii=0;ii<ENC_NO;ii++) {
      ENC_MNE[ii] = _args[ii*3]
      ENC_DEV[ii] = _args[ii*3+1] 
      ENC_CHA[ii] = _args[ii*3+2]
    }
  } else {
    ENC_NO = getval("Number of encoders to define as counters",ENC_NO)
    for (jj=0;jj<ENC_NO;jj++) {
      ENC_MNE[jj] = getval(sprintf("Counter mnemonic for %d. encoder",\
	jj+1),ENC_MNE[jj])
      ENC_DEV[jj] = getval(sprintf("Maxe device name for %d. encoder",\
	jj+1),ENC_DEV[jj])
      ENC_CHA[jj] = getval(sprintf("Maxe channel for %d. encoder",\
	jj+1),ENC_CHA[jj])
    }
  }

  encon
  setup_tail("enc")

}'

#%UU% counter-mne value
#%MDESC%
# Resets the (incremental) encoder counted in %B%counter-mne%B% to %B%value%B%. 
# Similar to %B%set\ motor-mne\ value%B%.
#
def encset '{
  local mne found old stepsize new

  mne = "$1"
  for (found=0,i = 0; i < ENC_NO; i++) {
    if (ENC_MNE[i] == mne && cnt_num(ENC_MNE[i]) != -1) {
      stepsize = counter_par(cnt_num(ENC_MNE[i]),"scale") 
      old = esrf_io(ENC_DEV[i],"DevReadEncPos",ENC_CHA[i]) * stepsize
      esrf_io(ENC_DEV[i],"DevLoadEncPos",ENC_CHA[i], ($2) / stepsize)  
      new = esrf_io(ENC_DEV[i],"DevReadEncPos",ENC_CHA[i]) * stepsize
      comment "Encoder \'%s\' reset from to %g to %g" "mne,old,new"
      found = 1
    }
  }
  if (!found) 
    print "Counter $1 is not a valid Maxe encoder mnemonic!"
}'


def encon '{
  local jj i
  global ENC_STATE 
  # define the pseudo counters
  for (jj=0;jj<ENC_NO;jj++) {
    local pstring 
    pstring = sprintf ("%s enc_precount none enc_getcounts none none %s %s",\
	ENC_MNE[jj],ENC_DEV[jj],ENC_CHA[jj])
    cpseudosdef pstring
    cdef("user_pollcounts",sprintf("enc_getcounts %s %s %d ;"\
       ,ENC_MNE[jj],ENC_DEV[jj],ENC_CHA[jj]),ENC_MNE[jj],0x02)
  }
  for (i=0; i < ENC_NO; i++) {
    if (cnt_num(ENC_MNE[i]) == -1) 
      printf("You have to define counter with mnemonic %s in the config file\n",\
        ENC_MNE[i])
  } 
  ENCSTATE = 1
}'

def encoff '{
  local jj
  global ENCSTATE
  for (jj=0;jj<ENC_NO;jj++) {
    cdef("","",ENC_MNE[jj],"delete")
  } 
  ENCSTATE = 0
}'

def encunsetup '{
  local i
  for (i=0; i < ENC_NO; i++) {
    if (cnt_num(ENC_MNE[i]) != -1) 
      printf("You can delete counter with mnemonic %s from the config file\n",\
        ENC_MNE[i])
  }
  encoff
}'

def encbody (how) '{
  if (how == 1) {
    if (ENCSTATE) {
      encoff
    } else {
      encon
    }
  } else if (how == 2) {
    encsetup
  }
  return ENCSTATE ? "In use" : "Not used"
}'

#%UU%  [enc-mne sigma-mne first-mne last-mne]
#%MDESC%
#    Switches on test mode where not only the average value for an
#    encoder reading is calculated but also the sigma. 
#    (sigma = sqrt(sum(y-avarage)**2/ N)).
#    sigma should not depend on the number of readings.
#    The encoder mne specifies the encoder for which the sigma
#    calculation has to be done. The sigma-mne is pseudo counter
#    where the result has to be written to. (Can be empty - in this case
#    there will be no sigma calculation but the values will still be stored
#    in the ENC_TESTGRP
def encteston '
  global ENC_TESTMNE ENC_TESTSIGMA ENC_TESTGRP ENC_TESTT ENC_TESTL ENC_TESTF
  ENC_TESTGRP = 62
  if ($#) { 
    ENC_TESTMNE = $1
    ENC_TESTSIGMA = $2
    ENC_TESTF = $3
    ENC_TESTL = $4

  } else {
    local defa
    if ((ENC_TESTMNE <= 0) || ((defa= cnt_mne(ENC_TESTMNE)) == -1)) 
      defa = ""	 
    ENC_TESTMNE = cnt_num(getval("Enc counter mne to test",defa))
    if ((ENC_TESTSIGMA <= 0) || ((defa= cnt_mne(ENC_TESTSIGMA)) == -1)) 
      defa = ""	 
    ENC_TESTSIGMA = cnt_num(getval("Counter mne for sigma",defa))
    if ((ENC_TESTF <= 0) || ((defa= cnt_mne(ENC_TESTF)) == -1)) 
      defa = ""	 
    ENC_TESTF = cnt_num(getval("Counter mne for first reading",defa))
    if ((ENC_TESTL <= 0) || ((defa= cnt_mne(ENC_TESTL)) == -1)) 
      defa = ""	 
    ENC_TESTL = cnt_num(getval("Counter mne for last reading",defa))
  }
'

#%UU%
#%MDESC% Switches off test mode 
def enctestoff '
   data_grp(ENC_TESTGRP,0,0)
   unglobal ENC_TESTMNE ENC_TESTSIGMA ENC_TESTGRP ENC_TESTT ENC_TESTF ENC_TESTL
'

#%IU%  <counter-mne> <device> <channel>
#%MDESC%
#    Resets internal registers
def enc_precount ' 
ENC_AVER[$1] = 0 ; ENC_NOREADS[$1]=0

# From here on for sigma tests 
if (ENC_TESTMNE == $1) {
  data_grp(ENC_TESTGRP,10000,2)
  ENC_TESTT = time()
}
'

#%IU%  <counter-mne> <device> <channel>
#%MDESC%
#    The actual reading routine
def enc_getcounts '
{
  local val
  ESRF_ERR = -1
  val = esrf_io("$2","DevReadEncPos",$3)
  if (!ESRF_ERR) {
    ENC_AVER[$1] += val
    ENC_NOREADS[$1]++;
  }

  S[$1] = counter_par($1,"scale")*\
 	ENC_AVER[$1] / ((ENC_NOREADS[$1]==0)? 1 : ENC_NOREADS[$1])

  # From here on for sigma tests 
  if (!ESRF_ERR && (ENC_TESTMNE == $1)) {
    local av
    data_nput(ENC_TESTGRP,ENC_NOREADS[$1]-1,time()-ENC_TESTT,val)
    if ((ENC_TESTSIGMA > 0) && ENC_NOREADS[$1]) {
      av = ENC_AVER[$1] / ENC_NOREADS[$1]
      data_uop (ENC_TESTGRP,1,ENC_TESTGRP,1,"sub",av)
      S[ENC_TESTSIGMA] = sqrt (data_anal(ENC_TESTGRP,0,0,1,1,"sumsq") / \
		ENC_NOREADS[$1])
      data_uop (ENC_TESTGRP,1,ENC_TESTGRP,1,"add",av)
      if (ENC_TESTF>0)
        S[ENC_TESTF] = data_get(ENC_TESTGRP,0,1)
      if (ENC_TESTL>0)
        S[ENC_TESTL] = val

    }
  }

}
'

#%MACROS%
#%IMACROS%
#%ATTENTION%
#%UL%
# %LI% There is no delete macro for the moment 
# %LI% Reading is done for each encoder separately. These macros have not
#  been written with fast execution speed in mind and should therefore
#  only be used during testing.
# %XUL%
#%DEPENDENCIES%
# The file maxeenc.mac has to be read in       !done by: startup script
#    (this file needs: cpseudo.mac stchanges.mac)
#%AUTHOR%
#  MAXEENC.MAC  - JK 3.94
#%TOC%