esrf

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

#%TITLE% XLENS_tango.mac
#$Revision: 1.2 $
#%NAME% Macros for CRL lenses tango device servers.
#%DESCRIPTION%
# The macros provide users with an interface between SPEC and CRL lenses tango
# device servers.
#%SETUP%
#When doing the config, declare a %B%motor\0controller%B%.
#%BR%
#%PRE%
#MOTORS\0\0\0\0DEVICE\0\0\0ADDR\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<>MODE\0\0NUM\0\0\0\0\0\0\0\0<>TYPE%BR%
#\0\0\0YES\0\0\0__XLENS\0\0\0//orion:10000/fe/xlens-mot/id18\0\0\0\0\02\0\0Macro\0Motors%BR%
# %BR%%B%Please\0note,%B% that the "-x" and "-z" parts of the tango domain name will added in the macros, depending on the channel number! %BR%
# Channel 0 will be "-x", %BR%
# channel 1 will be "-z" !
#%PRE%
#%BR% %BR%
#%BR% %BR%
#Then create %B%macro\0motors%B% in a similar manner. Unit is index number of the controller.
#%PRE%
#Number:\0<>Controller\0\0\0\0\0\0\0\00:\0MAC_MOT\0\0\01:\0MAC_MOT
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\0x/0\0\0\0\0\0\0\0\0\0\0x/1
#Name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0FE_L_Y\0\0\0\0\0\0\0FE_L_Z
#Mnemonic\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fly\0\0\0\0\0\0\0\0\0\0flz
#
#Steps\0per\0degree/mm\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0160\0\0\0\0\0\0\0\0\02000
#Sign\0of\0user\0*\0dial\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01\0\0\0\0\0\0\0\0\0\0\0\01
#Backlash\0[steps]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00\0\0\0\0\0\0\0\0\0\0\0\00
#Steady-state\0rate\0[Hz]\0\0\0\0\0\0\0\0\0\0\0\01000\0\0\0\0\0\0\0\0\01000
#Base\0rate\0[Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0200\0\0\0\0\0\0\0\0\0\0\015
#Acceleration\0time\0[msec]\0\0\0\0\0\0\0\0\0\02000\0\0\0\0\0\0\0\0\0\0500
#Motor\0accumulator\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00\0\0\0\0\0\0\0\0\0\0\0\00
#Restrictions\0<>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NONE\0\0\0\0\0\0\0\0\0NONE
#
#Dial\0=\0accumulator\0/\0steps
#\0\0High\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\07.0000\0\0\0\0\0\0\06.8755
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000\0\0\0\0\0\0\00.0000
#\0\0Low\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-6.4000\0\0\0\0\0\0-6.5265
#User\0=\0sign\0*\0dial\0+\0offset
#\0\0Offset\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000\0\0\0\0\0\0\00.0000
#\0\0`High'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\07.0000\0\0\0\0\0\0\06.8755
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000\0\0\0\0\0\0\00.0000
#\0\0`Low'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-6.4000\0\0\0\0\0\0-6.5265
#%PRE%
# Please note, that step size and rates are not taken into account!
#%END%
#%BR%
# Then hit 'm' twice. Set the following for your motor:
#%PRE%
#Hardware\0read\0mode\0<>\0\0\0\0\0\0\0\0%B%NO\0QUERY\0=NQ%B%
#%PRE%
# If you miss this, you will be asked to confirm motor positions after each
# change on a revolver.
#%END%
#%HISTORY%
#$Log: XLENS_tango.mac,v $
#Revision 1.2  2016/12/02 12:05:51  guilloud
#changed TANGO_ERR test.
#
#Revision 1.1  2012/03/07 14:59:56  witsch
#Initial revision
#

need spec_utils

if (!(whatis("__xlens_debug")    & 2)) rdef __xlens_debug \'#$*\'
if (SPEC == "holg") {
    if (!(whatis("__xlens_verbose")  & 2)) rdef __xlens_verbose \'eprint "XLENS >>> "\'
} else {
    if (!(whatis("__xlens_verbose")  & 2)) rdef __xlens_verbose \'#$*\'
}

#%UU%
#%MDESC% toggle debug mode for the present macros.
def XLENS_debug '{
    if ((whatis("__xlens_debug") >> 16) <= 5) { # just a # sign -> off
        rdef __xlens_debug "eprint \"XLENS: \", "
        eprint "XLENS debug is ON"
    } else {
        rdef __xlens_debug \'#$*\'
        eprint "XLENS debug is OFF"
    }
}
'

#%IU%
#%MDESC% called after each tango_[get|io] call. Checks for errors.
def __XLENS_tango_catch_error '{
    if (TANGO_ERR != "0") {
        tty_cntl("md")
        #__errstr = what "(\"" addr "\", \"" attr "\")"
        __errstr    =   __XLENS["macfname"] " - " func " - ERROR: " what \
            "(\"" addr "\", \"" attr "\") " add "\n"
        __XLENS_error(__errstr)
        __xlens_debug  TANGO_ERR_STACK
        tty_cntl("me")
        return ".error."
    }
}
'

