esrf

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

#%TITLE% pi_e517.mac $Revision: 1.6 $
#%NAME%
# Macros to control a piezo PI E517 controller connected via TCP/IP.
#
#%DESCRIPTION%
#  This macro file allows to connect a piezo to a macro motor in SPEC.
#
#%DL%
#%DT%PI E-517 (TCP)%DD%
#%XDL%
#
#  For debug purpose mainly, it's also possible to configure a macro
#  counter that will read the position of a piezo axis.
#  Parameter of the macro counter:
#  <motor> : motor mnemonic to reflect position.
#
#%END%
#
#%SETUP%
#  In order to configure a macro motor:
#  %DL%
#    %DT% 1)
#         You must have a "MOTORS" defined with:
#         %BR%
#         %DL%
#           %DT% DEVICE
#           set to "pi_e517"
#           %DT% TYPE
#           set to "Macro Motor"
#           %DT% ADDR
#           set to the TCP Address of the controller
#           %DT% NUM
#           must be set also
#         %XDL%
#    %DT% 2)
#         Per piezo axis you must define a motor with:
#         %BR%
#         %DL%
#           %DT% Controller
#           set to "MAC_MOT"
#           %DT% Unit
#           field must be set to the "MOTOR" entry.
#           %DT% Chan
#           field must be set to the piezo axis of the controller
#           (for instance "0" stands for axis "A", "1" for "B" etc)
#         %XDL%
#  %XDL%
#
#  In order to configure a macro counter:
#  %DL%
#    %DT% 1)
#         You must have a "SCALERS" defined with:
#         %BR%
#         %DL%
#           %DT% DEVICE
#           set to "pi_e517_c"
#           %DT% TYPE
#           set to "Macro Counter"
#           %DT% NUM
#           must be set also
#         %XDL%
#    %DT% 2)
#         Per piezo axis you must define a counter with:
#         %BR%
#         %DL%
#           %DT% Device
#           set to "MAC_CNT"
#           %DT% Mnemonic
#           what you want.
#           %DT% parameters
#           "motor" -> mnemonic of the motor to reflect position.
#           %DT% Unit
#           do not mind
#           %DT% Chan
#           do not mind
#         %XDL%
#
#  %XDL%
#
#%END%

need spec_utils

constant PI_E517_HEAD "PI E-517 :"

global PI_E517[]

######################################################################
###############################         ##############################
###############################  DEBUG  ##############################
###############################         ##############################
######################################################################

#%UU% [<personal msg>]
#%MDESC%
# Switch on or off the print of debug messages
#
def pi_e517debug '{
    if(PI_E517["debug"]) {
        rdef pi_e517__debug \'#\$#\'
            print PI_E517_HEAD"debug mode is OFF"
        PI_E517["debug"]=0
    }
    else {
        rdef pi_e517__debug \'print PI_E517_HEAD,"$*"\'
            print PI_E517_HEAD"debug mode is ON"
        PI_E517["debug"]=1
    }
}'


# No debug by default
def pi_e517__debug \'#\$#\'


#%IU% <msg>
#%MDESC%
#    Prints error message <msg> in bold with a red header.
def pi_e517_err(msg) '{
    local  _colors _prompt

    _colors = cprint_colors_enabled()
    cprint_enable_colors

    _prompt = PI_E517_HEAD "ERROR : "
    cprint(_prompt, 1, 8, 1)
    bprint(sprintf("%s\n", msg))

    if(_colors == 0){
        cprint_disable_colors
    }
}'

######################################################################
###########################                 ##########################
###########################  COMMUNICATION  ##########################
###########################                 ##########################
######################################################################


#%UU% (<tcp_dev>, <cmd>)
#%MDESC%
#    Sends <cmd> to a tcp device.
# Adds "\n" at end of <cmd>
# Uses tcp/ip device : <tcp_dev>.
def pi_e517_put(tcp_dev, cmd) '{
    local _cmd

    # Purges <cmd>.
    _cmd = removeEndingChar( cmd, "\n")
    _cmd = removeEndingChar(_cmd, "\r")

    # Adds terminator.
    _cmd = sprintf("%s\n", _cmd)

    pi_e517__debug "pi_e517_put tcp_dev="tcp_dev " _cmd=" _cmd

    sock_put(tcp_dev, _cmd)
}'


#%UU% (<tcp_dev>)
#%MDESC%
#    Reads and returns the socket.
def pi_e517_get(tcp_dev) '{
    local _ans

    _ans = sock_get(tcp_dev)

    return(_ans)
}'


#%IU% (<mot_num>, <cmd>)
#%MDESC%
#    Sends <cmd> to the controller corresponding to motor <mot_num>
# and returns the answer.
#
# -<mot_num> : motor number
# -<cmd>     : string
#
def pi_e517_send(mot_num, cmd) '{
    local _tcp_dev

    _tcp_dev = pi_e517_get_tcp_dev_by_mot(mot_num)

    if(_tcp_dev == "0"){
        print "ERROR pi_e517_cmd bad motor name or undefined motor"
        return(-1)
    }

    sock_par(_tcp_dev, "flush")
    pi_e517__debug "SEND \"" cmd "\" to " _tcp_dev

    if(pi_e517_put(_tcp_dev, cmd) == -1){
        return( -1)
    }

    if ((_ans = pi_e517_get(_tcp_dev)) == -1){
        return( -1)
    }
    else{
        pi_e517__debug "GET " _ans " from " _tcp_dev

        return(_ans)
    }
}'


