esrf

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

#%TITLE% PMB.MAC
#%NAME%
#%B%PMB.MAC%B% - Pneumatic Mirror Bender set of macros
#%DESCRIPTION% The Pneumatic Mirror Bender is used to bend a mirror, using
#a proportional pressure control valve to set the radius of the curvature.
#%SETUP% The pressure switch (PS) is automatically open if the pressure in the
#system is less than 8bars - Relay (Wago 750-402). There is a pneumatic valve
#(PV1) for additional security - Relay (Wago 750-502). Three way valve (TW -
#DAC :Wago 750-554) or pressure controller (PACE5000) sets the pressure.
#We may read a pneumatic valve (PV2) which closes automatically if the
#pressure is more that 2.2 Bars - Relay (Wago 750-502). The gauge (PT - ADC:
#Wago 750-492) or pressure controller (PACE5000) reads the pressure. Security
#read channel, if existing, - ADC (Wago 750-492) confirms the threeway valve
#output.
#%EXAMPLE%
#To define the PMB macro motor, you must define it as follows:
#%B%MAC_MOT%B%, 100000 %B%steps/mm%B%, %B%limits%B% -0.1 to 2.1,
#%B%readback%B%%B%slop%B% 10000, %B%hardware%B%%B%read%B%%B%mode%B% AL+NQ.
#%PRE%
#Example of configuration:
#MOTORS	DEVICE	ADDR	<>MODE	NUM	<>TYPE
#YES    pmb		  	1	Macro Motors
#Example of the spec config file:
#	If wago setup:
#		MOTPAR:dactype = wago
#		MOTPAR:dacdev = id29/wcid29d/wc
#		MOTPAR:dacname = setp
#		MOTPAR:dacstep = 0.25
#    		MOTPAR:adctype = wago
#    		MOTPAR:adcdev = id29/wcid29d/wc
#    		MOTPAR:adcname = readp
#    		MOTPAR:adcconv = 5
#    		MOTPAR:valtype = wago
#    		MOTPAR:valdev = id29/wcid29d/wc
#    		MOTPAR:valname = mvopen
#		MOTPAR:pvtype = wago
#		MOTPAR:pvdev = id29/wcid29d/wc
#		MOTPAR:pvroot = mirv

#%B%*name%B% is the wago channel logical name (as in the resources),
#%B%*dev%B% is the appropriate device server name,
#%B%dacstep%B% is the ramping step for setting the pressure,
#%B%adcch%B% is the channel to be read on the ADC.
#%B%adcconv%B% is the factor to conver the ADC current to pressure (pres=curr/adcconv),
#%END%

#%IU% (mne,type,unit,module,chan)
#%MDESC% The command is executed when spec does (re)config, where %mne% could be .. (if %B%type%B% controller) or the motor number, if motor.
def pmb_config(mne,type,unit,module,chan) '{
global PMB_old
global PMB_DEBUG HDBdacsetval

  if (PMB_DEBUG != 0) {
    tty_cntl("md");printf ("pmb_config %s\n", type);tty_cntl("me")
  }

  if (type == "ctrl")
    return

  printf ("%s\n", mne)
  if (motor_par(mne,"device_id") != "pmb")
    return ".error."

  if (pmb_getprops(mne) == -1)
    return ".error."
}'

#%IU% (mot)
#%MDESC% Get and set different properties at the initialisation if the
#motor %B%mot%B%.
def pmb_getprops(mot) '{
local type dev nam ret dd lcmd

  if (PMB_DEBUG != 0)
    printf ("pmb_getprops %s\n", mot)

  #set pressure (DAC)
  type = motor_par(mot,"dactype")
  dev = motor_par(mot,"dacdev")
  if (type == "wago") {
    nam = motor_par(mot,"dacname")
    ret = esrf_io(dev,"DevName2Key",nam)
    if (ret == -1)
      return(-1)
    motor_par(mot,"dackey",ret,"add")
    motor_par(mot,"adca0",4,"add")
    motor_par(mot,"adca1",8,"add")
  } else if (type == "pace")  {
    split(dev, dd,":")
    lcmd = sprintf ("ping %s -c 1", dd[0])
    if (unix(lcmd) != 0) {
      eprintf ("Controller %s not responding, disabling the motors %s\n", \
		dd[0], mot)
      return(-1)
    } else {
      motor_par(mot,"adca0",0,"add")
      motor_par(mot,"adca1",1,"add")
    }
  }

  if (PMB_DEBUG != 0) {
    tty_cntl("md");printf ("pmb_getprops \n");tty_cntl("me")
  }

  #read pressure (ADC)
  type = motor_par(mot,"adctype")
  if (type == "wago") {
    dev = motor_par(mot,"adcdev")
    nam = motor_par(mot,"adcname")
    ret = esrf_io(dev,"DevName2Key",nam)
    if (ret == -1)
      return(-1)
    motor_par(mot,"adckey",ret,"add")
  }

  #open if compressed air (Relay)
  if (type = motor_par(mot,"valtype")) {
    if (type == "wago") {
      dev = motor_par(mot,"valdev")
      nam = motor_par(mot,"valname")
      ret = esrf_io(dev,"DevName2Key",nam)
      if (ret == -1)
        return(-1)
      motor_par(mot,"valkey",ret,"add")
    }
  }

  #two security valves (Relay)
  if (type = motor_par(mot,"pvtype")) {
    if (type == "wago") {
      dev = motor_par(mot,"pvdev")
      nam = motor_par(mot,"pvroot")
      for (i=1; i<=2; i++) {
        ret = esrf_io (dev,"DevName2Key", sprintf("%s%d",nam,i))
        if (ret == -1)
          return(-1)
        motor_par(mot,sprintf("pv%dkey",i),ret,"add")
      }   
    }
  }
  return(0)
}'

