esrf

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

#%TITLE% MOCO.MAC
#
#%NAME%
#  MOCO.MAC - Macros for operating and testing the MoCo unit
#
#%CATEGORY% Isg, Other hardware
#
#%OVERVIEW%
#  This macro set allows to set MoCo isgdevices in %B%spec%B%, configure
#  their analog outputs as a pseudomotors, their signal inputs as
#  pseudocounters and provide simple macros for basic operation.
#  %BR%
#  An interactive macro %B%moco%B% can be used for device configuration and
#  monitoring.
#  %BR%
#  More than one MoCo unit can be operated through this macro set.
#
#%EXAMPLE%
#  %DL%
#  %DT%mocosetup mocopiezo 2 inbeam=inb outbeam=outb
#  %DD%Configures a MoCo unit connected to the serial line #2 and assigns the
#      name \"mocopiezo\" to it . Associates the INBEAM and OUTBEAM input
#      channels to the pseudocounters inb and outb.
#  %DT%mocosetup pitch id33/serlin/11 scale=0.001
#  %DD%Configures a MoCo unit associated to the TACO device \"id33/serlin/11\"
#      and selects a scale factor of 0.001 for the pitch pseudomotor
#  %DT%moco
#  %DD%Starts the interactive test program with the default unit.
#  %DT%mococonfig setpoint=0.9 sspeed=5
#  %DD%Sets the regulation setpoint value to 90% and the scaning speed to
#      5 volts per second.
#  %DT%mocotune pitch
#  %DD%Starts a tuning procedure in the unit called \"pitch\". This unit
#      becomes the default one.
#  %XDL%
#
#%DEPENDENCIES%
#  These macros make use of the following macro sets:
#  %UL%
#  %LI%stlist.mac
#  %LI%isgdevice.mac
#  %LI%isg.mac
#  %XUL%

#%SETUP%
# A %B%mocosetup%B% macro must be included in the setup file for every MoCo
# unit configured. Each unit is identified by its name that must be a unique
# isgdevice identifier.
#%END%

jtdo("isgdevice.mac")
jtdo("isg.mac")
jtdo("machinfo.mac")

#%UU% <moco_name> <serline> [<parameter>=<value> ...]
#%MDESC%
#  Configures a mocounit connected to <serline> with the name <moco_name>. If
#  <moco_name> is also a valid motor mnemonic with no associated motor
#  controller, it gets configured as pseudocounter driving the piezo output.
#  The following optional parameters can be also set.
#  %UL%
#  %LI%Valid parameters:%DL%
#    %DT%address=<addr>
#    %DD%This parameter allows to address a particular unit when the serial
#        line is shared by several isgdevices in dasychain.
#        If <addr> is a non-numerical value, it is treated as the isgdevice
#        address set by the ADDR command and stored internally in the unit.
#        On the other hand if <addr> is a numerical value it indicates the
#        relative position of the module in the serial line chain starting
#        from 0.
#        If this parameter is not specified, %B%spec%B% looks for the
#        first MoCo unit in the chain.
#    %DT%scale=<scale_factor>
#    %DD%Sets the scale factor for the piezo pseudomotor to <scale_factor>.
#        The default is 1.
#    %DT%rtime=<read_time>
#    %DD%Sets the maximum update time in seconds for the piezo pseudomotor
#        position. If set to 0, the piezo position is read from the unit at
#        every \"wa\" or at every scan point. If set to -1, the unit position
#        is read only when the pseudomotor is moved.
#        The default is 10 seconds.
#    %DT%outbeam=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as OUTBEAM
#        pseudocounter. The \"Scale Factor\" value in the %B%spec%B% config
#        file applies.
#    %DT%inbeam=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as INBEAM
#        pseudocounter. The \"Scale Factor\" value in the %B%spec%B% config
#        file applies.
#    %DT%foutbeam=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as OUTBEAM
#        filtered pseudocounter. The \"Scale Factor\" value in the %B%spec%B%
#        config file applies.
#    %DT%finbeam=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as the
#        INBEAM filtered pseudocounter. The \"Scale Factor\" value in the
#        %B%spec%B% config file applies.
#    %DT%sum=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the sum of the INBEAM and OUTBEAM values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%fsum=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the sum of the INBEAM and OUTBEAM filtered values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%diff=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the difference of the INBEAM and OUTBEAM values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%fdiff=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the difference of the filtered INBEAM and OUTBEAM values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%ratio=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the ratio of the OUTBEAM and INBEAM values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%fratio=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as a
#        pseudocounter holding the ratio of the OUTBEAM and INBEAM filtered values.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%cpiezo=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as the
#        pseudocounter holding the output voltage (?PIEZO).
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%oscmain=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as the
#        pseudocounter holding the main component used for regulation in
#        oscillation mode.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%oscquad=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as the
#        pseudocounter holding the quadrature component in oscillation mode.
#        The \"Scale Factor\" value in the %B%spec%B% config file applies.
#    %DT%softbeam=srcur
#    %DD%Selects the value of the Storage Ring as software normalisation value.
#    %DT%update=<update_time>
#    %DD%Sets the update time in seconds for the interactive macro (moco).
#        The default is 2 seconds.
#    %DT%runforever[=yes]
#    %DD%Runs the interactive macro (moco) in \"forever\" mode.
#    %XDL%
#  %XUL%
def mocosetup '{
   local retval

   if ($# == 0 || (retval = _mocosetup("$*"))) {
      if (SETUP) print "Error in line: $0 $*"
      if (retval < 0) {
         print "Usage:  $0 piezo_mne serial_line [parameter=value ...]"
         if (yesno("\nDisplay online help", 0)) eval("help local moco")
      }
   }
}'


