esrf

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

#%TITLE% ICV196.MAC 
#%NAME%
#  Relays configuration and control with icv196 card
#%CATEGORY% Generic I/O
#%DESCRIPTION%
# The Icv196 DIO board holds 96 channels; no 0 up to 63 are reserved for monitoring purposes (inputs), and the rest are dedicated to level or pulse control (outputs). One device server serves one channel.%BR%
#Those macros aim to interface SPEC to the icv196 boards in a way that all the channels used can be grouped into what we call %B%systems%B%, and be considered as actuators of that system they belong to. 
#%EXAMPLE%
#%DL%
#%DT%diosetup reset
#%DD% initialises the whole relays configuration.
#%DT%diosetup system diodes
#%DD% initialises the system called "diodes"
#%DT%diosetup actuator d1 0 id/diodes/1 0 0 0 0.1
#%DD% attaches the relay served by device id/diodes/1, named "d1" as 1st actuator of diodes system.
#%DT%diosetup actuator d2 0 id/diodes/2 0 0 0 0.1
#%DD% attaches the relay served by device id/diodes/2, named "d2" as 2nd actuator of diodes system,
#%DT%diosetup system shutter
#%DD% initialises a 2nd system system called "shutter",etc ...
#%DT%dioread diodes 
#%DD% 
#%PRE%
# diodes system
#------------------------------------
#         d1 --> ON
#         d2 --> OFF
#%PRE%
#%DT%dioread shutter 
#%DD% 
#%PRE%
# shutter system
#------------------------------------
#         sh --> ON
#%PRE%
#%DT%dioset diodes d2 1 
#%DD% Sets actuator d2 on position ON.
#%PRE%
# diodes system
#------------------------------------
#         d1 --> ON
#         d2 --> ON
#%PRE%
#%XDL%
#%SETUP%
# %B%diosetup%B% with no argument raises up a configuration menu. 
#%BR% They are 2 input entries in case of both positions of a relay are monitored; When only 1 position is monitored, it is useful also to revert the information from "dioread", by setting either the input 1 or the input 2. The output channel logic can be reverted as well by setting accordingly the corresponding option. The settling time is the time to wait after an action, before displaying its result.
#%END%

#---------------------------------------------------------------- SETUP

#%UU% <setup_flag> [name] [output] [pulsed] [input1] [input2] [output_logic_revert] [settling_sec]
#%MDESC%
#%PRE%
#[setup_flag]		: 0|"reset"	1|"system"	2|"actuator"
#-----------------------> global init.	system init.	actuator setup
#[name]			: 	-	system name	actuator name
#[output] 		:	-		-	device server name
#[pulsed_output] 	:	-		-	device server name
#[input1]	 	:	-		-	device server name
#[input2] 		:	-		-	device server name
#[output_logic_revert] 	:	-		-	1|0 for Yes or No
#[settling_sec]		:	-		-	seconds 
#%PRE%
def diosetup '{
  global DIOSYS DIOX DIONO 
  global DIOACT DIOx DIOno
  global DIOO DIOI0 DIOI1 DIOLOG DIOTIME DIOOP

  DIOSYS[0]

  setup_tail ("dio")
  if ($#) { 
    _dio_setup $*
    _dio_conf
  } else {
    menu ("DIGITAL I/O ICV196 BOARD CONFIGURATION","_diomenu","","_dio_conf")
  }
}'

#%IU%
#%MDESC% Setup menu.
def _diomenu '{

  local add d  tmparr

