esrf

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

"""#%TITLE% birmingham_magnet.mac
#%NAME%
# Macros for the use of a 17T superconducting magnet controller from Birmingham (????).
#%DESCRIPTION%
# Use of the Birmingham superconducting magnet controller.
#%SETUP%
# In the config editor in the "Motor and Counter Device Configuration" page (hit "D") create a motor
# controller like follows: 
# %BR%
#MOTORS\0\0\0\0\0\0\0\0\0\0DEVICE\0\0\0\0\0\0\0\0\0\0ADDR\0\0<>MODE\0\0NUM\0\0\0\0\0\0\0\0\0\0\0\0\0<>TYPE%BR%
#\0\0\0YES\0\0\0\0\0\0\0\0\0\0BIRMSM\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0\0\0\0\0\0\0\0\0\0\01\0\0\0\0\0\0\0Macro\0Motors
# %BR%
#Then create the macro motor:
#%PRE%
#Number:\0<>Controller\0\0\0\0\0\0\0\0\0\0\00:\0MAC_MOT
#%BR%
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00/0\0(first\0num\0is\0index\0num\0of\0controller)
#%BR%
#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\0\0\0\0\0\0birm
#%BR%
#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\0\0\0birm
#%BR%
#Steps\0per\0degree/mm\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\010000
#%BR%
#Sign\0of\0user\0*\0dial\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Backlash\0[steps]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00
#%BR%
#Steady-state\0rate\0[Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Base\0rate\0[Hz]\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\01
#%BR%
#Acceleration\0time\0[msec]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Motor\0accumulator\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00
#%BR%
#Restrictions\0<>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NONE
#%BR%
#
#%BR%
#Dial\0=\0accumulator\0/\0steps
#%BR%
#\0\0High\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\017.0000
#%BR%
#\0\0Current\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\00.0000
#%BR%
#\0\0Low\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-17.0000
#%BR%
#User\0=\0sign\0*\0dial\0+\0offset
#%BR%
#\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\0\0\0\00.0000
#%BR%
#\0\0`High'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\017.0000
#%BR%
#\0\0Current\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\00.0000
#%BR%
#\0\0`Low'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-17.0000
#%PRE%
#%BR%
# It is advisable to set the backlash for the macro motors to 0. 
#%ATTENTION%
#  %DL%
#  %DT% Channel numbers are :
#  %DD% 0 for magnet field
#  %DD% 1 for Current Temp Heat Exchanger
#  %DD% 2 for Current Temp Probe
#  %DD% 3 for Needle Valve Position
#  %DD% 4 for Needle Valve Pressure Target
#  %DD% 5 for Needle Valve Actual Pressure
#  %DD% 6 for helium level
#  %DD% 7 for atto position
#  %XDL%
#  %DL%
#%END%
# Modifications history:
# 10/04/2013 Creation 
"""

#-----------------------------------------------------------
#%IU%(serialline, parity, speed)
#%MDESC% Setting serial line parameters
def _birmsm__set_serial_parameters(serialline, parity, speed) '{
    """
    /*
     * symbolic defines - used by server and client alike
     */
    #define SL_RAW 0 /* raw read/write mode */
    #define SL_NCHAR 1 /* character read/write mode */
    #define SL_LINE 2 /* line read mode */

    #define SL_NONE 0
    #define SL_ODD 1
    #define SL_EVEN 3

    #define SL_DATA8 0
    #define SL_DATA7 1
    #define SL_DATA6 2
    #define SL_DATA5 3

    #define SL_STOP1 0
    #define SL_STOP15 1
    #define SL_STOP2 2

    #define SL_TIMEOUT 3 /* timeout parameter */
    #define SL_PARITY 4 /* number of parity bits parameter */
    #define SL_CHARLENGTH 5 /* number of data bits parameter */
    #define SL_STOPBITS 6 /* number of stop bits parameter */
    #define SL_BAUDRATE 7 /* baud rate parameter */
    #define SL_NEWLINE 8 /* new line character parameter */
    """    
    global ESRF_ERR
    local params[], device, lspeed, lparity, lbytes
    device = serialline
    #device = ser_par(serialline, "device_id")
    if (index(device, "/dev/")) {
        eprint "_birmsm__set_serial_parameters(): can`t set parameters on local serial line", \
                           device
        return(-1)
    }
    if (!speed)  { lspeed = 9600 }
    else         { lspeed = speed }
    if (index(parity, "even"))  { lparity = 3; lbytes = 1 }
    else if (index(parity, "odd"))  { lparity = 1; lbytes = 1 }
    else         { lparity = 0; lbytes = 0 }
    # setting the parameters as wished by the Tango DS
    params[ 0] =       3  # SL_TIMEOUT    /* timeout parameter */
    params[ 1] =     500  # timeout value
    params[ 2] =       4  # SL_PARITY     /* number of parity bits parameter */
    params[ 3] = lparity  # even parity
    params[ 4] =       5  # SL_CHARLENGTH /* number of data bits parameter */
    params[ 5] =  lbytes  # 7 data bits
    params[ 6] =       6  # SL_STOPBITS   /* number of stop bits parameter */
    params[ 7] =       0  # 1 stop bit
    params[ 8] =       7  # SL_BAUDRATE   /* baud rate parameter */
    params[ 9] =  lspeed  # baud
    params[10] =       8  # SL_NEWLINE    /* new line character parameter */
    params[11] =      10  # LF

    ESRF_ERR = -1
    taco_io(device, "DevSerSetLongParameter", params)
    if (ESRF_ERR){
        __BIRMSM_debug  "_birmsm__set_serial_parameters: taco_io(\"" device "\", \"DevSerSetParameter\", params) failed!"
        return(0)
    } else {
        return(1)
    }
}
'