def _mocosetup(args) '{
   global MOCO[]
   global MOCO_AUX[]

   local i nparam auxlist0[] auxlist1[] larr
   local serlin isgdev isgname
   local inbeam_mne outbeam_mne finbeam_mne foutbeam_mne
   local sum fsum diff fdiff ndiff fndiff ratio fratio
   local sum_mne fsum_mne diff_mne fdiff_mne ndiff_mne fndiff_mne ratio_mne fratio_mne
   local oscmain oscquad oscmain_mne oscquad_mne
   local numb mne macrodef aux aux2
   local inb outb finb foutb piezo
   local key cpiezo

   nparam = split(args, auxlist0)
   for (i = 0; i < nparam; i++) {
      if (split(auxlist0[i], larr, "=") > 1){
         delete auxlist0[i]
         auxlist1[larr[0]] = larr[1]
      } else if (i > 1) {
         delete auxlist0[i]
         auxlist1[larr[0]] = "yes"
      }
   }
   if (!((0 in auxlist0) && (1 in auxlist0))) {
      printf("Bad parameters\n")
      return(-1)
   }
   isgname = auxlist0[0]
   serlin = auxlist0[1]

   if ("address" in auxlist1){
      if (auxlist1["address"] + 0 == auxlist1["address"])
         isgdev = isgdevice_add(isgname, serlin , 0, auxlist1["address"])
      else
         isgdev = isgdevice_add(isgname, serlin , 1, auxlist1["address"])
      delete auxlist1["address"]
   } else
      isgdev = isgdevice_add(isgname, serlin , 3, "MOCO")

   if (isgdev <= 0 || isgdevice_check(isgname, 3, "MOCO") == 0) {
      printf("No MoCo device found at serial port : %s\n", serlin)
      return(1)
   }

   if (MOCO_AUX["setup_n"] != SETUP_N) {
      list_init MOCO
      MOCO_AUX["setup_n"] = SETUP_N
   }

   piezo = motor_num(isgname)
   if (piezo < 0 || motor_par(piezo,"controller") != "NONE")
      piezo = -1

   if (list_add(MOCO, isgname) <= 0) {
      printf("Invalid moco/piezo name: %s\n", isgname)
      return(-1)
   }

   MOCO[isgname]["setup"] = "mocosetup " args

   sscanf(isgdevice_comm(isgname, "?VER"), "MOCO %s", MOCO[isgname]["version"])

   outb = ("outbeam" in auxlist1)? cnt_num(mne = auxlist1["outbeam"]) : -1
   delete auxlist1["outbeam"]
   outbeam_mne = (outb >=0 && counter_par(outb,"controller")=="NONE")? mne:-1

   inb = ("inbeam" in auxlist1)? cnt_num(mne = auxlist1["inbeam"]) : -1
   delete auxlist1["inbeam"]
   inbeam_mne = (inb >=0 && counter_par(inb,"controller")=="NONE")? mne: -1

   foutb = ("foutbeam" in auxlist1)? cnt_num(mne = auxlist1["foutbeam"]) : -1
   delete auxlist1["foutbeam"]
   foutbeam_mne=(foutb >=0 && counter_par(foutb,"controller")=="NONE")? mne:-1

   finb = ("finbeam" in auxlist1)? cnt_num(mne = auxlist1["finbeam"]) : -1
   delete auxlist1["finbeam"]
   finbeam_mne=(finb >=0 && counter_par(finb,"controller")=="NONE")? mne:-1

   sum = ("sum" in auxlist1)? cnt_num(mne = auxlist1["sum"]) : -1
   delete auxlist1["sum"]
   sum_mne=(sum >=0 && counter_par(sum,"controller")=="NONE")? mne:-1

   fsum = ("fsum" in auxlist1)? cnt_num(mne = auxlist1["fsum"]) : -1
   delete auxlist1["fsum"]
   fsum_mne=(fsum >=0 && counter_par(fsum,"controller")=="NONE")? mne:-1

   diff = ("diff" in auxlist1)? cnt_num(mne = auxlist1["diff"]) : -1
   delete auxlist1["diff"]
   diff_mne=(diff >=0 && counter_par(diff,"controller")=="NONE")? mne:-1

   fdiff = ("fdiff" in auxlist1)? cnt_num(mne = auxlist1["fdiff"]) : -1
   delete auxlist1["fdiff"]
   fdiff_mne=(fdiff >=0 && counter_par(fdiff,"controller")=="NONE")? mne:-1

   ndiff = ("ndiff" in auxlist1)? cnt_num(mne = auxlist1["ndiff"]) : -1
   delete auxlist1["diff"]
   ndiff_mne=(ndiff >=0 && counter_par(ndiff,"controller")=="NONE")? mne:-1

   fndiff = ("fndiff" in auxlist1)? cnt_num(mne = auxlist1["fndiff"]) : -1
   delete auxlist1["fndiff"]
   fndiff_mne=(fndiff >=0 && counter_par(fndiff,"controller")=="NONE")? mne:-1

   ratio = ("ratio" in auxlist1)? cnt_num(mne = auxlist1["ratio"]) : -1
   delete auxlist1["ratio"]
   ratio_mne=(ratio >=0 && counter_par(ratio,"controller")=="NONE")? mne:-1

   fratio = ("fratio" in auxlist1)? cnt_num(mne = auxlist1["fratio"]) : -1
   delete auxlist1["fratio"]
   fratio_mne=(fratio >=0 && counter_par(fratio,"controller")=="NONE")? mne:-1

   cpiezo = ("cpiezo" in auxlist1)? cnt_num(mne = auxlist1["cpiezo"]) : -1
   delete auxlist1["cpiezo"]
   cpiezo_mne=(cpiezo >=0 && counter_par(cpiezo,"controller")=="NONE")? mne:-1

   oscmain = ("oscmain" in auxlist1)? cnt_num(mne = auxlist1["oscmain"]) : -1
   delete auxlist1["oscmain"]
   oscmain_mne=(oscmain >=0 && counter_par(oscmain,"controller")=="NONE")? mne:-1

   oscquad = ("oscquad" in auxlist1)? cnt_num(mne = auxlist1["oscquad"]) : -1
   delete auxlist1["oscquad"]
   oscquad_mne=(oscquad >=0 && counter_par(oscquad,"controller")=="NONE")? mne:-1

   if (MOCO[isgname]["version"] < 2.0) {
      printf("warning : MOCO firmware version too low (%s). Oscillation not supported.\n ", \
                          MOCO[isgname]["version"])
      oscmain_mne = oscquad_mne = -1
   }

   MOCO[isgname]["outbeam"] = outbeam_mne
   MOCO[isgname]["inbeam"]  = inbeam_mne
   MOCO[isgname]["foutbeam"] = foutbeam_mne
   MOCO[isgname]["finbeam"]  = finbeam_mne
   MOCO[isgname]["sum"]    = sum_mne
   MOCO[isgname]["fsum"]   = fsum_mne
   MOCO[isgname]["diff"]   = diff_mne
   MOCO[isgname]["fdiff"]  = fdiff_mne
   MOCO[isgname]["ndiff"]  = ndiff_mne
   MOCO[isgname]["fndiff"] = fndiff_mne
   MOCO[isgname]["ratio"]  = ratio_mne
   MOCO[isgname]["oscmain"] = oscmain_mne
   MOCO[isgname]["oscquad"] = oscquad_mne
   MOCO[isgname]["fratio"] = fratio_mne
   MOCO[isgname]["softbeam"] = ("softbeam" in auxlist1)? auxlist1["softbeam"] : ""
   delete auxlist1["softbeam"]
   scale = auxlist1["scale"] + 0
   delete auxlist1["scale"]
   MOCO[isgname]["scale"] = scale = (scale <= 0) ? 1 : scale

   MOCO[isgname]["rtime"] = ("rtime" in auxlist1)? auxlist1["rtime"] : "10"
   delete auxlist1["rtime"]

   if (piezo >= 0) {
      MOCO[isgname]["piezo"] = isgname
      moco_resetlimits(isgname, piezo, scale)

      macrodef = sprintf("moco_move(\"%s\", %s, %g)\n", isgname, isgname, scale)
      cdef("user_checkall", macrodef, isgname)
      macrodef = sprintf("moco_motorsrun %s\n", isgname)
      cdef("user_motorsrun", macrodef, isgname)
      macrodef = sprintf("moco_getpangles(\"%s\", %s, %g)\n", isgname, isgname, scale)
      cdef("user_getpangles", macrodef, isgname)
   } else {
      MOCO[isgname]["piezo"] = -1
      cdef("user_checkall",  "", isgname, "delete")
      cdef("user_motorsrun", "", isgname, "delete")
      cdef("user_getpangles","", isgname, "delete")
   }

   macrodef = ""
   if (outbeam_mne != -1 || inbeam_mne != -1   || \
       sum_mne != -1 || diff_mne != -1         || \
       ndiff_mne != -1 || ratio_mne != -1) {
      macrodef = \
         sprintf("moco_getcounts(\"%s\", \"?BEAM\", %s, %s, %s, %s, %s, %s)\n",\
                       isgname, outbeam_mne, inbeam_mne, \
                                sum_mne, diff_mne, ndiff_mne, ratio_mne)
   }
   if (foutbeam_mne != -1 || finbeam_mne != -1   || \
       fsum_mne != -1   || fdiff_mne != -1  || \
       fndiff_mne != -1 || fratio_mne != -1) {
      macrodef = \
         sprintf("%smoco_getcounts(\"%s\", \"?FBEAM\", %s, %s, %s, %s, %s, %s)\n", \
             macrodef, isgname, foutbeam_mne, finbeam_mne, \
                                fsum_mne, fdiff_mne, fndiff_mne, fratio_mne)
   }
   if (oscmain_mne != -1 || oscquad_mne != -1) {
      macrodef = \
         sprintf("%smoco_getoscilcounts(\"%s\", %s, %s)\n", \
                           macrodef, isgname, oscmain_mne, oscquad_mne)
   }
   if (macrodef)
      cdef("user_getcounts", macrodef, isgname)
   else
      cdef("user_getcounts", "", isgname, "delete")

   key= "C" isgname
   if (cpiezo_mne != -1) {
      cdef ("user_getcounts", sprintf("moco_getcountpiezo(\"%s\", %s)\n", isgname, cpiezo_mne), key)
   }
   else {
      cdef ("user_getcounts", "", key, "delete")
   }

   if (MOCO[name]["softbeam"] == "srcur") {
      if (whatis("__MI") & 0x5000004) {
         macrodef = sprintf("moco_srcurrent(\"%s\")\n", isgname)
         cdef("user_postcount", macrodef, isgname)
      } else {
         print "moco: option \"softbeam=srcur\"  needs to run misetup."
      }
   }

   if (MOCO[isgname]["runforever"] = (auxlist1["runforever"] == "yes")) {
      macrodef = sprintf("moco %s\n", isgname)
      cdef("begin_mac", macrodef, isgname)
   } else {
      cdef("begin_mac", "", isgname, "delete")
   }
   delete auxlist1["runforever"]

   MOCO[isgname]["update"] = (auxlist1["update"] + 0)
   delete auxlist1["update"]

   setup_tail("moco", isgname)

   i = ""
   for (i in auxlist1) {
      print "Invalid parameter: " i "=" auxlist1[i]
   }
   if (i != "")
      return(-1)
   else
      return(0)
}'