#  menuoptval(0,"\n\n","System: ", DIOSYS[DIOX] ,"S")
  menuoptbutton (0,0,"System:","S")
  menuvardynl("DIOX","DIOSYS","DIONO" ,"", "_dio_delsys")
  menuoptgroupselect1(-10," "," ",DIOSYS,DIOX,DIONO,"DIOX", 2) 

  for (tmparr[0]=0,d=0;d<DIOno[DIOX];d++) {
    add = d+DIOX*100
    if (DIOACT[add]) tmparr[d]=DIOACT[add]
    else tmparr[d]=d+1
  }
  if (DIOx>=DIOno[DIOX]) DIOx=0#DIOno[DIOX]
  print ("\n  ");menupru ("Actuators:\n")
  menuoptgroupselect1(-10," ","  current:",tmparr,DIOx,DIOno[DIOX],"DIOx", 2) 

  menuoptbutton (15,0,"Add one: + ; ","+")
  menuaction("DIOx=DIOno[DIOX]++")

  menuoptbutton (0,"\n","Remove current: - .","-")
  menuaction("_dio_delact")

  if (DIOno[DIOX]) {

    menusep

    add = DIOx + DIOX*100

    menuoptval(20,0,"name",DIOACT[add],"name") 
    menuvargetv(sprintf("DIOACT[%d]",add))
 
    menuoptval(0,"\n","output device name ",DIOO[add],"o")  
    menuvargetv(sprintf("DIOO[%d]",add));printf("%20s"," ")
    menuaction(sprintf("if (DIOO[%d]) DIOOP[%d]=\"\";",add,add))
    menuoptval(0,"\n","pulsed output device name",DIOOP[add],"p")   
    menuvargetv(sprintf("DIOOP[%d]",add));printf("%20s"," ")
    menuaction(sprintf("if (DIOOP[%d]) DIOO[%d]=\"\";",add,add))

    menuoptval(0,"\n","input 1 device name",DIOI0[add],"i")  
    menuvargetv(sprintf("DIOI0[%d]",add));printf("%20s"," ")
    menuoptval(0,"\n","input 2 device name",DIOI1[add],"n")   
    menuvargetv(sprintf("DIOI1[%d]",add));printf("\n%20s"," ")

    menuoptval(0,"\n","revert output logic",DIOLOG[add]?"YES":"NO","r")  
    menuvartogg(sprintf("DIOLOG[%d]",add));printf("%20s"," ")
    menuoptval(0,"\n","settling time (sec)",DIOTIME[add],"s")   
    menuvargetv(sprintf("DIOTIME[%d]",add))
  }
}'

DIOSYS[0]

#%IU% <deleted_index> <number_of_systems_prior_to_deletion>
#%MDESC% Setup menu: system deletion.
def _dio_delsys '{

local x_deleted no_old add1 add2

x_deleted = $1
no_old    = $2
add1 = x_deleted * 100
add2 = DIOno[DIOX] + DIOX*100
DIOID[DIOSYS[x_deleted]]=0  

if (x_deleted==no_old-1) {
  for (i=0;i<DIOno[no_old-1];i++) {
    adel = i+ x_deleted*100
    DIOid [DIOACT[adel]]=0
    DIOACT[adel]=0;    DIOO[adel]   ="";    DIOOP[adel] ="";
    DIOI0[adel] ="";    DIOI1[adel] ="";
    DIOLOG[adel] =0;    DIOTIME[adel] =0;
  }
} else {

  for (i=0;i<DIOno[no_old-1];i++) {
    add1 = i + x_deleted*100
    add2 = i + (no_old-1)*100
    DIOid[DIOACT[add1]]=0
    DIOACT[add1] = DIOACT[add2] ; DIOACT[add2]=0;
    DIOO[add1]   = DIOO[add2]   ; DIOO[add2]   ="";
    DIOOP[add1]  = DIOOP[add2]  ; DIOOP[add2] ="";
    DIOI0[add1]  = DIOI0[add2]  ; DIOI0[add2] ="";
    DIOI1[add1]  = DIOI1[add2]  ; DIOI1[add2] ="";
    DIOLOG[add1] = DIOLOG[add2] ; DIOLOG[add2] =0;
    DIOTIME[add1]= DIOTIME[add2]; DIOTIME[add2] =0;
  } 
  for (;i<DIOno[x_deleted];i++) {
    add2 = i + x_deleted*100
    DIOACT[add2]=0;    DIOO[add2]   ="";    DIOOP[add2] ="";
    DIOI0[add2] ="";    DIOI1[add2] ="";    DIOLOG[add2] =0;
    DIOTIME[add2] =0;
  }
  DIOno[x_deleted]=DIOno[no_old-1]
}
DIOno[no_old-1]=0
DIOx = 0
}'

#%IU%
#%MDESC% Setup menu: actuator deletion.
def _dio_delact '{
  local add1 add2
  
  add1 = DIOx + DIOX*100
  add2 = DIOno[DIOX]-1 + DIOX*100