#%IU% (<mot_num>, <cmd>)
#%MDESC%
#    Sends <cmd> to the controller corresponding to motor <mot_num>
# without wating for an answer.
#
# -<mot_num> : motor number
# -<cmd>     : string
#
# Returns  0 in case of success.
# Returns -1 in case of error.
#
def pi_e517_send_no_ans(mot_num, cmd) '{
    local _tcp_dev

    _tcp_dev = pi_e517_get_tcp_dev_by_mot(mot_num)

    sock_par(_tcp_dev, "flush")

    pi_e517__debug "SEND \"" cmd "\" to " _tcp_dev

    if(pi_e517_put(_tcp_dev, cmd) == -1){
        return( -1)
    }

    return(0)

}'


#%IU% (<mot_num>)
#%MDESC%
#    Returns the ip address/name of the controller corresponding to motor
# <mot_num>
#    Returns -1 in case of error.
#
def pi_e517_get_tcp_dev_by_mot(mot_num)'{
    local _ans

    pi_e517__debug "pi_e517_get_tcp_dev_by_mot" mot_num

    _ans  = motor_par(mot_num, "tcp_dev")

    if(_ans != ""){
        return (_ans)
    }
    else{
        pi_e517_err(sprintf("parameter tcp_dev not defined for motor %d", mot_num))
        return (-1)
    }
}'


#%IU% (<mot_num>)
#%MDESC%
#    Returns the channel letter of axis of motor <mot_num>.
# Returns -1 in case of failure.
#
def pi_e517_get_chan_letter(mot_num, caller) '{
    local _ans

    pi_e517__debug "in pi_e517_get_chan_letter for motor number " mot_num

    _ans = motor_par(mot_num, "chan_letter")

    pi_e517__debug "in pi_e517_get_chan_letter read letter=" _ans

    if (_ans == "A" || _ans == "B" || _ans == "C"){
        return(_ans)
    }
    else{
        pi_e517_err(sprintf("parameter chan_letter not properly defined for motor %d", mot_num))
        print "_ans="_ans  "  caller="caller
        pi_e517_err( "It should be automatic -> please run reconfig.")
        return(-1)
    }
}'

#%IU% (<mot_num>)
#%MDESC%
#    Returns the channel NUMBER of axis of motor <mot_num>.
# Returns -1 in case of failure.
#
def pi_e517_get_chan_nb(mot_num) '{
    local _ans

    pi_e517__debug "in pi_e517_get_chan_nb" mot_num

    _ans = motor_par(mot_num, "chan_nb")
    return(_ans)
}'


#######################################################################
#######################                         #######################
#######################  CONTROLLER MANAGEMENT  #######################
#######################                         #######################
#######################################################################


#%IU% (<mot_num>)
#%MDESC%
#    Read the position from the controller axis corresponding
# to motor <mot_num> using command "POS? <N>"

# Returns the position read.
# Returns "ERROR" in case of error.
#
def pi_e517_get_read_pos(mot_num) '{
    local   _chan_letter  _cmd  _ans   _pos

    pi_e517__debug "in pi_e517_get_read_pos " mot_num

    _chan_letter = pi_e517_get_chan_letter(mot_num, 321)
    _cmd = sprintf("POS? %s", _chan_letter)
    _ans = pi_e517_send(mot_num, _cmd)
    pi_e517__debug "in pi_e517_get_read_pos _ans=" _ans

    _ans = removeEndingChar(_ans , "\n")

    # Removes "A="
    _ans = substr(_ans, 3)

    pi_e517__debug "in pi_e517_get_read_pos cleanned _ans=" _ans

    _pos = _ans + 0.0

    pi_e517__debug "in pi_e517_get_read_pos _pos=" _pos

    return(_pos)
}'

#%IU% (<mot_num>)
#%MDESC%
#    Read the target position from the controller axis corresponding
# to motor <mot_num> using command "MOV? <N>"
#
# Returns the target position read.
# Returns "ERROR" in case of error.
#
def pi_e517_get_pos(mot_num) '{
    local   _chan_letter  _cmd  _ans   _pos

    pi_e517__debug "in pi_e517_get_pos " mot_num

    _chan_letter = pi_e517_get_chan_letter(mot_num, 354)
    _cmd = sprintf("MOV? %s", _chan_letter)
    _ans = pi_e517_send(mot_num, _cmd)
    pi_e517__debug "in pi_e517_get_pos _ans=" _ans

    _ans = removeEndingChar(_ans , "\n")

    # Removes "A="
    _ans = substr(_ans, 3)

    pi_e517__debug "in pi_e517_get_pos cleanned _ans=" _ans

    _pos = _ans + 0.0

    pi_e517__debug "in pi_e517_get_pos _pos=" _pos

    return(_pos)
}'