def mocounsetup '{
   local isgname

   isgname = "$1"
   cdef("", "", isgname, "delete")
   isgdevice_remove(isgname)

   if (whatis("MOCO") &&0x0400){
     list_remove(MOCO, isgname)
   }

   if (list_n(MOCO) <= 0){
      unglobal MOCO MOCO_AUX
   }
}'

def moco_setdefault(isgname) '{
   if (MOCO[0] <= 0) {
      print "No MOCO devices configured. Use first \`mocosetup\'."
      return(0)
   }
   if (isgname != "") {
      MOCO_AUX["default"] = isgname
      if (!list_check(MOCO, isgname)) {
         print "\`" isgname "\' is not a valid MOCO unit."
      }
   }
   if (!list_check(MOCO, MOCO_AUX["default"])) {
      MOCO_AUX["default"] = MOCO[1]
      print "Setting \`" MOCO_AUX["default"] "\' as default MOCO unit."
   }
   return(1)
}'

#%UU% [<moco_name>] [param=<value> ...]
#%MDESC%
# With no parameters displays some of the configuration values. With parameters
# the configuration values are changed.
#  %UL%
#  %LI%Valid configuration values are:%DL%
#    %DT%srange=<Vmin>:<Vmax>
#    %DD%Defines the scan range for tuning.
#    %DT%sspeed=<speed>
#    %DD%Defines the scanning speed in volts per second.
#    %DT%setpoint=<spoint>
#    %DD%Sets the operation point
#    %DT%set=<option>:<option>: ...
#    %DD%Enables operation options
#    %DT%clear=<option>:<option>: ...
#    %DD%Disables operation options
#    %DT%autotune=<autotune_event>:<autotune_event>: ...
#    %DD%Enables autotune under certain conditions
#    %DT%autotune=off
#    %DD%Disables autotune
#    %DT%autopeak=<autopeak_event>:<autopeak_event>: ...
#    %DD%Enables autopeak under certain conditions
#    %DT%autopeak=off
#    %DD%Disables autopeak
#    %XDL%
#  %XUL%