if (DIOno[DIOX]>0 && \
    _dio_makesure("actuator ",DIOACT[DIOx]?DIOACT[DIOx]:DIOx+1)) {
  DIOno[DIOX]--

  DIOid[DIOACT[DIOx]]=0

  if (DIOx==DIOno[DIOX]) DIOx=0
  else {
    DIOACT[add1] = DIOACT[add2]
    DIOO[add1]   = DIOO[add2] 
    DIOOP[add1]  = DIOOP[add2]
    DIOI0[add1]  = DIOI0[add2]
    DIOI1[add1]  = DIOI1[add2] 
    DIOLOG[add1] = DIOLOG[add2]
    DIOTIME[add1]= DIOTIME[add2]
  }
  DIOACT[add2]=0
  DIOO[add2]=DIOOP[add2]=DIOI0[add2]=DIOI1[add2]=""
  DIOLOG[add2]=DIOTIME[add2] = 0
}
}'

#%IU% (text,argument)
#%MDESC% Setup menu: ask for validation.
def _dio_makesure (text,arg1) '{
  local decision question
  question = "Confirm you want to erase " text arg1
  decision = yesno(question,1)
  return decision
}'

#%IU%
#%MDESC% Setup: Stores system and actuators numeric indexes as function of their name. 
def _dio_conf '{

{  unglobal DIOID DIOid  }

  global DIOID DIOid
  local sys act

  for (sys=0;sys<DIONO;sys++) {
    DIOID[DIOSYS[sys]]=sys+1
    for (act=0;act<DIOno[sys];act++) DIOid[DIOACT[act+sys*100]]=act+sys*100+1
  }
}'

#%UU%
#%MDESC% Un-Setup the whole thing.
def diounsetup '{
  unglobal DIOSYS DIOX DIONO DIOACT DIOx DIOno DIOO DIOI0 DIOI1 DIOLOG DIOTIME 
  unglobal DIOOP DIOID DIOid DIOSTAT DIOPOS DIOOPEN DIOCLOSE 
}'

#%IU% see diosetup.
#%MDESC% Command line setup.
def _dio_setup '{
  local add i nn arr j

  if ("reset"=="$1" || "0"=="$1") {
    diounsetup
  } else if ("system" == "$1" || "1"=="$1") {
    DIOX=DIONO 
    DIOSYS[DIOX]="$2" 
    DIONO++
    DIOno[DIOX] = 0
  } else if ("actuator"=="$1" || "2"=="$1") {
    add = DIOno[DIOX]+DIOX*100   
    DIOno[DIOX] ++
    DIOACT[add]= "$2" 
    DIOO[add]=   "$3"
    DIOOP[add]=   "$4"
    DIOI0[add]=  "$5"
    DIOI1[add]=  "$6"
    DIOLOG[add]=  $7
    DIOTIME[add]= $8
  } else {
    print "WARNING: Wrong argument given while setting up DIO macros"
    print "         DIO setup aborted."
  }
}'

#---------------------------------------------------------------- USER CONTROL
#  def userwa 'dioread usersystemname'
#  def usermv 'dioset usersystemname $*'

global DIOSTAT DIOPOS DIOOPEN DIOCLOSE
global DEVOPEN DEVCLOSE DEVFAULT DEVRUN DEVMOVING

DIOPOS[0]="OFF"
DIOPOS[1]="ON"

# Device server flags
 
DEVOPEN	  = 4
DEVCLOSE  = 3
DEVFAULT  = 23
DEVRUN    = 14
DEVMOVING = 9

# Returned by "DevState" and "DevReadValue" and "_dio_read()"

DIOSTAT[DEVOPEN] = DIOPOS[0]?DIOPOS[0]:"OPEN"	
DIOSTAT[DEVCLOSE] = DIOPOS[1]?DIOPOS[1]:"CLOSE"	
DIOSTAT[-DEVOPEN] = DIOPOS[1]?DIOPOS[1]:"CLOSE"	
DIOSTAT[-DEVCLOSE] = DIOPOS[0]?DIOPOS[0]:"OPEN"	
DIOSTAT[DEVFAULT] = "FAULT"	
DIOSTAT[DEVRUN] = "IDLE"	
DIOSTAT[DEVMOVING] = "PULSING"  
DIOSTAT[-DEVRUN] = "IDLE"	
DIOSTAT[-DEVMOVING] = "PULSING"  