#%IU%(mnum, type, unit, mod, chan)
#%MDESC%
# The macro motor configuration function
def __XLENS_config(mnum, type, unit, mod, chan) '{
    # chan will be used for counters to designate the tag address. Leave alone.
    __xlens_debug "Configuring XLENS", mnum, type, unit, mod, chan

    local func, attr, what, __errstr
    func    =   "__XLENS_config()"
    addr    =   __XLENS_ADDR
    what    =   "tango_get"
    if (type == "ctrl") {
        # delete all the associative arrays to do a clean job.
        global __XLENS[]
        local x
        __XLENS["savedir"]      =   SPECD "/../../../local/spec/userconf"
        __XLENS["macfname"]     =   "XLENS_tango.mac"
        __XLENS["unit"]         = __XLENS_ADDR # saving for the spec bug in _par
    }
    else if (type == "mot") {
        motor_par(mnum, "backlash", 0)      # is handled by server
        __xlens_verbose "Motor", motor_name(mnum), "(mne", motor_mne(mnum) ")"
    }
}
'

#%IU%(mnum, cmd, p1, p2, p3)
#%MDESC%
# The macro motor command function
def __XLENS_cmd(mnum, cmd, p1, p2, p3) '{
    local unit, chan, retval
    __xlens_debug "Command XLENS", mnum, cmd, p1, p2, p3, "(" __XLENS["unit"] ")"
    local func, attr, what, __errstr
    func    =   "__XLENS_cmd()"
    addr    =   __XLENS["unit"]
	if (!addr) { # when macro has just been loaded and a reconfig is performed
		addr	=	__XLENS_ADDR
	}
    what    =   "tango_io"
    if (mnum != "..") {
        unit = motor_par(mnum, "unit")
        chan = motor_par(mnum, "channel") # 0 -> x / 1 -> z
        if (chan == 0) {
            addr    =   addr "-x"
        }
        else if (chan == 1) {
            addr    =   addr "-z"
        }
        else {
            __XLENS_error("Channel must be 0 for x and 1 for z!")
            return ".error."
        }
        if (cmd == "start_one") {
            local state, position
            attr = "Position"
            state   =   __XLENS_state(addr)
            what    =   "tango_put"
            __xlens_debug "tango_put(\"" addr "\", \"" attr "\", " p1 ")"
            tango_put(addr, attr, p1)
            __XLENS_tango_catch_error
        }
        else if (cmd == "position") {
            local state, position
            state   =   __XLENS_state(addr)
            __xlens_debug "position:", chan, "state is", state
            what    =   "tango_get"
            attr    =   "Position"
            __xlens_debug "get_status:", chan, addr, "state is", state
            retval = tango_get(addr, attr)
            __XLENS_tango_catch_error
            return retval
        }
        else if (cmd == "get_status") {
            local state, xtra[]
            attr = "Position"
            state = __XLENS_state(addr)
            __xlens_debug "get_status:", chan, addr, "state is", state
            if (state == "ALARM") {
                __xlens_debug "get_status: in ALARM state"
                attr = "HardLimitLow"
                retval = tango_get(addr, attr)
                __XLENS_tango_catch_error
                if (retval == 1) {
                    return 0x04
                } else {
                    attr = "HardLimitHigh"
                    retval = tango_get(addr, attr)
                    __XLENS_tango_catch_error
                    if (retval == 1) {
                        return 0x08
                    }
                }
            } else
            if (state == "MOVING") {
                return 2
            } else
            if (state == "ON") {    # all good
                return 0
            } else {                # anything else is bad
                return 0x20
            }
        }
        else if (cmd == "abort_one") {
            attr    =   "Abort"
            __xlens_debug "tango_io(\"" addr "\", \"" attr "\")"
            tango_io(addr, attr)
            __XLENS_tango_catch_error
        }
    }
}
'

#%IU%(und)
#%MDESC%Get state of xlens motor%BR%
#%END%
# Info from J. Meyer 12/12/11 on states%BR%
# Von ON = 0 bis UNKNOWN=13%BR%
# enum DevState { ON, OFF, CLOSE, OPEN, INSERT, EXTRACT, MOVING,%BR%
#                 STANDBY, FAULT, INIT, RUNNING, ALARM, DISABLE,%BR%
#                 UNKNOWN };
def __XLENS_state(addr) '{
    __xlens_debug "state from", addr
    local state, aux[], stenum[], str
    str     =   "ON OFF CLOSE OPEN INSERT EXTRACT MOVING STANDBY FAULT INIT
                 RUNNING ALARM DISABLE UNKNOWN"
	if (!addr) { # when macro has just been loaded and a reconfig is performed
		return "UNKNOWN"
	}
    split(str, stenum)
    local func, attr, what, __errstr
    func    =   "__XLENS_state()"
    what    =   "tango_get"
    attr    =   "State"
    __xlens_debug "tango_get(\"" addr "\", \"" attr "\", aux)"
    state   =   tango_get(addr, attr)
    __XLENS_tango_catch_error
    return stenum[state]
}
'


#%IU%(mesg)
#%MDESC% Writes indentical error message only once in a while.
def __XLENS_error(errstr) '{
    global __XLENSERR[]
    local expiry, now, str
    str = "XLENS: " errstr
    expiry  =   5   # seconds before message is redisplayed
    now     =   time()
    if (errstr in __XLENSERR) {
        if ((time() - __XLENSERR[errstr]) > expiry) {
            __XLENSERR[errstr] = now
            cprint(str, 3, 1, 1)
        }
    } else {
        __XLENSERR[errstr] = now
        cprint(str, 3, 1, 1)
    }
    local x
    for (x in __XLENSERR) {
        if ((time() - __XLENSERR[x]) > 20) {
            delete __XLENSERR[x]
        }
    }
}
'

#%MACROS%
#%IMACROS%
#%INTERNALS%
#%AUTHOR% H. Witsch, BLISS - ESRF
#$Revision: 1.2 $, $Date: 2016/12/02 12:05:51 $
#%TOC%