#%IU% (<mot_num>, <position>)
#%MDESC%
#    Sends to controller of axis corresponding to <mot_num> a
# move to <position> command.
# Sends "MOV A/B/C <position>"
#
# cannot do MOV in open loop : must use voltage.
#
# Returns -1 in case of error.
#
def pi_e517_set_pos(mot_num, position) '{
    local   _cmd  _chan_letter

    pi_e517__debug "in pi_e517_set_pos " mot_num

    if (openloop){
        print "closed loop is OPEN, piezo cannot be controlled in position (use voltage)"
    }

    _chan_letter = pi_e517_get_chan_letter(mot_num, 355)
    _cmd = sprintf("MOV %s %g", _chan_letter, position)

    pi_e517_send_no_ans(mot_num, _cmd)
}'


#%IU% (<mot_num>)
#%MDESC%
#    Read the voltage from the controller axis corresponding
# to motor <mot_num> using command "? <N>"

# Returns the voltage read.
# Returns "ERROR" in case of error.
#
def pi_e517_get_voltage(mot_num) '{
    local   _chan  _cmd  _ans   _pos

    pi_e517__debug "in pi_e517_get_voltage - mot " mot_num

    _chan = pi_e517_get_chan_nb(mot_num)

    _cmd = sprintf("VOL? %s", _chan)

    _ans = pi_e517_send(mot_num, _cmd)
    pi_e517__debug "in pi_e517_get_voltage _ans=" _ans

    _ans = removeEndingChar(_ans , "\n")

    # Removes "1="
    _ans = substr(_ans, 3)

    pi_e517__debug "in pi_e517_get_voltage cleanned _ans=" _ans

    _voltage = _ans + 0.0

    pi_e517__debug "in pi_e517_get_voltage _voltage=" _voltage

    return(_voltage)
}'


def pi_e517_get_closed_loop_status(mot_num) '{
    local _ans  _pos  _cmd  _chan_letter  _status

    _chan_letter = pi_e517_get_chan_letter(mot_num, 436)

    # First check if closed-loop is active.
    _cmd = sprintf("SVO? %s", _chan_letter)
    _ans = pi_e517_send(mot_num, _cmd)
    _ans = removeEndingChar(_ans, "\n")
    _ans = substr(_ans, 3, 1)


    if (_ans == 0){
        pi_e517__debug " closed-loop is disabled."
        return(0)
    }
    else if(_ans == 1){
        pi_e517__debug " closed-loop is active."
        return(1)
    }

}'


#%IU% (<mot_num>)
#%MDESC%
#    Returns the individual "on-target status" of axis corresponding
# to motor <mot_num>
# Uses "ONT?" command
# ONT? return 1 if device is on-target
# Usable only in closed-loop ie if SVO? returns 1.
#
# Returns 0 if not on target and closed-loop active.
# Returns 1 if on target or closed-loop is disabled.
#
def pi_e517_get_status(mot_num) '{
    local _ans  _pos  _cmd  _chan_letter  _status
    local _loop_status

    pi_e517__debug "in pi_e517_get_status " mot_num

    _chan_letter = pi_e517_get_chan_letter(mot_num, 457)

    pi_e517__debug "in pi_e517_get_status SVO? _ans=" _ans

    # Checks Closed loop status.
    _loop_status = pi_e517_get_closed_loop_status(mot_num)

    if (_loop_status == 0){
        pi_e517__debug " closed-loop is disabled."
        _status = 1
        return(_status)
    }
    else if(_loop_status == 1){
        pi_e517__debug " closed-loop is active."

        # Then checks ONT.
        _cmd = sprintf("ONT? %s", _chan_letter)
        _ans = pi_e517_send(mot_num, _cmd)

        _ans = removeEndingChar(_ans , "\n")

        #pi_e517__debug "in pi_e517_get_status ONT? _ans=" _ans

        # Checks channel in answer.
        _chan = substr(_ans, 1, 1)
        if (_chan != _chan_letter){
            print "in pi_e517_get_status strange...."
        }

        # Removes "1=".
        _status = substr(_ans, 3)
        return(_status)
    }
}'


#%IU% (mot_num)
#%MDESC%
#    Sends to controller of motor <mot_num> a stop command.
# Sends "STP"
#
#   is it better to use HLT ?
# HLT -> stop smoothly.
# STP / 24 -> stop asap.
#
# !!! on a HLT or STP, the PI controller updates the target 
# !!! position using real position...
def pi_e517_stop(mot_num) '{

    pi_e517__debug "in pi_e517_stop " mot_num

    # return(pi_e517_send_no_ans(mot_num, "STP"))
    return(pi_e517_send_no_ans(mot_num, "HLT"))
}'



# PLM : position high limit