#
def mococonfig '{
   local isgname auxlist[] npar i

   npar = split("$*", auxlist)
   if (!npar || !list_check(MOCO, "$1")) {
      moco_setdefault("")
      isgname = MOCO_AUX["default"]
   } else {
      isgname = list_item(MOCO, "$1")
      moco_setdefault(isgname)
      for (i = 1; i < npar; i++) auxlist[i-1] = auxlist[i]
      delete auxlist[npar - 1]
      npar--
   }

   if (isgname = MOCO_AUX["default"]) {
      if (npar)
         moco__config(isgname, auxlist)
      else
         moco__config_show(isgname)
   }
}'

def moco__config(isgname, list) '{
   local i option[] comm
   for (i = 0; i in list; i++) {
      if (split(list[i], option, "=") != 2) {
         print "Bad configuration format [" list[i] "]."
         return(-1)
      }
      if (option[0] == "srange") {
         comm = moco_wspaces(option[1])
         comm = "SRANGE " comm
      } else if (option[0] == "sspeed") {
         comm = "SPEED " option[1]
      } else if (option[0] == "setpoint") {
         comm = "SETPOINT " option[1]
      } else if (option[0] == "set") {
         comm = moco_wspaces(option[1])
         comm = "SET " comm
      } else if (option[0] == "clear") {
         comm = moco_wspaces(option[1])
         comm = "SET " comm
      } else if (option[0] == "autotune") {
         comm = moco_wspaces(option[1])
         comm = "AUTOTUNE " comm
      } else if (option[0] == "autopeak") {
         comm = moco_wspaces(option[1])
         comm = "AUTOPEAK " comm
      } else {
         print "Bad configuration option [" list[i] "]."
         return(-1)
      }
      if (isgdevice_comm_ack(isgname, comm) != "OK") {
         print "Error setting configuration option. [" comm "]"
      }
   }
}'