#%IU% (mot, key, p1, p2)
#%MDESC%Executed by spec, when reading or moving (depends on the %B%key%B%)
#the motor %B%mot%B%
def pmb_cmd(mot, key, p1, p2) '{
  global PMB_new[] PMB_old[]

  if (PMB_DEBUG != 0) {
    tty_cntl("md");printf ("pmb_cmd %s (%s)\n", mot,key);tty_cntl("me")
    printf("p1=%f, old pmb_m value=%f", p1, PMB_old[mot])
  }

  if (key=="magnitude") {
    PMB_new[mot]=PMB_old[mot]+p1
    if (PMB_DEBUG)
       printf("setting new motor pos. to be %f", PMB_new[mot])
  } else if ((key == "start_one") || (key == "set_position")) {  
    if (PMB_DEBUG)
       printf("motor should move to %f", PMB_new[mot])

    if (_pmbset(mot, PMB_new[mot]) == -1)
      return(-1)

    PMB_old[mot] = PMB_new[mot]
  } else if (key == "position") {
    pos = _pmbread(mot)
    return(pos)
  }
}'

#%IU% (mot)
#%MDESC% Return the bender pressure - read the ADC and convert the value
#in pressure [Bar].
def _pmbread(mot) '{
local conv

  conv = _adcread(mot)
  if (motor_par(mot,"adctype") != "pace")
    conv = 0.15625*(conv) - 0.625
  PMB_old[mot] = conv
  return(conv)
}'

#%IU% (mot)
#%MDESC% Return the reading on the ADC [mA] if wago, pressure [Bar] if PACE .
def _adcread(mot) '{
local type dev ch key
local adc_curr[] ret

  type = motor_par(mot,"adctype")
  dev = motor_par(mot, "adcdev")

  if (type == "wago") {
    key =  motor_par(mot, "adckey")
    ret = esrf_io(dev, "DevReadNoCachePhys", key, adc_cur)
    if (ret != -1) {
      ret = adc_cur[0]
      if (PMB_DEBUG != 0) {
        printf ("pmb_cmd: device %s - pos %f\n", dev, ret)
      }
    }
    return(ret)
  } else if (type == "pace") {
    ret = _pace_readpres(dev)
    return(ret)
  } else {
    #other types
    ret = A[mot]
    return(ret)
  }
}'

#%IU% (mot, press)
#%MDESC% Set the bender to a pressure %B%pres%B% [Bar]. Do it in steps.
def _pmbset(mot,pres) '{
local cur_pres new_pres sec_step
local val a0 a1

  if (PMB_DEBUG)
    printf("------------>setting the pressure to %f\n", pres)
  if ((pres < 0) || (pres > 2))
    return (-1)

  if (motor_par(mot,"valtype")) {
    if (_valstate(mot) != 1)
      return(-1)
  }

  cur_pres = _pmbread(mot)
  if (cur_pres < 0)
    return (-1)
  if (cur_pres < 0)
    cur_pres = 0

  if (fabs(pres - cur_pres) < 0.01)
    return (0)

  sec_step = motor_par(mot,"dacstep")
  a0 = motor_par(mot,"adca0")
  a1 = motor_par(mot,"adca1")
  if (pres > cur_pres) {
    new_pres = pres - cur_pres
  } else {
    sec_step *= -1.
    new_pres = cur_pres - pres
  }
  while (1) {
    if (new_pres <= fabs(sec_step)) {
        val = a0 + a1 * pres
      if (_dacset(mot, val) < 0)
        return (-1)
      sleep(0.5)
      if (_pmbread(mot) < 0)
        return (-1)
      return(0)
    } else {
      cur_pres += sec_step
      val = a0 + a1 * pres
      if (_dacset(mot, val) < 0)
        return (-1)
      sleep(3)
      cur_pres = _pmbread(mot)
      if (cur_pres < 0)
        return(-1)
      if (pres == cur_pres)
        return(0)
      if (pres > cur_pres)
        new_pres = pres - cur_pres
      else
	new_pres = cur_pres - pres 
    }
    sleep(0.5)
  }
}'

