esrf

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

#%TITLE% followmot.mac
#%NAME%
#
#%CATEGORY%
#%DESCRIPTION%
#   This macro set implement the structure for SPEC motors (followers) which should
#   change their position according to the position of a master SPEC motor.
#   3 types of behavior are implemented for a follower and can be changed dynamically.
#       1 - single:
#           when the master is moving, position of the follower is calculated
#           and set in the A[] SPEC array in order the follower will start its
#           movement with the Master
#
#       2 - sync:
#           the movement of the follower have to be done in the same time of the
#           master movment (synchronized start and stop of the movement).
#           This case is mainly used during zapenergy scan in which followers must
#           be at their optimum value during all the mOvement of the master motor.
#
#       3 - sbs (Step By Step):
#           During the Master movement, the follower will calclculate and move
#           according to the changing Master position as fast as possible.
#           The reading loop of the master position is not implement in this
#           macro set.
#           This case is mainly used during zapenergy scan when the speed of
#           followers and the master cannot fit.
#
#       Case 1 is validated using the "followmot_add" macro
#       Case 2 is validated using the "followmot_sync" macro
#       Case 3 is validated using the "followmot_sbs" maccro
#
#       In each case, specifi macros for each followers should be provided. Needed
#       values to calculate parameters and positions of the followers will be set
#       in the FOLLOWMOT_PAR[] SPEC associative array. The resulting followers
#       positions will be stored in the FOLLOWMOT_LIST manage bi stlist.mac
#       macro set
#
#       Message, Debug and Error macros are generated using hg.mac macro set
#
#%EXAMPLE%
#%DL%
#%DT%XXXsetup%DD%
#%SETUP%
#%UL%
#%LI%
#%XUL%

need hg

hg_generate("followmot")


##############################################################################
##########                                                          ##########
##########                MACROS CALLED FROM SPEC                   ##########
##########                                                          ##########
##############################################################################

#%IU%
#%MDESC%
#   Definition of global variables
#
def followmot_setup '{
    # FOLLOWMOT parameters
    global FOLLOWMOT_PAR[]
    # FOLLOWMOT_PAR["master_pos"] --> contains the new master position value to
    #                                 calculate followers position
    #
    # FOLLOWMOT_PAR["master_start"]   |
    # FOLLOWMOT_PAR["master_stop"]    |-->  information on the master movement to synchronize
    # FOLLOWMOT_PAR["master_movtime"] |     interrested followers
    # FOLLOWMOT_PAR["master_acctime"] |

    # List of motors used as followers.
    global FOLLOWMOT_LIST[]

    list_init FOLLOWMOT_LIST


    if($# > 0) {
       FOLLOWMOT_PAR["master_mne"] = "$1"
    }


}'


# Definition of the macro which will contain all the follower.s
# calculation macros
cdef("users_followmot_calc_pos", "", "")