#%UU% <mot_num>
#%MDESC%
#    Prints out infos read from controller of motor <mot_num>
def pi_e517_infos '{

    if ($#==0){
        print "please specify a motor num"
        exit
    }
    else{
        printf(" %25s  CCL?: %s\n", "command level",          removeChars(pi_e517_send($1, "CCL?"), "\n"))
        printf(" %25s  CSV?: %s\n", "GCS Syntax version",     removeChars(pi_e517_send($1, "CSV?"), "\n"))
        printf(" %25s  DCO?: %s\n", "Drift compensation",     removeChars(pi_e517_send($1, "DCO?"), "\n"))
        printf(" %25s  ERR?: %s\n", "Last error",             removeChars(pi_e517_send($1, "ERR?"), "\n"))
        printf(" %25s  IDN?: %s\n", "Identification",         removeChars(pi_e517_send($1, "IDN?"), "\n"))
        printf(" %25s  IFC?: %s\n", "Temporary IP settings",  removeChars(pi_e517_send($1, "IFC?"), "\n"))
        printf(" %25s  IFS?: %s\n", "Persistent IP settings", removeChars(pi_e517_send($1, "IFS?"), "\n"))
        printf(" %25s  MOV?: %s\n", "Target positions",       removeChars(pi_e517_send($1, "MOV?"), "\n"))
        printf(" %25s  ONL?: %s\n", "Online",                 removeChars(pi_e517_send($1, "ONL?"), "\n"))
        printf(" %25s  ONT?: %s\n", "On Target",              removeChars(pi_e517_send($1, "ONT?"), "\n"))
        printf(" %25s     tolerance: %s", "", pi_e517_send($1 ,"SPA? A 0X07000900"))
        printf(" %25s     tolerance: %s", "", pi_e517_send($1 ,"SPA? B 0X07000900"))
        printf(" %25s     tolerance: %s", "", pi_e517_send($1 ,"SPA? C 0X07000900"))
        printf(" %25s  NLM?: %s\n", "position low limit",        removeChars(pi_e517_send($1, "NLM?"), "\n"))
        printf(" %25s  PLM?: %s\n", "position high limit",       removeChars(pi_e517_send($1, "PLM?"), "\n"))
        printf(" %25s  POS?: %s\n", "Positions",                 removeChars(pi_e517_send($1, "POS?"), "\n"))
        printf(" %25s  SAI?: %s\n", "Axis identifiers",          removeChars(pi_e517_send($1, "SAI?"), "\n"))
        printf(" %25s  SSN?: %s\n", "Serial Number",             removeChars(pi_e517_send($1, "SSN?"), "\n"))
        printf(" %25s  SVO?: %s\n", "Servo Mode / Closed loop ", removeChars(pi_e517_send($1, "SVO?"), "\n"))
        printf(" %25s  TAD?: %s\n", "ADC Values of input sig. ", removeChars(pi_e517_send($1, "TAD?"), "\n"))
        printf(" %25s  TIO?: %s\n", "Digital I/O lines",         removeChars(pi_e517_send($1, "TIO?"), "\n"))
        printf(" %25s  VCO?: %s\n", "Velocity control mode",     removeChars(pi_e517_send($1, "VCO?"), "\n"))
        printf(" %25s  VEL?: %s\n", "Velocities",                removeChars(pi_e517_send($1, "VEL?"), "\n"))
        printf(" %25s  VER?: %s\n", "Firmware version",          removeChars(pi_e517_send($1, "VER?"), "\n"))
        printf(" %25s  VMA?: %s\n", "Voltage output high limit", removeChars(pi_e517_send($1, "VMA?"), "\n"))
        printf(" %25s  VMI?: %s\n", "Voltage output low limit",  removeChars(pi_e517_send($1, "VMI?"), "\n"))
        printf(" %25s  VOL?: %s\n", "Voltages",                  removeChars(pi_e517_send($1, "VOL?"), "\n"))

        printf(" %25s   Osen 1: %s\n", "Offset sensor 1 (doc p.38)", removeChars(pi_e517_send($1, "SPA? 1 0x02000200"), "\n"))
        printf(" %25s   Osen 2: %s\n", "Offset sensor 2", removeChars(pi_e517_send($1, "SPA? 2 0x02000200"), "\n"))
        printf(" %25s   Osen 3: %s\n", "Offset sensor 3", removeChars(pi_e517_send($1, "SPA? 3 0x02000200"), "\n"))

        printf(" %25s   Ksen 1: %s\n", "Gain sensor 1 (doc p.38)", removeChars(pi_e517_send($1, "SPA? 1 0x02000300"), "\n"))
        printf(" %25s   Ksen 2: %s\n", "Gain sensor 2", removeChars(pi_e517_send($1, "SPA? 2 0x02000300"), "\n"))
        printf(" %25s   Ksen 3: %s\n", "Gain sensor 3", removeChars(pi_e517_send($1, "SPA? 3 0x02000300"), "\n"))


        # printf("        ?: %s\n", removeChars(pi_e517_send(_name, "?"), "\n"))
    }

    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    #   ONL returns 1= 2= 3=
    #   TAD returns 1= 2= 3=
    #   VOL returns 1= 2= 3=
    #
    #   SAI returns A= B= C=
    #   ONT returns A= B= C=
    #   VEL returns A= B= C=
    #   SVO returns A= B= C=


}'