def moco_wspaces(str) '{
   local len newstr i

   len = length(str)
   newstr = ""
   for (i = 1; i <= len; i++) {
      c = substr(str, i, 1)
      if (c == ":")
         newstr = newstr " "
      else
         newstr = newstr c
   }
   return(newstr)
}'

def moco__config_show(isgname) '{
   local aux[] answ npar i

   print "ISGdevice: " isgname

   answ = isgdevice_comm(isgname, "?SRANGE")
   split(answ, aux)
   print "\tsrange="aux[0]":"aux[1]

   answ = isgdevice_comm(isgname, "?SPEED")
   split(answ, aux)
   print "\tsspeed="aux[0]

   answ = isgdevice_comm(isgname, "?SETPOINT")
   print "\tsetpoint="answ

   answ = isgdevice_comm(isgname, "?SET")
   npar = split(answ, aux)
   printf("\tset=%s", aux[0])
   for (i = 1; i < npar; i++) printf(":%s",  aux[i])
   print

   answ = isgdevice_comm(isgname, "?AUTOTUNE")
   npar = split(answ, aux)
   printf("\tautotune=%s", aux[0])
   for (i = 1; i < npar; i++) printf(":%s",  aux[i])
   print

   answ = isgdevice_comm(isgname, "?AUTOPEAK")
   npar = split(answ, aux)
   printf("\tautopeak=%s", aux[0])
   for (i = 1; i < npar; i++) printf(":%s",  aux[i])
   print
}'

def moco_comm(comm, isgname) '{
   isgname = isgname? isgname : ""

   if (!moco_setdefault(isgname)) {
      print "Bad moco unit."
      exit
   }
   isgname = MOCO_AUX["default"]

   if (index(comm, "?") == 1)
      return (isgdevice_comm(isgname, comm))
   else
      return (isgdevice_comm_ack(isgname, comm))
}'

def mococomm '{
   print moco_comm("$1", "$2")
}'

#%UU% [<moco_name>]
#%MDESC%
# Prints the current state (Sends the request ?STATE to the MoCo unit).
def mocostate 'mococomm "?STATE" $*'