#%UU% (<mot_mne>, <desc>, <func>)
#%MDESC%
#   add a followers.
#   <mot_mne> must refers to SPEC configured motor
#   <func> must be defined
#
def followmot_add(mot_mne, desc, func) '{

    if (motor_num(mot_mne) == -1) {
        printf("Motor \"%s\" not configured, exit !!\n", mot_mne)
        exit
    }

    if ((whatis(func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", func)
        exit
    }

    if (!list_check(FOLLOWMOT_LIST, mot_mne)) {
        list_add(FOLLOWMOT_LIST, mot_mne)
    }

    list_setpar(FOLLOWMOT_LIST, mot_mne, "desc", desc)
    list_setpar(FOLLOWMOT_LIST, mot_mne, "sync", 0)
    list_setpar(FOLLOWMOT_LIST, mot_mne, "sbs",  0)
    list_setpar(FOLLOWMOT_LIST, mot_mne, "mode", "single")

    cdef("users_followmot_calc_pos", sprintf("%s\n", func), mot_mne)

}'


# Definition of the macro which will contain all the follower.s
# macros to synchronize their movement to the master movement
cdef("users_followmot_setparam", "", "")
cdef("users_followmot_moveparam", "", "")
cdef("users_followmot_restoreparam", "", "")
cdef("users_followmot_checkspeed", "", "")
#%UU% (<mot_mne>, <set_param_func>, <restore_param_func>)
#%MDESC%
#   Allow follower <mot_mne> to adapt its movement to fit the master movement
#   <mot_mne> must refer to a valid follower
#   <set_param_func> will set the necessary follower parameters
#   <restore_param_func> will restore the follower changed parameters
#
def followmot_sync(mot_mne, set_func, move_func, restore_func, check_func) '{

    if (!list_check(FOLLOWMOT_LIST, mot_mne)) {
        printf("\"%s\" is not a valid follower, exit !!!\n", mot_mne)
        exit
    }

    if ((whatis(set_func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", set_func)
        exit
    }

    if ((whatis(move_func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", move_func)
        exit
    }

    if ((whatis(restore_func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", restore_func)
        exit
    }

    if ((whatis(check_func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", check_func)
        exit
    }

    list_setpar(FOLLOWMOT_LIST, mot_mne, "sync", 1)

    cdef("users_followmot_setparam"    , sprintf("%s\n", set_func),     mot_mne)
    cdef("users_followmot_moveparam"   , sprintf("%s\n", move_func),    mot_mne)
    cdef("users_followmot_restoreparam", sprintf("%s\n", restore_func), mot_mne)
    cdef("users_followmot_checkspeed"  , sprintf("%s\n", check_func),   mot_mne)
}'

# Definition of the macro which will contain all the follower's macros to
# move outside of spec in Step-By-Step mode
cdef("users_followmot_sbs_move", "", "")

#%UU% (<mot_mne>, <sbs_func>, <register_func>)
#%MDESC%
#   Followers will move outside to the value calculated from
#   the master position stored in FOLLOWMOT_PAR["master_pos"].
#   A <register_func> may be provided to register in ZAP arrays the position
#   of each movement
#
def followmot_sbs(mot_mne, sbs_func) '{

    if (!list_check(FOLLOWMOT_LIST, mot_mne)) {
        printf("\"%s\" is not a valid follower, exit !!!\n")
        exit
    }

    if ((whatis(sbs_func) & 2) != 2) {
        printf("Macro \"%s\" not defined, exit !!\n", set_param_func)
        exit
    }

    list_setpar(FOLLOWMOT_LIST, mot_mne, "sbs", 1)
    cdef("users_followmot_sbs_move", sprintf("%s\n", sbs_func), mot_mne)
}'



#%UU%
#%MDESC%
#   Display all configured followers
#
def followmot_show '{
    local ifmot

    printf(" O------------- FOLLOWMOT ----------\n")
    printf(" |   motor  |    status  |     desc.\n")
    printf(" O----------------------------------\n")
    printf(" | master : %s                  \n", FOLLOWMOT_PAR["master"])
    printf("  ..................................\n")

    for (ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        printf(" |%8s  | %10s |  %s \n",                          \
               FOLLOWMOT_LIST[ifmot],                                   \
               list_getpar(FOLLOWMOT_LIST, ifmot, "active")?" [active] ":"[inactive]", \
               list_getpar(FOLLOWMOT_LIST, ifmot, "desc"))
    }
    printf("  ---------------------------------\n")

}'

##############################################################################
##########                                                          ##########
##########                    MONO MACRO MOTOR                      ##########
##########                                                          ##########
##############################################################################
#%IU% (new_master_pos)
#%MDESC%
#   Set A[] array of all the active follower's according to new master position
#   This macro is call in the Master Macro motor
#
def followmot_move(new_master_pos)'{
    local ifmot  fmot_mne  fmot_num msg fm_act fm_mode

    followmot_master_setpos(new_master_pos)

    # Followers movements.
    for (ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        fmot_mne = followmot_getname(ifmot)
        fmot_num = motor_num(fmot_mne)
        fm_mode = followmot_getmode(fmot_mne)

        if (followmot_isactive(fmot_mne) && (fm_mode == "single")) {

            A[fmot_num] = followmot_getpos(fmot_mne)

            followmot_dbg(sprintf("Should move %s to %g", fmot_mne, A[fmot_num]))

        } else {
            fm_act = list_getpar(FOLLOWMOT_LIST, ifmot, "active")?"active":"inactive"
            msg = sprintf("Follower \"%s\" is %s and mode is %s", fmot_mne, fm_act, fm_mode)
            followmot_dbg(msg)
        }
    }
}'

#%IU% (new_master_pos)
#%MDESC%
#   Set the new master position and call all follower's calculation macros.
#   For each follower, the parameter "position" in the FOLLOWMOT_LIST will be set
#
def followmot_master_setpos(new_master_pos)'{
    FOLLOWMOT_PAR["master_pos"] = new_master_pos

    users_followmot_calc_pos
}'

#%IU% (mot_mne)
#%MDESC%
#   return the "position" parameter of the FOLLOWMOT_LIST for <mot_mne> follower
#   -999999 if the <mot_mne> is not a valid follower
#
def followmot_getpos(mot_mne)'{
    if (list_check(FOLLOWMOT_LIST, mot_mne)) {
        return(list_getpar(FOLLOWMOT_LIST, mot_mne, "position"))
    } else {
        printf("\"%s\" is not a valid follower\n", mot_mne)
        return(-999999)
    }
}'

def followmot_getminspeed() '{
    local ifmot fmot_mne fmot_num fm_sync_allowed min_speed

    # Followers movements.
    for (min_speed=1000000,ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        fmot_mne = followmot_getname(ifmot)
        fmot_num = motor_num(fmot_mne)
        fm_sync_allowed = list_getpar(FOLLOWMOT_LIST, fmot_mne, "sync")
        if (followmot_isactive(fmot_mne) && fm_sync_allowed) {
            fmot_speed = list_getpar(FOLLOWMOT_LIST, fmot_mne, "min_speed")
            if (min_speed > fmot_speed) {
                min_speed = fmot_speed
            }
        }
    }

    return(min_speed)
}'

def followmot_checkspeed(en_from, en_to, en_time) '{
    local ifmot fmot_mne fmot_num fm_sync_allowed fm_ok

    FOLLOWMOT_PAR["e_from"]  = en_from
    FOLLOWMOT_PAR["e_to"]    = en_to
    FOLLOWMOT_PAR["e_time"]  = en_time

    users_followmot_checkspeed

    # Followers movements.
    for (fm_ok=1,ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        fmot_mne = followmot_getname(ifmot)
        fm_sync_allowed = list_getpar(FOLLOWMOT_LIST, fmot_mne, "sync")
        if (followmot_isactive(fmot_mne) && fm_sync_allowed) {
            fmot_ok &= list_getpar(FOLLOWMOT_LIST, fmot_mne, "check_speed")
        }
    }

    return(fm_ok)
}'

##############################################################################
##########                                                          ##########
##########                 FOLLOWMOT TOOLS MACROS                   ##########
##########                                                          ##########
##############################################################################

#%UU% (<mot_mne>)
#%MDESC%
#   Remove item <mot_mne> from the followers list
#
def followmot_del(mot_mne) '{
    if (list_check(FOLLOWMOT_LIST, mot_mne)) {

        cdef("users_followmot_setparam", "", mot_mne, "delete")
        cdef("users_followmot_restoreparam", "", mot_mne, "delete")

        if (list_getparam(FOLLOWMOT_LIST, mot_mne, "sync")) {
            cdef("users_followmot_setparam", "", mot_mne, "delete")
            cdef("users_followmot_restoreparam", "", mot_mne, "delete")
        }

        if (list_getparam(FOLLOWMOT_LIST, mot_mne, "sbs")) {
            cdef("users_followmot_sbs_move", "", mot_mne, "delete")
        }

        list_remove(FOLLOWMOT_LIST, mot_mne)
    }
}'