#%UU% (<mot_num>)
#%MDESC%
#    Returns the list of all available parameters.
def pi_e517_get_parameters(mot_num) '{
    local _tcp_dev

    _tcp_dev = pi_e517_get_tcp_dev_by_mot(mot_num)

    if(_tcp_dev == "0"){
        print "ERROR pi_e517_cmd bad motor name or undefdined motor"
        return(-1)
    }

    sock_par(_tcp_dev, "flush")
    pi_e517__debug "SEND \"HPA?\" to " _tcp_dev

    if(pi_e517_put(_tcp_dev, "HPA?") == -1){
        return( -1)
    }

    sleep(0.1)

    if ((_ans = pi_e517_get(_tcp_dev)) == -1){
        return( -1)
    }
    else{
        pi_e517__debug "GET " _ans " from " _tcp_dev

        return(_ans)
    }
}'




#%UU% (<mot_num>, <parma>)
#%MDESC%
#    Returns the value of parameter <param>
def pi_e517_get_parameter(mot_num, param) '{
    local _tcp_dev _chan_letter
    local _tmp_arr[]  _value

    _tcp_dev = pi_e517_get_tcp_dev_by_mot(mot_num)

    if(_tcp_dev == "0"){
        print "ERROR pi_e517_cmd bad motor name or undefined motor"
        return(-1)
    }

    _chan_letter = pi_e517_get_chan_letter(mot_num, 569)

    _cmd = sprintf("SPA? %s %s", _chan_letter, param)

    sock_par(_tcp_dev, "flush")
    pi_e517__debug "SEND " _cmd " to " _tcp_dev

    if(pi_e517_put(_tcp_dev, _cmd) == -1){
        return( -1)
    }

    sleep(0.1)

    if ((_ans = pi_e517_get(_tcp_dev)) == -1){
        return( -1)
    }
    else{
        pi_e517__debug "GET " _ans " from " _tcp_dev

        # _ans looks like : "A 0X07000900=2.00000000e-1"
        split(_ans, _tmp_arr, "=")
        _value = removeEndingChar( _tmp_arr[1], "\n")

        return(_value+0.0)
    }
}'



def pi_e517_get_tolerances '{

    print "Tolerances:"
    printf("A (pz40) %s\n", pi_e517_get_parameter(pz40, "0X07000900"))
    printf("B (pz41) %s\n", pi_e517_get_parameter(pz41, "0X07000900"))
    printf("C (pz42) %s\n", pi_e517_get_parameter(pz42, "0X07000900"))
    printf("A (pz43) %s\n", pi_e517_get_parameter(pz43, "0X07000900"))
    printf("B (pz44) %s\n", pi_e517_get_parameter(pz44, "0X07000900"))
    printf("C (pz45) %s\n", pi_e517_get_parameter(pz45, "0X07000900"))


}'




# Switches axis of motor <mot_mne> to OFFLINE mode to be able to control it manually.

# Controller must be activated in SPEC config...

def pi_e517_set_offline(mot_mne) '{
    local  _channel _mot_num

    _mot_num = motor_num(mot_mne)
    _channel = pi_e517_get_chan_nb(_mot_num)

    # NB: ONL 1st parameter is 1/2/3  (not A/B/C)
    _cmd = sprintf("ONL %d 0", _channel)

    pi_e517_send_no_ans(_mot_num, _cmd)

}'


# Switches axis of motor <mot_mne> to ONLINE mode to be able to control it remotely.
# Controller must be activated in SPEC config...
def pi_e517_set_online(mot_mne) '{
    local  _channel _mot_num

    _mot_num = motor_num(mot_mne)
    _channel = pi_e517_get_chan_nb(_mot_num)

    # NB: ONL 1st parameter is 1/2/3  (not A/B/C)
    _cmd = sprintf("ONL %d 1", _channel)

    pi_e517_send_no_ans(_mot_num, _cmd)

}'


#%UU% ()
#%MDESC%
#
def pi_e517_help '{

    if ($#==0){
        print "please specify a motor num"
        exit
    }
    else{
        printf("  IDN?: %s\n", removeChars(pi_e517_send($1, "IDN?"), "\n"))
        printf("  VER?: %s\n", removeChars(pi_e517_send($1, "VER?"), "\n"))
        printf("  IFC?: %s\n", removeChars(pi_e517_send($1, "IFC?"), "\n"))
        printf("  CSV?: %s\n", removeChars(pi_e517_send($1, "CSV?"), "\n"))
        printf("  ERR?: %s\n", removeChars(pi_e517_send($1, "ERR?"), "\n"))
        printf("  HPA?: %s\n", removeChars(pi_e517_send($1, "HPA?"), "\n"))
    }

}'


#%UU% (<tcp_dev>)
#%MDESC%
#    Returns the *controller* model name (should be E-517)
def pi_e517_get_model(tcp_dev) '{
    local _model  _ans

    _ans = pi_e517_put(tcp_dev, "IDN?")
    sleep(0.01)
    _idn = pi_e517_get(tcp_dev)
    pi_e517__debug "IDN="_idn

    _model = substr(_idn, 21, 5)

    if (_model == "E-517"){
        return("E-517")
    }
    else{
        return("UNKNOWN")
    }
}'