# Returned by "_dio_read()"

# not used : DIOSTAT[2] = DIOPOS[0]?DIOPOS[0]:"OPEN"	
# not used : DIOSTAT[1] = DIOPOS[1]?DIOPOS[1]:"CLOSE"	
DIOSTAT[0] = "UNKNOWN"			
DIOSTAT[-1] = "COMMUNICATION ERROR"

# Output Commands

DIOCLOSE[0] = "DevClose"
DIOOPEN[0]  = "DevOpen"
DIOCLOSE[1] = "DevOpen"
DIOOPEN[1]  = "DevClose"

#%UU% [system_name] 
#%MDESC% Read and display the state of the actuators of the specified system. If none is specified, the last system addressed is considered. 
def dioread '{

  local i 

  DIOX = fabs(_dio_which ("$1"))

  printf("\n %s system\n",DIOSYS[DIOX])
  printf("------------------------------------\n")

  for (i=0;i<DIOno[DIOX];i++) {
    printf(" %10s --> %s\n",DIOACT[i+DIOX*100],DIOSTAT[_dio_read(i+DIOX*100)])
  }
}'

#%IU% (internal_address)
#%MDESC% Read the state of an actuator. 
def _dio_read (address) '{
  local stat comp

  if (DIOI0[address]) {

    stat = _dio_devread(DIOI0[address])
    if ((stat<0)||(stat==DEVFAULT)) return stat

    if (DIOI1[address]) {
      comp = _dio_devread(DIOI1[address])
      if ((comp<0)||(comp==DEVFAULT)) return comp
      if (stat==comp) return 0 
    }

    return stat
  }
  
  if (DIOI1[address]) return -(_dio_devread(DIOI1[address]))

  if (DIOOP[address]) {
    stat = _dio_devread(DIOOP[address])
    if (DIOLOG[address]) return -stat
    else                 return stat
  }

  if (DIOO[address]) {
    stat = _dio_devread(DIOO[address])
    if (DIOLOG[address]) return -stat
    else                 return stat
  }

  return 0
}'


#%UU% <system_name> <actuator_name> <1|0|on|off>
#%MDESC% Changes output level of an actuator.
def dioset '{
  local posi w1 w2 ai

  if (3!=$#) {
    print "usage: $0 system actuator 1|0|on|off"
    exit 
  }

  if ((w1 = _dio_which("$1",0)<0)) exit
  if ((w2 = _dio_which("$2",1)<0)) exit

  DIOX = w1 ; DIOx = w2

  posi = "$3"
  if (posi=="on") posi=1
  if (posi=="off") posi=0

  ai= DIOx + DIOX*100

  if (posi) _dio_close (ai)
  else _dio_open (ai)

  dioread
}'

#%IU% (internal_address)
#%MDESC% Open actuator relay. 
def _dio_open (address) '{
  esrf_io (DIOO[address],DIOOPEN[DIOLOG[address]])
  sleep(DIOTIME[ai])	
}'

#%IU%  (internal_address)
#%MDESC% Close actuator relay.
def _dio_close(address) '{
  esrf_io (DIOO[address],DIOCLOSE[DIOLOG[address]])
  sleep(DIOTIME[ai])	
}'

#%UU% <system_name> <actuator_name> <time_in_seconds>
#%MDESC% Pulses for the specified time, the specified actuator.
def diopulse '{

  local x1 x2 ad

  if (3!=$#) {
    print "usage: $0 system actuator time (in sec)"
    exit 
  }

  if ((x1 = _dio_which("$1",0))<0) exit
  if ((x2 = _dio_which("$2",1))<0) exit

  DIOX = x1 ; DIO_X = x2

  ad = x2 + x1*100

  if (DIOOP[ad]) _dio_devpulse (DIOOP[ad],$3) 
  else print "$2 Not a pulsed relay ($1 system)"

  _dio_wait (ad,DEVRUN)
}'