#%IU% (mot_mne)
#%MDESC%
#   return the active state of the <mot_mne> follower
#
def followmot_isactive(_mot_mne)'{

    if (list_check(FOLLOWMOT_LIST, _mot_mne)) {
        # print list_check(FOLLOWMOT_LIST, _mot_mne)
        return(list_getpar(FOLLOWMOT_LIST, _mot_mne, "active"))
    }

    return(0)
}'

#%UU% (<motmne>)
#%MDESC%
#   Enable follower <motmne> if configured
#
def followmot_enable(motmne) '{
    if (list_check(FOLLOWMOT_LIST, motmne)) {
        list_setpar(FOLLOWMOT_LIST, motmne, "active", 1)
    }
    else{
        followmot_err(sprintf("followmot_enable() : %s motor not in followers list.", motmne))
    }
}'


#%UU% (<motmne>)
#%MDESC%
#   Disable follower <motmne> if configured
#
def followmot_disable(motmne) '{
    if (list_check(FOLLOWMOT_LIST, motmne)) {
        list_setpar(FOLLOWMOT_LIST, motmne, "active", 0)
    }
}'


#%UU% ()
#%MDESC%
#   Enable all followers
#
def followmot_enable_all() '{
    for (ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        followmot_enable_all(FOLLOWMOT_LIST[ifmot])
    }
}'


#%UU% ()
#%MDESC%
#   Disable all followers
#
def followmot_disable_all() '{
    local ifmot

    for (ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        followmot_disable(FOLLOWMOT_LIST[ifmot])
    }
}'

#%UU% (<motmne>, <follow_mode>)
#%MDESC%
#   Set movement mode for followers.
#   mode are "single" or "sbs"
#   In mode "single", the follower will move to the calculated position one time
#   starting with the master motor
#   In mode "sbs", during Master movement, follower position wil be constantly recalculted
#   and follower will move ecah time to its new position.
#
def followmot_setmode(motmne, follow_mode) '{
    if (list_check(FOLLOWMOT_LIST, motmne)) {
        list_setpar(FOLLOWMOT_LIST, motmne, "mode", follow_mode)
    }
}'

#%UU% (<motmne>)
#%MDESC%
#   return movement mode for followers.
#   mode are "single" or "sbs"
#
def followmot_getmode(motmne) '{
    if (list_check(FOLLOWMOT_LIST, motmne)) {
        return(list_getpar(FOLLOWMOT_LIST, motmne, "mode"))
    }
}'


#%IU% (mot_mne)
#%MDESC%
#   return the list of followers mnemonic
#
def followmot_getdependant() '{
    local ifmot fm_list

    for (fm_list="",ifmot=1 ; ifmot <= list_n(FOLLOWMOT_LIST) ; ifmot++) {
        fmot_mne = followmot_getname(ifmot)
        fm_list = sprintf("%s %s ", fm_list, fmot_mne)
    }
    return(fm_list)
}'

#%IU% (ind)
#%MDESC%
#   return the motor name of the follower's at index <ind> in the FOLLOWMOT_LIST list
#
def followmot_getname(ind)'{
    return(FOLLOWMOT_LIST[ind])
}'