#%UU% [<moco_name>]
#%MDESC%
# Starts regulation (Sends the command GO to the MoCo unit).
def mocogo 'moco_comm("GO", "$*")'

#%UU% [<moco_name>]
#%MDESC%
# Stops regulation (Sends the command STOP to the MoCo unit).
def mocostop 'moco_comm("STOP", "$*")'


#%UU% [<moco_name> [S]]
#%MDESC%
# Performs a normal tunning procedure. If the parameter \"S\" is used the
# macro executes in silent mode and produces no screen printout.
#
def mocotune '{
   moco_comm("TUNE", "$*")
   moco__tune($# == 2)
}'

#%UU% [<moco_name> [S]]
#%MDESC%
# Performs a peak tunning procedure. If the parameter \"S\" is used the
# macro executes in silent mode and produces no screen printout.
#
def mocopeak '{
   moco_comm("TUNE PEAK", "$*")
   moco__tune($# == 2)
}'

def moco__tune(silent) '{
   local isgname m

   isgname = MOCO_AUX["default"]

   moco_getstate(isgname, 1)
   while (MOCO[isgname]["state"] < 0) {
      moco_getstate(isgname, 1)
      if (!silent) {
         printf("\r%s %s", substr("-\\|/", (m=++m%4)+1, 1), MOCO[isgname]["status"])
         tty_cntl("ce")
      }
      sleep(.1)
   }
   if (!silent) {
      printf("\r%s", MOCO[isgname]["status"])
      tty_cntl("ce")
      print
   }
}'

def moco_moco2user(piezo, mocopos, scale) '{
   return(user(piezo, mocopos * scale))
}'

def moco_user2moco(piezo, userpos, scale) '{
   return(dial(piezo, userpos) / scale)
}'

def moco_resetlimits(isgname, piezo, scale) '{
   local range[] vrange modsteps answ

   if ((answ = isgdevice_comm(isgname, "?OPRANGE")) == ISGDEV_ERR)
      return

   split(answ, range)

   if (range[0] * range[1] >= 0)
      vrange = (fabs(range[0]) <= 5 && fabs(range[1]) <= 5)? 5 : 10
   else
      vrange = (fabs(range[0]) <= 5 && fabs(range[1]) <= 5)? 10 : 20

   MOCO[isgname]["range"] = vrange * scale

   modsteps = spec_par("modify_step_size")
   spec_par("modify_step_size", 1)
   motor_par(piezo, "step_size", 0xFFFF / MOCO[isgname]["range"])
   spec_par("modify_step_size", modsteps)
   motor_par(piezo, "backlash", 0)

   set_lim(piezo, dial(piezo, moco_moco2user(piezo, range[0], scale)),\
                  dial(piezo, moco_moco2user(piezo, range[1], scale)))

   MOCO[isgname]["moving"] = 1
}'

def moco_move(isgname, piezo, scale) '{
   if (A[piezo] != MOCO[isgname]["user"] || MOCO[isgname]["mv"]) {
      if (isgdevice_comm(isgname, \
	   sprintf("PIEZO %g", moco_user2moco(piezo, A[piezo], scale))) \
           == ISGDEV_OK) {
         MOCO[isgname]["mv"] = 0
         MOCO[isgname]["moving"] = 1
      }
   }
}'

def moco_motorsrun '{
   if (MOCO["$1"]["moving"] == 1) {
      sscanf(isgdevice_comm("$1", "?STATE"), "%s", state)
      if (state == "MOVE")
         return(1)
      else
         MOCO["$1"]["moving"] = 2
   }
}'

def moco_getpangles(isgname, piezo, scale) '{
   local flag rtime

   flag = MOCO[isgname]["moving"]
   rtime = MOCO[isgname]["rtime"]

   if (!flag) {
      if (rtime >= 0) {
         if (rtime == 0 || time() > MOCO[isgname]["nextt"])
            flag = 1
      }
   }

   if (flag) {
      MOCO[isgname]["user"] = A[piezo] = \
	  moco_moco2user(piezo, isgdevice_comm(isgname, "?PIEZO"), scale)
      if (flag == 2)
          MOCO[isgname]["moving"] = 0

      MOCO[isgname]["nextt"] = time() + rtime

   } else
      A[piezo] = MOCO[isgname]["user"]
}'

def moco_getstate(isgname, flag) '{
   local status

   if (flag || time() > MOCO[isgname]["nextT"]) {
      if ((status = isgdevice_comm(isgname, "?STATE")) == ISGDEV_ERR)
         status = "???"

      if (status == "IDLE")
         MOCO[isgname]["state"] = 0
      else if (status == "RUN")
         MOCO[isgname]["state"] = 1
      else
         MOCO[isgname]["state"] = -1

      MOCO[isgname]["nextT"] = time() + 30

      if (status != MOCO[isgname]["status"]) {
         MOCO[isgname]["status"] = status
         return(1)
      } else
         return(0)
   }
}'