#%UU% <system_name> <actuator_name> <state_to_wait_for>
#%MDESC% Waits for the requested state is reached. 
#(valid states are : DEVOPEN, DEVCLOSE, DEVRUN,DEVMOVING.)
def diowait '{

  local x1 x2 ad

  if (3!=$#) {
    print "usage: $0 system actuator time (in sec)"
    exit 
  }

  if ((x1 = _dio_which("$1",0))<0) exit
  if ((x2 = _dio_which("$2",1))<0) exit

  DIOX = x1 ; DIO_X = x2

  ad = x2 + x1*100

  _dio_wait (ad,$3)
}'

#%IU% (internal_address,state_waited_for)
#%MDESC% Wait for the state changes and returns the final state. 
def _dio_wait (address,status) '{

  local device stat

  if (DIOOP[address] && !(DIOI0[address] || DIOI1[address])) {
    status = status==DEVOPEN?DEVRUN:status
    status = status==DEVCLOSE?DEVMOVING:status
  }

  if (status == DEVRUN || status == DEVMOVING) {
    device = DIOOP[address]
    printf ("%s: %s is ",DIOSYS[DIOX],DIOACT[DIOx])
    while ((stat=_dio_devstate(device))!=status && stat>=0&&stat != DEVFAULT) {
      printf ("\r%s: %s is %s",DIOSYS[DIOX],DIOACT[DIOx],DIOSTAT[stat])
    }
    if (stat<0 || stat==DEVFAULT) printf ("%s\n",DIOSTAT[stat])
    else printf (" %s\n",DIOSTAT[stat])

  } else {
    printf ("%s: %s is ",DIOSYS[DIOX],DIOACT[DIOx])
    while ((stat=_dio_read(address))!=status && stat>=0&&stat != DEVFAULT) {
      printf ("\r%s: %s is %s",DIOSYS[DIOX],DIOACT[DIOx],DIOSTAT[stat])
    }
    if (stat<0 || stat==DEVFAULT) printf ("%s\n",DIOSTAT[stat])
    else printf (" %s\n",DIOSTAT[stat])
  }
  return stat
}'

#---------------------------------------------------------------- LOW LEVEL

#%IU% (device_server_name)
#%MDESC% Returns the status of the specified device (DevState).
def _dio_devstate(dev) '{
  
  local resp
  ESRF_ERR = 0
  resp = esrf_io(dev,"DevState")
  if (ESRF_ERR) return -1
  else return resp
}'

#%IU% (device_server_name, time_in_seconds)
#%MDESC% Sends pulse command (DevReset) to the specified device.
def _dio_devpulse (dev,val) '{
  esrf_io(dev,"DevReset",val*256)
}'

#%IU% (device_server_name)
#%MDESC% Sends Opening command (DevOpen) to the specified device.
def _dio_devopen (dev) '{
  esrf_io(dev,"DevOpen")
}'

#%IU% (device_server_name)
#%MDESC% [Sends Closing command (DevClose) to the specified device.
def _dio_devclose (dev) '{
  esrf_io(dev,"DevClose")
}'

#%IU% (device_server_name)
#%MDESC% Returns Value on the specified device channel. (DevReadValue).
# Use globals DEVOPEN, DEVCLOSE ... to interpret the output.
def _dio_devread(dev) '{

  local resp
  ESRF_ERR = 0
  resp = esrf_io(dev,"DevReadValue")
  if (ESRF_ERR) return -1
  else return resp
}'


#---------------------------------------------------------------- UTILS


#%IU% (name,flag) 
#%MDESC% Returns the configuration index of the specified name. if flag is 0, the name is of a system, otherwise it is of an actuator.
def _dio_which (name,subl) '{
  local which

  if (name) {

    which = subl?DIOid[name]:DIOID[name]
    if (which) which--
    else {
      print "Don\'t know it,",name
      which = subl?-DIOx:-DIOX
    }
    return which
  }
  else return (subl?DIOx:DIOX)
}'


#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#%PRE%
#  - The file has to be read in                       !done by startup script
#    this file needs: %B% menu.mac%B%
#%PRE%
#%AUTHOR%
#  ICV196.MAC - Marie-Claire LAGIER - 97/2/18
#%TOC%