#%IU%
#%MDESC%
#    Checks if controller is responding sending it "IDN?".
#
# Returns  1 if controller is responding.
# Returns  0 if controller is NOT responding.
# Returns -1 in case of error.
#
def pi_e517_check_ctrl(mot_num) '{
    local _tcp_dev

    _tcp_dev = pi_e517_get_tcp_dev_by_mot(mot_num)

    if(pi_e517_put(_tcp_dev, "IDN?") == -1){
        return (-1)
    }

    if ((_ans = pi_e517_get(_tcp_dev)) == -1){
        return (-1)
    }
    else{
        print _ans
    }

    return (1)
}'


#%IU%
#%MDESC%
# Converts channel from digit to single char.
# 1 -> "A"
# 2 -> "B"
# 3 -> "C"
def pi_e517_getch(ch) '{

    pi_e517__debug "pi_e517_getch for " ch

    if(ch==1) {
        return("A")
    }

    if(ch==2) {
        return("B")
    }

    if(ch==3) {
        return("C")
    }

    print PI_E517_HEAD"ERROR: \""mne"\" wrong channel, only 3 axis are supported"
    return(-1)
 
}'


######################################################################
############################               ###########################
############################  MACRO MOTOR  ###########################
############################               ###########################
######################################################################

#%IU%
#%MDESC%
#    Called by spec after reading the config file
#
def pi_e517_config(mot_num, type, p1, p2, p3) '{
    local _tcp_dev  _msg  _msg2
    local _velocity
    local _cmd

    _tcp_dev = sprintf("%s:50000", pi_e517_ADDR)

    pi_e517__debug "Using controller E517, @="_tcp_dev

    if(type=="ctrl") {
        local _model

        print ""

        # p1==controller number (0..N)
        # p2==number of motors supported (1..M)

        _msg   = sprintf("p1=\"%s\" p2=\"%s\"", p1, p2)
        _msg2  = sprintf("addr=\"%s\"", _tcp_dev)

        # Opens a socket to the specified host and port.
        # Returns 1 for success and 0 for failure.
        sock_par(_tcp_dev, "close")
        if (sock_par(_tcp_dev, "connect") == 1){

            # Controller model
            _model = pi_e517_get_model(_tcp_dev)

            if(_model == "E-517"){
                printf("[PI_E517] Using controller piezo PI ")
                cprint(_model, 4, 8)
                printf("  address = %s\n", _tcp_dev)

                motor_par(mot_num, "model", _model, "add")
            }
            else{
                pi_e517_err(sprintf( "WRONG MODEL : %s", _model))
            }
        }
        else{
            _msg = sprintf("Controller piezo E517 on address %s is not responding \n", _tcp_dev)
            pi_e517_err( _msg)

            # -> will not configure motors attached to this controller.
            return (".error.")
        }
    }
    else if(type=="mot") {
        # p1==unit p2==module p3==channel
        local _cmd
        local _mot_nb  _channel  _chan_letter

        # channel : 1..3
        _channel = p3 + 1

        # channel letter : A..C
        _chan_letter = pi_e517_getch(_channel)
        _msg = sprintf("Motor %d (%s) : chan %d (%s)",  \
                       mot_num, motor_mne(mot_num),     \
                       _channel, _chan_letter )
        pi_e517__debug _msg


        # Saves tcp dev controller in a custom parameter of the motor.
        motor_par(mot_num, "tcp_dev", _tcp_dev, "add")

        _msg  = sprintf("p1=\"%s\" p2=\"%s\" p3=\"%s\"", p1, p2, p3)

        printf( "[PI_E517]  \"%s\"  Configuring motor (ctrl=\"%s\") %s \n", \
                motor_mne(mot_num), _tcp_dev, _msg)

        # Saves channel letter as "chan_letter" motor parameter.
        motor_par(mot_num, "chan_letter", _chan_letter, "add")

        # Saves channel as "channel" motor parameter.
        pi_e517__debug "saving \"chan_nb\" parameter " _channel " for motor " mot_num
        motor_par(mot_num, "chan_nb", _channel, "add")


        # Switches axis to ONLINE mode to be able to control it by commands.
        # NB: ONL 1st parameter is 1/2/3  (not A/B/C)
        _cmd = sprintf("ONL %d 1", _channel)
        pi_e517_send_no_ans(mot_num, _cmd)

        # Displays the status of the closed loop.
        printf("[PI_E517]   \"%s\"  Closed loop is ", motor_mne(mot_num))
        cprint_on_off(pi_e517_get_closed_loop_status(mot_num))
        print ""

        # Activates the Velocity Control (VCO) for security :
        # It avoids to do brutal moves.
        # NB: VCO 1st parameter is A/B/C
        _cmd = sprintf("VEL? %s", _chan_letter)
        _velocity = removeChars(pi_e517_send(mot_num, _cmd), "\n")

        printf("[PI_E517]    \"%s\"  Velocity control activated for chan %s  (speed: %s) \n", \
               motor_mne(mot_num), _chan_letter, _velocity)

        _cmd = sprintf("VCO %s 1", _chan_letter)
        pi_e517_send_no_ans(mot_num, _cmd)


    }
    else {
        print PI_E517_HEAD"pi_e517_config() : unknown type : " type
    }
}'