def moco_getcounts(isgname, comm, _outbeam, _inbeam, _sum, _diff, _ndiff, _ratio) '{
   local answ
   local _vin _vout _vsum

   answ = isgdevice_comm(isgname, comm)
   sscanf(answ, "%g %g", _vin, _vout)
   _vsum = _vout + _vin

   if (_outbeam >= 0) S[_outbeam] = _vout/counter_par(_outbeam, "scale")
   if (_inbeam  >= 0) S[_inbeam] = _vin/counter_par(_inbeam, "scale")
   if (_sum     >= 0) S[_sum] = _vsum/counter_par(_sum, "scale")
   if (_diff    >= 0) S[_diff] = (_vout - _vin)/counter_par(_diff, "scale")
   if (_ndiff   >= 0) {
      if (_vsum != 0)
         S[_ndiff] = (_vout - _vin)/_vsum/counter_par(_ndiff, "scale")
      else
         S[_ndiff] = 0
   }
   if (_ratio   >= 0) {
      if (_vin)
         S[_ratio] = (_vout / _vin)/counter_par(_ratio, "scale")
      else
         S[_ratio] = 1
   }
}'

def moco_getcountpiezo(isgname, _cpiezo) '{
   local answ
   local _val

   answ= isgdevice_comm(isgname, "?PIEZO")
   sscanf(answ, "%g", _val)

   if (_cpiezo >= 0) S[_cpiezo] = _val/counter_par(_cpiezo, "scale")
}'

def moco_getoscilcounts(isgname, _oscmain, _oscquad) '{
   local answ
   local _vmain _vquad

   answ = isgdevice_comm(isgname, "?OSCBEAM")
   sscanf(answ, "%g %g", _vmain, _vquad)

   if (_oscmain >= 0) S[_oscmain] = _vmain / counter_par(_oscmain, "scale")
   if (_oscquad >= 0) S[_oscquad] = _vquad / counter_par(_oscquad, "scale")
}'


#%IU% (<isgname>)
#%MDESC%
#    
def moco_srcurrent(isgname) '{
   local current _state

   _state = id_state()

   if (TANGO_ERR != "0"){
       return ("ERROR")
   }

   if (mi_refilltime() < 10){
      current = "REFILLING"
   }
   else if (_state != 4){
      current = "FE Closed"
   }
   else{
      current = sprintf("%6.2f",  mi_SR_Current() )
   }

   isgdevice_comm(isgname, sprintf("SOFTBEAM %g", current))

   return(current)
}'


#%UU% [<device_name>]
#%MDESC%
#  Macro that runs the interactive loop. %B%moco%B% refresh certain
#  information on the screen and at the same time accepts commands
#  from the standard input.
#  %BR%
#
def moco '{
   local isgname options

   isgname = $#? "$1": ""
   if (!$# || list_check(MOCO, isgname) > 0){
      if (moco_setdefault(isgname)) {
         isgname = MOCO_AUX["default"]
         MOCO[isgname]["prompt"] = "(" MOCO_AUX["default"] ")"
      }
   } else if ((serdev = isgdevice_add("MoCo", "$1", 3, "MOCO")) > 0) {
      isgname = "MoCo"
      MOCO[isgname]["prompt"] = ""
   } else {
      print "No MoCo unit found."
      isgname = ""
   }
   if (!isgname) {
      print "Usage: $0 moconame"
      print "  or   $0 serial_line"
      if (yesno("\nDisplay online help", 0))
         eval("help local moco")
   } else {
      rdef isg_prompt  "moco_prompt"
      rdef isg_update  "moco_update"
      rdef isg_show    "moco_show_comm"
      rdef isg_process "moco_process_comm"

      if (MOCO[isgname]["runforever"]) {
         runforever(sprintf("isg_main(\"%s\", \"%s\", 0, %g)", \
		    isgname, options, MOCO[isgname]["update"]))
      } else
         isg_main(isgname, options, 0, MOCO[isgname]["update"])
   }
}'

def moco_update '{
   local sftbeam

   update_flag = moco_getstate(isgname, 1);
   sftbeam = MOCO[isgname]["softbeam"]
   if (sftbeam != "") {
      if (sftbeam == "srcur") {
         local oldsrcurr newscurr

         oldscurr = MOCO[isgname]["softval"] + 0
         MOCO[isgname]["softval"] = moco_srcurrent(isgname)
         newscurr =  MOCO[isgname]["softval"] + 0

         if (oldscurr * newscurr == 0 && oldscurr != newscurr)
            update_flag = 1

      } else {
	 MOCO[isgname]["softval"] = sftbeam "??"
      }
   }
}'