#%IU% (mot, val)
#%MDESC% Send the DAC the %B%val%B% . In case of wago (3 way valve) the
#value is in mA, Bar in case of PACE.
def _dacset(mot,val) '{
global HDBdacsetval
local type dev ret vals

  type = motor_par(mot,"dactype")
  if (type == "wago") {
    dev = motor_par(mot,"dacdev")
    key =  motor_par(mot, "dackey")
    vals[0] = key
    vals[1] = 0
    vals[2] = val
    ret = esrf_io(dev,"DevWritePhys", vals)
  } else if (type == "pace") {
    dev = motor_par(mot,"dacdev")
    ret = _pace_setpres(dev,val)
  } else {
    #other types
    ret = A[mot]
  }
  # set the new value to trigger a read in the hdb database
  if (ret != -1)
    ret = val
    HDBdacsetval = val
  if (PMB_DEBUG != 0) {
    printf ("pmb_cmd: device %s - ret %g\n", dev, ret)
  }
  return(ret)
}'

#%IU% (mot)
#%MDESC% Return the state of the pressure swith (PS valve). Open PV1 and PV2.
def _valstate(mot) '{
local ret

  ret = _valread(mot)
  if (ret == 0) {
    _pvopen(mot)
  }
  return(ret)
}'

#%IU% (mot)
#%MDESC% Read the state of the PS valve. Return 0 if open, 1 if closed,
#-1 if error.
def _valread(mot) '{
local type ret val

  type = motor_par(mot,"valtype")
  if (type == "wago") {
    #temporarily change PS to PV1
    #dev = motor_par(mot,"valdev")
    #key =  motor_par(mot, "valkey")
    dev = motor_par(mot,"pvdev")
    key = motor_par(mot, "pv1key")
    ret = esrf_io(dev,"DevReadNoCachePhys", key,val)
    if (ret != -1)
      ret = val[0]
    return(ret)
  }
  return(1)
}'

def _pvopen(mot) '{
local type ret dev i val

  ret = 0
  type = motor_par(mot,"pvtype")

  if (type == "wago") {
    val[1] = 0
    val[2] = 1
    dev =  motor_par(mot,"pvdev")
    valr =  motor_par(mot,"pvroot")
    for (i=1; i<=2; i++) {
      val[0] =  motor_par(mot, sprintf("pv%dkey",i))
      if (esrf_io(dev,"DevWriteDigi", val) < 0)
        ret = -1
    }
    return(ret)
  }
  return(0)
}'

def _pvclose(mot) '{
local type ret dev i val

  ret = 0
  type = motor_par(mot,"pvtype")

  if (type == "wago") {
    val[1] = 0
    val[2] = 0
    dev =  motor_par(mot,"pvdev")
    valr =  motor_par(mot,"pvroot")
    for (i=1; i<=2; i++) {
      val[0] =  motor_par(mot, sprintf("pv%dkey",i))
      if (esrf_io(dev,"DevWriteDigi", val) < 0)
        ret = -1
    }
    return(ret)
  }
  return(0)
}'

#%IU% (mot, pres)
#%MDESC% Set the pressure %B%pres%B%. Wait until value set. Return the value
#read from the PACE.
def _pace_setpres(dev,pres) '{
local rasw asw val

  #turn controller on
  sock_put(dev,":OUTP 1\r")
  sock_put(dev, sprintf(":SOUR %f\r",pres))
  sock_put(dev,":SENS:PRES?\r")
  rasw = sock_get(dev,"\r")
  split(rasw, asw)
  val = asw[1]*1
  while(fabs(val - pres) > 0.002) {
    val = _pace_readpres(dev)
  }
  #turn controller off
  ##sock_put(dev,":OUTP 0\r")
  return(val)
}'

#%IU% (mot)
#%MDESC% Return the pressure from the PACE.
def _pace_readpres(dev) '{
local rasw asw val

  #read pressure
  sock_put(dev,":SENS:PRES?\r")
  rasw = sock_get(dev,"\r")
  split(rasw, asw)
  val = asw[1]*1
  return(val)

}'

#%MACROS%
#%IMACROS%
#%AUTHOR% A.Beteva/BLISS%BR%
#$Revision: 2.0 $, $Date: 2013/03/20 17:00:46 $
#%TOC%
#%END%
#%LOG%
#$Log: pmb_mm.mac,v $
#Revision 2.0  2013/03/20 17:00:46  beteva
#Removed the VME part. Added the control of the valves to be optional.
#Adde possibility to read/set the pressure only with a pressure controller.
#
#Revision 1.3  2011/11/02 14:28:58  beteva
#changes to cope with the new wago module
#changes to use the pace5000 pressure generator instead of a 3way valve
#
#Revision 1.2  2008/07/29 11:21:24  guijarro
#version with all changes from ID29 + fix in logic in valread macro
#
#Revision 1.1  2006/06/21 14:24:43  beteva
#Initial revision
#