#  Valid PIEZO parameters for E517+E509+E505
#
#  321.NINA> p pi_e517_send("ctrl0","HPA?")
#  The following parameters are valid:
#  0X02000000=     1       3       INT     Sensor Mechanic.        Sensor enable   0 = Disabled    1 = Enabled
#  0X02000200=     0       3       FLOAT   Sensor Mechanic.        Sensor correction 0 order (offset)
#  0X02000300=     0       3       FLOAT   Sensor Mechanic.        Sensor correction 1st order (gain)
#  0X04000500=     2       6       FLOAT   ADC.    ADC gain
#  0X04000600=     2       6       FLOAT   ADC.    ADC offset
#  0X04000700=     2       6       FLOAT   ADC.    HW gain
#  0X04000800=     2       6       FLOAT   ADC.    HW offset
#  0X04000E00=     1       6       CHAR    ADC.    LCD unit
#  0X04000E01=     1       6       INT     ADC.    LCD format
#  0X05000000=     0       3       INT     Sensor Filter.  Digital filter type
#                0 = No Filter   1 = IIR Filter  2 = FIR filter  99 = User
#  0X05000001=     0       3       FLOAT   Sensor Filter.  Digital filter Bandwidth
#  0X05000002=     0       3       INT     Sensor Filter.  Digital filter order



#   
#   1003.NINA> p pi_e517_send(pz40, "HLP?")
#   The following commands are valid:
#   #5      -       Request motion status
#   #6      -       Query if position has changed since last POS?
#   #7      -       Request controller ready status
#   #8      -       Query if macro is running
#   #9      -       Get wave generator status
#   #24     -       Identical in function to STP
#   *IDN?   -       Get device identification
#   CCL     <Level> [<PSWD>]        Set command level
#   CCL?    -       Get command level
#   CSV?     -      Get GCS syntax version
#   CTO     {<TrigOutID> <CTOPam> <Value>}  Set configuration of trigger output
#   CTO?    [{<TrigOutID> <CTOPam>}]        Get configuration of trigger output
#   CTI     {<TrigInID> <CTIPam> <Value>}   Set configuration of trigger input
#   CTI?    [{<TrigInID> <CTIPam>}] Get configuration of trigger input
#   DCO     {<AxisID> <DCOState>}   Set drift compensation mode (0/1)



#%IU%
#%MDESC%
#    Called by spec on motor operation.
# p1 = ?
def pi_e517_par(mot_num, key, todo, p1) '{
    local _srv  _cmd  _ans _velocity
    local _chan_letter  _channel

    # _chan_letter = pi_e517_get_chan_letter(mot_num, 739)
    _channel = motor_par(mot_num, "channel")
    _chan_letter = pi_e517_getch(_channel + 1)

    _msg = sprintf("in pi_e517_par mot_num=%d key=%s todo=%s p1=%s", \
                   mot_num, key, todo, p1)
    pi_e517__debug _msg

    # print "***pi_e517_par " mot_num"," key"," todo"," p1
    # Returns new motor_par() argins handled
    if (key == "?" && todo == "get") {
        return("servo")
    }

    #PC: when is this called by spec?
    if (key == "servo") {
        # Handles the piezo closed loop.

        # !! si on veut fermer/ouvrir la boucle par soft il faut que le switch du
        # controleur soit en position open.

        if (todo == "set") {
            _cmd = sprintf("SVO %s %d", _chan_letter, (p1?1:0))
            pi_e517_send_no_ans(mot_num, _cmd)
        }

        _cmd = sprintf("SVO?")
        if((_ans = pi_e517_send(mot_num, _cmd)) == ".error.") {
            return(0)
        }

        sscanf(_ans, "A=%f", _srv)

        return(_srv)
    }

    if(key == "slew_rate" || key == "velocity"){
        # SET / GET velocity
        # Not called automatically on a reconfig...

        # Called on first move.

        if (todo == "set") {
            pi_e517__debug "pi_e517_par :slew_rate/velocity " p1

            if (p1 > 10) {
                print "Achtung pi_e517 velocity is :" p1
            }

            # Velocity is integer number like this
            # Too coarse 1 um/s
            _cmd = sprintf("VEL %s %f", _chan_letter, p1)
            pi_e517_send_no_ans(mot_num, _cmd)

        }
        else if(todo == "get"){
            _cmd = sprintf("VEL? %s", _chan_letter)
            if((_ans = pi_e517_send(mot_num, _cmd)) == ".error.") {
                return(0)
            }
            sscanf(_ans, "A=%f", _velocity)

            return(_velocity)
        }
    }
}'