#%IU%
#%MDESC%
#  Displays the prompt on the screen. If the "update" flag is set also
#  displays the board status.
#
def moco_prompt '
   if (MOCO[isgname]["softbeam"] != "")
      printf("MOCO%s: %s - %s (%s)", MOCO[isgname]["prompt"], date(),\
		     MOCO[isgname]["status"], MOCO[isgname]["softval"])
   else
      printf("MOCO%s: %s - %s", MOCO[isgname]["prompt"], date(), \
                     MOCO[isgname]["status"])
'

def moco_show_comm '
   isg_show_comm(".c, .config",   "Display spec setup")
'

#%IU%
#%MDESC%
#
def moco_process_comm '
   if (comm[0] == ".config" || comm[0] == ".c") {
      local aux

      print
      printf("\tSerial line: %s\n", ISGDEV_CONF[isgname]["serlin"])
      printf("\tPosition   : %d\n", ISGDEV_CONF[isgname]["pos"])
      print
      printf("\tPseudomotor\n")
      aux = MOCO[isgname]["piezo"]
      printf("\t       PIEZO mnemonic: %s\n", aux != -1 ? aux : "---")
      if (aux != -1)
      printf("\t         Scale factor: x%g\n", MOCO[isgname]["scale"])
      print
      aux = MOCO[isgname]["outbeam"]
      printf("\tPseudocounters:\n")
      printf("\t     OUTBEAM (normal): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["foutbeam"]
      printf("\t           (filtered): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["inbeam"]
      printf("\t     INBEAM  (normal): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["finbeam"]
      printf("\t           (filtered): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["sum"]
      printf("\t     SUM     (normal): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["fsum"]
      printf("\t           (filtered): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["diff"]
      printf("\t     DIFF    (normal): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["fdiff"]
      printf("\t           (filtered): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["ratio"]
      printf("\t     RATIO   (normal): %s\n", moco_cfg_show_cnt(aux))
      aux = MOCO[isgname]["fratio"]
      printf("\t           (filtered): %s\n", moco_cfg_show_cnt(aux))
      print
      aux = MOCO[isgname]["softbeam"]
      printf("\tSoftbeam:    %s\n", aux? aux : "---")
      print
      printf("\tSetup line: %s\n", MOCO[isgname]["setup"])
      return(1)
   }
'

def moco_cfg_show_cnt(mne) '{
   if (mne == -1)
      return("---")
   else {
      return(sprintf("%s [x%g]", mne, counter_par(cnt_num(mne), "scale")))
   }
}'

#%UU%
#%MDESC%
def mocoserver 'runforever("moco")'


#%MACROS%
#%AUTHOR% P.Fajardo, (Original 8/00).
#  $Revision: 1.15 $ / $Date: 2016/12/02 10:25:41 $
#%TOC%
#%END%
#%HISTORY%
#$Log: moco.mac,v $
#Revision 1.15  2016/12/02 10:25:41  guilloud
#changed TANGO_ERR test.
#
#Revision 1.14  2012/11/30 12:16:39  homsrego
#inclued the option for a pseudocounter (cpiezo) for the output voltage (from old BM01 macro).
#
#Revision 1.13  2012/05/05 06:42:37  beteva
#changes to cope with the new machinfo - interface with the machine.
#
#Revision 1.12  2011/06/23 13:55:15  guilloud
#protection against removing unexisting list.
#
#Revision 1.11  2009/01/20 08:47:51  guilloud
#if oscillation not supported, print a warning instead of crashing.
#
#Revision 1.10  2008/11/27 13:41:04  guilloud
#Oscillation award (changes by pablo ?).
#
#Revision 1.9  2008/08/12 14:24:59  rey
#doc change
#
#Revision 1.8  2008/08/12 13:57:21  rey
#documentation changes
#
#Revision 1.7  2005/11/18 09:47:11  fajardo
#bug (division by zero) in normalised pseudocounters fixed
#
#Revision 1.6  2005/05/12 15:21:13  fajardo
#fratio pseudocounter fixed
#
#Revision 1.5  2004/06/29 14:13:55  fajardo
#bug fix: local declaration added
#
#Revision 1.4  2004/03/29 17:29:56  fajardo
#minor bugs fixed
#
#Revision 1.3  2004/03/29 16:07:24  fajardo
#sum, diff and ratio pseudocounters added.
#
#Revision 1.2  2003/02/21 15:57:51  fajardo
#support for disabled pseudocounters
#updated for the new frontend device server (front end status)
#support for periodic update of pseudomotor position
#