#%IU%
#%MDESC%
# Called by spec,
def BIRMSM_config(mnum,type,unit,mod,chan) '{
    local addr mma
    global __BIRMSM_ADDR

    __BIRMSM_ADDR = addr = BIRMSM_ADDR # keep address for other macros
    __BIRMSM_debug "address", addr, __BIRMSM_ADDR

    __BIRMSM_debug "BIRMSM_config", mnum,type,unit,mod,chan
    # __BIRMSM_ADDR should contain sth like id12/serial/toto
    # in case of error (server or hardware) the setting to .error.
    # will make spec disable this macromotor.
#    if ( mnum == "..") {
#        if (!(whatis("__BIRMSM_SIMU") & 0x5000000)) {
#            if (!_birmsm__set_serial_parameters(addr, "odd", 9600)) {
#                return ".error."
#            }
#            # must be smaller than TRANSIENT_CallTimedoutTimeout (3000 mS)
#           TACO_ERR = 0
#           taco_io(addr, "DevSerSetTimeout", 2900)
#           if (TACO_ERR != 0) {
#              return(".error.")
#           }
#        }
#    }
    __birmsh_io(addr, "setpersist ON")
    return(0)
}
'

#%IU%
#%MDESC%
# Called by spec
def BIRMSM_cmd(mnum, cmd, p1, p2, p3) '{
    local addr, module, channel, strin

    addr = __BIRMSM_ADDR
    __BIRMSM_debug "BIRMSM_cmd:", mnum,cmd, p1, p2, p3
    
    if (mnum == "..") {
        return
    }
    if (cmd == "start_one") {
        # start counter, when it is one
        if (p2 == 0) {
            return
        }
        channel = motor_par(mnum, "channel")
        if (channel == 0) { # deal with magnet field
            strin = "abort"
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
            strin = "setfield " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        else if (channel == 1) { # deal with Current Temp Heat Exchanger
            strin = "set1 " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        else if (channel == 2) { # deal with Current Temp Probe
            strin = "set2 " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        else if (channel == 3) { # deal with Needle Valve Position
            strin = "setposition " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        else if (channel == 4) { # deal with Needle Valve Pressure Target
            strin = "setpressure " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        else if (channel == 7) { # deal with atto positions
            local strin
            strin = "setangle " p1
            __BIRMSM_debug strin
            if (__BIRMSM_io(addr, strin) == ".error.") return ".error."
        }
        #else if (channel == 5) { # DO NOT deal with Needle Valve Actual Pressure
        #else if (channel == 6) { # DO NOT deal with helium level
    }
    else if (cmd == "get_status") {
        if (channel == 0) { # deal with magnet field
            channel  = motor_par(mnum, "channel")
            local strin, strout, aux[]
            strin = "ready"
            __BIRMSM_debug strin
            strout = __BIRMSM_io(addr, strin)
            split(strout, aux, ":")
            __BIRMSM_debug strout, "---->", aux[2], "<----"
            if (aux[2] == "OFF\n")
                return 2
        }
        else 
            return 0
    }
    else if ((cmd == "position") || (cmd == "counts")) {
        local field, strout, aux[]
        if (cmd == "position")
            channel  = motor_par(mnum, "channel")
        else if (cmd == "counts")
            channel  = counter_par(mnum, "channel")
        if (channel == 0) { # deal with magnet field
            local field, strout, aux[]
            strin = "output"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            strout = substr(strout, 11)
            split(strout, aux, ",")
            if (sscanf(aux[0], "%f", field) != 1) {
                eprint "answer from \"output\" can`t be scanned for field value", aux[0]
                return ".error."
            }
            __BIRMSM_debug "position/counts return", field
            return field
        }
        else if (channel == 1) { # deal with Current Temp Heat Exchanger
            strin = "sensA"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
        else if (channel == 2) { # deal with Current Temp Probe
            strin = "sensB"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
        else if (channel == 3) { # deal with Needle Valve Position
            strin = "nv"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
        else if (channel == 4) { # deal with Needle Valve Pressure Target
            strin = "pressure"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
        else if (channel == 5) { # deal with Needle Valve Actual Pressure
            strin = "pressure"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[3] * 1.0
        }
        else if (channel == 6) { # deal with helium level
            strin = "helevel"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
        else if (channel == 7) { # deal with atto position
            strin = "attoangle"
            __BIRMSM_debug strin
            if ((strout = __BIRMSM_io(addr, strin)) == ".error.") return ".error."
            __BIRMSM_debug strout
            split(strout, aux, ":")
            return aux[2] * 1.0
        }
    }
}
'

if (!(whatis("__BIRMSM_debug")  & 2)) rdef __BIRMSM_debug \'#$*\'

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

if (!(whatis("__BIRMSM_info")  & 2)) rdef __BIRMSM_info \'eprint\'
#%UU%
#%MDESC% toggle info mode for the present macros.
def BIRMSM_info '{
  if ((whatis("__BIRMSM_info")>>16) <= 3) { # just a # sign -> off
    rdef __BIRMSM_info "eprint"
    print "BIRMSM info is ON"
  } else {
    rdef __BIRMSM_info \'#\$*\'
    print "BIRMSM info is OFF"
  }
}
'


#%UU%
#%MDESC% toggle info mode for the present macros.
def __BIRMSM_simuf(cmd) '{
    global __BIRMSM_SIMU[]
    local answ
    __BIRMSM_debug "BIRMSM SIMU cmd", cmd
    local aux[], n
    if (cmd == "output")
        answ = sprintf("output:OK:%fT,%fA", __BIRMSM_SIMU["field"]*1.0, __BIRMSM_SIMU["field"]*12.3)
    else if (index(cmd, "setfield") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["field"] = aux[1] * 1.0
        answ = "setfield:OK"
    }
    else if (cmd == "heater")
        answ = sprintf("heater:OK:%d", __BIRMSM_SIMU["heater"])
    else if (cmd == "persistent")
        answ = sprintf("persistent:OK:%fT,%fA", __BIRMSM_SIMU["field"]*1.0, __BIRMSM_SIMU["field"]*12.3)
    else if (index(cmd, "setpersist") == 1) { # startswith 
        split(cmd, aux, " ")
        if (aux[1] == "ON") __BIRMSM_SIMU["heater"] = 0
        answ = "setpersist:OK"
    }
    else if (cmd == "persistentmode")
        answ = sprintf("persistentmode:OK:%s", __BIRMSM_SIMU["heater"] ? "ON":"OFF")
    else if (cmd == "ready")
        answ = "ready:OK:ON"
    else if (cmd == "abort")
        answ = "abort:OK"
    else if (cmd == "getstatus") 
        answ = "blablablablabla"
    else if (index(cmd, "set1") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["heat exchanger"] = aux[1] * 1.0
        answ = "set1:OK"
    }
    else if (cmd == "sensA") answ = sprintf("sensA:OK:%f", __BIRMSM_SIMU["heat exchanger"])
    else if (index(cmd, "set2") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["probe"] = aux[1] * 1.0
        answ = "set2:OK"
    }
    else if (cmd == "sensB") answ = sprintf("sensB:OK:%f", __BIRMSM_SIMU["probe"])
    else if (index(cmd, "setpressure") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["NV target pressure"] = aux[1] * 1.0
        answ = "setpressure:OK"
    }
    else if (cmd == "pressure") answ = sprintf("pressure:OK:%f", __BIRMSM_SIMU["NV target pressure"])
    else if (index(cmd, "setposition") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["NV position"] = aux[1] * 1.0
        answ = "setposition:OK"
    }
    else if (cmd == "nv") answ = sprintf("nv:OK:%f", __BIRMSM_SIMU["NV position"])
    else if (cmd == "helevel") answ = sprintf("helevel:OK:%d", 43)
    else if (index(cmd, "setangle") == 1) {
        split(cmd, aux, " ")
        __BIRMSM_SIMU["attoangle"] = aux[1] * 1.0
        answ = "setangle:OK"
    }
    else if (cmd == "attoangle") answ = sprintf("attoangle:OK:%f", __BIRMSM_SIMU["attoangle"])
    else answ = cmd ":OK"
    #
    __BIRMSM_debug "BIRMSM simulation answer:", answ
    return(answ)
}
'

#%IU%(addr, cmd)
#%MDESC% Called by spec, write command to controller and read answer.
def __BIRMSM_io(addr, cmd) '{
    local answ
    if (!(whatis("__BIRMSM_SIMU") & 0x5000000)) {
        if (__BIRMSM_put(addr, cmd) == ".error.") {
                return(".error.")
        }
        # a sleep here should be unnecessary, if the timeout is set correctly
#       sleep(1)
        return __BIRMSM_get(addr)
    }
    else {
        answ = __BIRMSM_simuf(cmd)
    }
    return(answ)
}
'


#%IU%(addr, cmd)
#%MDESC% Called by spec, write command to controller, no answer expected.
# return .error. in case of error  
def __BIRMSM_put(addr, cmd) '{
    local answer

    if (!(whatis("__BIRMSM_SIMU") & 0x5000000)) {
        __BIRMSM_debug "__BIRMSM_put(\"" addr "\", \"" cmd "\")"
        local str
        str = cmd "\n"
        ser_par(addr, "flush", 2)
        answer = ser_put(addr, str)
        __BIRMSM_debug "__BIRMSM_put: ser_put answers", answer
        if (answer == 0) {
            return ".error."
        }
    }
    else {
        __BIRMSM_simuf(cmd)
    }
    return 0
}
'

#%IU%(addr)
#%MDESC% Called by spec, read an answer
def __BIRMSM_get(addr) '{
    if (!(whatis("__BIRMSM_SIMU") & 0x5000000)) {
        local answer
        answer = ser_get(addr, "\n")
        __BIRMSM_debug "__BIRMSM_get(\"" addr "\") = ", answer
        if (answer == "") {
            return ".error."
        }
	    return answer
    }
    return 0
}
'


# some programmer help
#%UU%
#%MDESC% toggle debug mode for the present macros.
def BIRMSM_simu '{
    if (!(whatis("__BIRMSM_SIMU") & 0x5000000)) {
        global __BIRMSM_SIMU[]
        __BIRMSM_SIMU["active"] = 1
        __BIRMSM_SIMU["heater"]    = 0
        print "BIRMSM simulation is ON"
    } else {
        unglobal __BIRMSM_SIMU
        print "BIRMSM simulation is OFF"
    }
}
'


#%UU% [output|voltage|heater|ramprate|units|target|persistent|ready|getstatus]
#%MDESC% miscellaneous calls to the controller
def BIRMSM_command'{
    local send
    send = "$*"
    __BIRMSM_debug "\"$*\""
    print __BIRMSM_io(__BIRMSM_ADDR, send)
}'

#%UU%
#%MDESC% miscellaneous calls to the controller
def BIRMSM_heater'{
    local str, strout, aux[], status
    str = "ON  OFF  OFF AT FIELD  NO MATCH"
    strout = __BIRMSM_io(addr, "heater")
    split(strout, aux, ":")
    status = aux[2] + 0
    split(str, aux, "  ")
    print "Main coil heater status is:", aux[status]
}'


#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#The file birmingham_magnet.mac havs to be read in. 
#%AUTHOR% BLISS - ESRF, H. Witsch%BR%
#$Revision: 1.1 $
#%TOC%