#%IU%
#%MDESC%
# MACRO MOTOR:
# Called by spec on motor operation.
#
def pi_e517_cmd(mot_num, key, p1, p2) '{

    # print ">>> pi_e517_cmd "mot_num"," key"," p1"," p2

    if(mot_num == "..") {
        return(0)
    }

    # Returns the current motor position in mm or deg
    if (key == "position") {
        local pos
        pos = pi_e517_get_pos(mot_num)

        pi_e517__debug "position() : pos    :  " pos " micron"
        return(pos)
    }

    # Starts a motion (p1==abs pos, p2==rel pos, with pos in mm or deg)
    if (key == "start_one") {
        local aux

        pi_e517__debug "start_one(): pos     :  "p1" micron"
        pi_e517_set_pos(mot_num, p1)

        # ???
        if((t=motor_par(mot_num, "deadtime")) != 0) {
            pi_e517__debug "start_one(): sleeping:  "t" seconds"
            sleep(t)
        }
    }

    # Status
    if (key == "get_status") {
        _status = pi_e517_get_status(mot_num)

        if (_status == 0) {
            # print "moving" mot_num
            return (0x02)
        }
        else {
            # printf(" %s is on-target\n", motor_mne(mot_num))
            sleep(0.1)
            return(0)
        }
    }

    # Stops a single motor.
    if (key == "abort_one") {
        pi_e517__debug "pi_e517_cmd abort_one()"
        pi_e517_stop(mot_num)

        return(1)
    }

    # SET velocity on first move (not on a reconfig).
    if(key == "slew_rate" || key == "velocity"){
        _chan_letter = pi_e517_get_chan_letter(mot_num, 853)

        pi_e517__debug "pi_e517_par :slew_rate/velocity " p1

        if (p1 > 10) {
            print "Achtung velocity is :" p1
        }

        _cmd = sprintf("VEL %s %d", _chan_letter, p1)
        pi_e517_send_no_ans(mot_num, _cmd)

    }
}'



######################################################################
######################                          ######################
######################  POSITION MACRO COUNTER  ######################
######################                          ######################
######################################################################

#%IU%
#%MDESC%
# Called by spec after reading the config file
#
def pi_e517_c_config(count_num, type, p1, p2, p3) '{

    #
    if(type=="ctrl") {
        # ?
    }

    #
    if(type=="cnt") {
        local _mot_mne _mot_num

        _cnt_mne = cnt_mne(count_num)
        _mot_num = counter_par(count_num, "motor")
        _mot_mne = motor_mne(_mot_num)

        if((mot_num = motor_num(_mot_mne)) == -1) {
            pi_e517_err(sprintf( "invalid motor name parameter %s  for counter %s",\
                                 _mot_mne,_cnt_mne))
        }

    }
}'


#%IU%
#%MDESC%
# Called by spec on counter operation.
#
def pi_e517_c_cmd(count_num,key,p1,p2) '{

    if (key == "counts") {
        local _pos  _mot_num  _mot_mne  _cnt_mne

        _cnt_mne = cnt_mne(count_num)
        _mot_num = counter_par(count_num, "motor")
        _mot_mne = motor_mne(_mot_num)

        pi_e517__debug "pi_e517_c_cmd : counts for counter " _cnt_mne
        pi_e517__debug "                  get pos of motor " _mot_mne

        _pos = pi_e517_get_read_pos(_mot_num)

        return(_pos)
    }
}'



######################################################################
#######################                         ######################
#######################  VOLTAGE MACRO COUNTER  ######################
#######################                         ######################
######################################################################

#%IU%
#%MDESC%
# Called by spec after reading the config file
#
def pi_e517_v_config(count_num, type, p1, p2, p3) '{

    #
    if(type=="ctrl") {
        # ?
    }

    #
    if(type=="cnt") {
        local _mot_mne _mot_num

        _cnt_mne = cnt_mne(count_num)
        _mot_num = counter_par(count_num, "motor")
        _mot_mne = motor_mne(_mot_num)

        _msg = sprintf("for counter %d(%s) motor num=%d (%s)",  \
                       count_num, _cnt_mne, _mot_num, _mot_mne)

        if((mot_num = motor_num(_mot_mne)) == -1) {
            pi_e517_err(sprintf("invalid motor name parameter %s for counter %s ", \
                                _mot_mne,_cnt_mne))
        }
    }
}'


#%IU%
#%MDESC%
# Called by spec on counter operation.
#
def pi_e517_v_cmd(count_num,key,p1,p2) '{

    if (key == "counts") {
        local _pos  _mot_num  _mot_mne  _cnt_mne

        _cnt_mne = cnt_mne(count_num)
        _mot_num = counter_par(count_num, "motor")
        _mot_mne = motor_mne(_mot_num)

        pi_e517__debug "pi_e517_v_cmd : counts for counter " _cnt_mne
        pi_e517__debug "                  get pos of motor " _mot_mne

        _pos = pi_e517_get_voltage(_mot_num)

        return(_pos)
    }
}'


#
#%MACROS%
#%IMACROS%
#%AUTHOR% MP CG BLISS 2012 2013
#%TOC%