esrf

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

#%TITLE% XML_obj.mac
#%NAME%
#   Some macros to handle spechardware objects manipulations
#%DESCRIPTION%
#   To do
#

#%UU% (id)
#%MDESC%Creates a spechw object: Creates an associative array to store 
#data, identified by <id>. 
#If object was existing, overwrites it.
#%BR%returns 0 .
def c_newObj(id)'{
   local myobj mywhat

   myobj = sprintf("_OBJ_%s",id)
   unglobal @myobj
   global @myobj[]
   
   return(0)
}'

#%UU% (id)
#%MDESC%Creates a spechw object if was not already existing.
#If object was existing, uses it.
#%BR%returns 0 .
def c_getObj(id)'{
   local myobj mywhat

   if (c_isObj(id) == 0) {
      myobj = sprintf("_OBJ_%s",id)
      unglobal @myobj
      global @myobj[]
   }
   
   return(0)
}'
#%UU% (id)
#%MDESC%Kill spec hw object 'id'. 
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_delObj(id)'{
   local myobj
   
   if (c_isObj(id) == 1) {
      myobj = sprintf("_OBJ_%s",id)
      xml_debug "removing " \'"myobj"\'
      unglobal @myobj
      return(0)
   }
   else {
      return(-1)
   }
}'

#%UU% (id)
#%MDESC%Check if 'id' is a valid spechw object
#%BR%returns 1 if is a spechw object
#%BR%returns 0 if not
def c_isObj(id)'{
   local myobj mywhat

   myobj = sprintf("_OBJ_%s",id)
   mywhat = whatis(myobj)
   if ( (mywhat & 0x5000004) == 0x5000004) {
      return(1)
   }
   else {
#      p id " is not a spechw object"
      return(0)
   }
}'

#%UU% (id)
#%MDESC%returns a string being the name of the associative array
#for the spechw object 'id'.
#%BR%returns this string name if OK
#%BR%returns "__error__" if NOT OK 
def c_getObjName(id)' {
   local myobj
   
   if (c_isObj(id) ==1) {   
      myobj = sprintf("_OBJ_%s",id)
      return(myobj)
   }
   else {
      return("__error__")
   }
    
}'

#%UU%(id,key,value)
#%MDESC% Sets the key,value of a spechw object 'id'
#%BR%returns 0 if OK
#%BR%returns -1 if OK
def c_setObjProp(id,key,value)'{
   local myobj
   
   if(c_isObj(id) == 1) {
      myobj = sprintf("_OBJ_%s",id)
      @myobj["local"][key] = value
      return(0)
   }
   else {
      return(-1)
   }

}'

#%UU%(id,key)
#%MDESC% returns the key value of a spechw object
#%BR%returns "__error__" if not OK
def c_getObjProp(id,key)'{
   local myobj myvalue

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
      if ( (key in @myobj["local"]) == 1 ) {
         myvalue = @myobj["local"][key]
         return(myvalue)
      }
      else {
         return("__error__")
      }
   }
   else {
      return("__error__")
   }

}'


#%UU%(id,key)
#%MDESC% delete a key of a spechw object
#%BR%returns 0 if OK
#%BR%returns "__error__" if not OK
def c_delObjProp(id,key)'{
   local myobj myvalue

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
      delete @myobj["local"][key]
      return(myvalue)
   }
   else {
      return("__error__")
   }

}'


#%UU%(id)
#%MDESC% Dumps the spechw object (only local keys)
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_showObj(id)'{
   local myobj ii

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
      for (ii in @myobj["local"]) {
         p ii " : " @myobj["local"][ii]
      }
      return(0)
   }
   else {
      return(-1)
   }

}'


#%UU%(id)
#%MDESC% Dumps the complete spechw object
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_dumpObj(id)'{
   local myobj myvalue

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
      p @myobj
      return(0)
   }
   else {
      return(-1)
   }

}'

#%UU%(id,key)
#%MDESC% Checks if this is a key for that spechw object.
#%BR%returns 1 if found
#%BR%returns 0 if not found
def c_hasObjProp(id,key)'{
   local myobj ii found

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
   
      if ( (key in @myobj["local"]) == 1) {
         return(1)
      }
      else {
         return(0)
      }
   }
   else {
      return(0)
   }

}'

#%UU%(id,value)
#%MDESC% In spechw object 'id', finds the 'first' key 
#which value is 'value'. 
#%BR%returns this key if found
#%BR%returns __error__ if not found
def c_getObjKey(id,value)'{
   local myobj ii

   if (c_isObj(id) == 1) {   
      myobj = sprintf("_OBJ_%s",id)
   
      for (ii in @myobj["local"]) {
         if (@myobj["local"][ii] == value) {
	    return(ii)
         }
      }
      return("__error__")
   }
   else {
      return("__error__")
   }

}'

#%UU% (id)
#%MDESC% For a spechw object, returns the number of xxx["local][]
#elements.
#%BR%returns -1 in case of error
def c_countObjProp(id)'{
   local ii ind  myarray

   if (c_isObj(id) == 1) {   
      myarray = c_getObjName(id)
   
      ind = 0
      for (ii in @myarray["local"] ){
         ind++
      }
      return(ind)
   }
   else {
      return(-1)
   }
}'



#%UU%(id,hwr_obj)
#%MDESC% For a spechw object 'id', it will realize
#%BR% - extraction of all the 'hwrid' values associated to the 'role' 
#properties.
#%BR% - each 'hwrid' value is assumed to be a xml path to the description
#of a hardware motor.
#%BR% - extracts from each 'hwrid' value, the associated motor name by
#reading the 'specname' property.
#%BR% - for each, register as ' real' (which  checks motor present in the spec 
#configuration.
#%BR% - for each, finally, if motor present, creates a property 'role' with
#value being this motor name. 
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_loadMotorsByRole(id,hwr_obj)'{
   local myobj  mybloc myval ret mymotname _tmp_role ii anerror arr nb
   
   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocrole_%s",id)
   
   anerror = 0
   
   if (c_isObj(id) == 1) {
#     extract to cache
      myval = c_blocExtractByRole(id,hwr_obj)
      if (myval == -1) {
         p "c_loadMotorsByRole : equipment: " id " : error extracting roles "
         return (-1)
      }

#    get list of keys
     _tmp_role = asso_keys(@mybloc)
     
      for (ii in _tmp_role) {
         myval = @mybloc[ii]["hwrid"]
#        we guess motor mne in /motors/toto string	 
#	 nb = split(myval,arr,"/")
#         mymotname = arr[nb-1]
#        now get the motor name itself      
         mymotname = c_extractByProp(id,myval,"specname",0)
         if (mymotname != "__error__") {
#           Check this is a valid motor name
            if (motor_num(mymotname) <0) {	 
               p "c_loadMotorsByRole: " id " motor " mymotname " is not in the config"
               anerror++    
	    }
	    c_setObjProp(id,ii,mymotname)
	    
	 }
      }
#     delete for the moment, the tmp array
#      p "Deleting " mybloc
      unglobal @mybloc
      if (anerror == 0) {
         return(0)
      }
      else {
         return(-1)
      }	
   }
   else {
      return(-1)
   } 
	 
}'


#%IU%(id,hwr_obj)
#%MDESC% For a spechw object 'id', extract the information by role, from 
#a hardware object (hwr_obj). It creates an associative array with all 
#this information, for futher use by c_extractByRole macro.
#%BR%ACCESS TO XML file
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_blocExtractByRole(id,hwr_obj)'{
   local myobj myhrw_obj ii mybloc ret
   
#   p "c_BlocExtractByRole: " id " " hwr_obj

   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocrole_%s",id)
   unglobal @mybloc
   global @mybloc
   
   ret = xml_readRoles(hwr_obj)
   
   if (ret == 0) {
      for (ii in XML_tmp) @mybloc[ii] = XML_tmp[ii]
      @myobj["_xmlrole"]["obj"]= hwr_obj
      @myobj["_xmlrolearray"]["obj"]= mybloc
   
      return(0)
   }
   else {
      return(-1)
   }

}'


#%IU%(id,hwr_obj,role,att,flagw)
#%MDESC% For an spechw object 'id', extracts from a hardware object (hwr_obj),
#the 'att' value associated to role 'role'.
#%BR%This macro executes a c_blocExtractByRole if not already done.
#%BR% - if flagw is set to 1, it means that we should be able to write
#back to the xml file. for that: sets to the spechw object the useful
#info (xml path ..) and in particular,creates a local key 'role' 
#with the value being the value of hardware attribute 'att'. 
#%BR%returns the 'att' value if OK
#%BR%returns the string __error__ if NOT OK
def c_extractByRole(id,hwr_obj,role,att,flagw)'{
   local myobj myhrw_obj mybloc mystr myval
   
#   p "c_extractByRole: " id " " role " " att

   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocrole_%s",id)
   
   if (c_isObj(id) == 1) {
#     Check if a c_blocExtractByRole has been called   
      if (@myobj["_xmlrole"]["obj"] != hwr_obj) {
#        c_blocExtractByRole has not been called  yet 
         ret = c_blocExtractByRole(id,hwr_obj)
	 if (ret != 0) {
	    return("__error__")
	 }
      }

#     Check that the key exists for associated array
      if ( att in @mybloc[role]) {
	 myval = @mybloc[role][att]
	 if (flagw == 1) {
	    mystr = sprintf("%s:%s/@%s",@myobj["_xmlrole"]["obj"],\
	    	@mybloc[role]["__path__"], att)
            @myobj["_xmlpath"][role] = mystr
            @myobj["local"][role] = myval
	 }
	 return(myval)
      }
      else {
        p "c_extractByRole: " mybloc " array has no key[" role "][" att "]"
	return("__error__")
      }
   }
   else {
      return("__error__")
   }
}'



#%UU%(id,hwr_obj)
#%MDESC% For a spechw object 'id', it will extract from the hardware object
#(hwr_obj)all the property/values that it will store in the object,
#plus the information to be able to write them back to the xml file
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_loadByProp(id,hwr_obj)'{
   local myobj  mybloc myval ret mymotname _tmp_role ii mystr
   
   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocprop_%s",id)
   
   if (c_isObj(id) == 1) {
#     extract to cache
      myval = c_blocExtractByProp(id,hwr_obj)
      if (myval == -1) {
         p "c_loadByProp: equipment: " id " : error extracting properties "
         return (-1)
      }

#    get list of keys
     _tmp_role = asso_keys(@mybloc)
     
      for (ii in _tmp_role) {
         myval = @mybloc[ii]["__value__"]
	 c_setObjProp(id,ii,myval)
	 mystr = sprintf("%s:%s", hwr_obj,\
	        @mybloc[ii]["__path__"])
	 @myobj["_xmlpath"][ii] = mystr
      }
#     delete for the moment, the tmp array
#      p "Deleting " mybloc
      unglobal @mybloc
      return(0)	
   }
   else {
      return(-1)
   } 
	 
}'


#%IU%(id,hwr_obj)
#%MDESC% For a spechw object 'id', extract the information by property, 
#from a hardware object (hwr_obj), at first level.
#It creates an associative array with all 
#this information, for futher use by c_ExtractByProp macro.
#%BR%ACCESS TO XML file
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_blocExtractByProp(id,hwr_obj)'{
   local myobj myhrw_obj ii mybloc ret
   
#   p "c_blocExtractByProp: " id " " hwr_obj

   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocprop_%s",id)
   unglobal @mybloc
   global @mybloc
   
   ret = xml_readProperties(hwr_obj)
   
   if (ret == 0) {
#     @mybloc = XML_tmp does not work
      for (ii in XML_tmp) @mybloc[ii] = XML_tmp[ii]
      @myobj["_xmlprop"]["obj"]= hwr_obj
      @myobj["_xmlproparray"]["obj"]= mybloc
      return(0)
   }
   else {
      return(-1)
   }
}'


#%IU%(id,hwr_obj,prop,flagw)
#%MDESC% For an spechw object 'id', extracts from a hardware object (hwr_obj),
#the value of property 'prop.
#%BR%This macro executes a c_blocExtractByProp if not already done.
#%BR% - if flagw is set to 1, it means that we should be able to write
#back to the xml file. for that: sets to the spechw object the useful
#info (xml path ..) and in particular,creates a local key 'prop' 
#with this value. 
#%BR%returns the 'prop' value if OK
#%BR%returns the string __error__ if NOT OK
def c_extractByProp(id,hwr_obj,prop,flagw)'{
   local myobj myhrw_obj mybloc mystr myval
   
#   p "c_ExtractByProp: " id " " prop

   myobj = sprintf("_OBJ_%s",id)
   mybloc = sprintf("_XML_tmp_blocprop_%s",id)

   if (c_isObj(id) == 1) {
#     Check that a c_blocExtractByprop has been called   
      if (@myobj["_xmlprop"]["obj"] != hwr_obj) {
#        c_blocExtractByProp has not been called  yet 
         ret = c_blocExtractByProp(id,hwr_obj)
	 if (ret != 0) {
	    return("__error__")
	 }
      }

#     Check that the key exists for associated array
      if ( "__value__" in @mybloc[prop]) { 
	 myval = @mybloc[prop]["__value__"]
         if (flagw == 1) {
	    mystr = sprintf("%s:%s/%s", @myobj["_xmlprop"]["obj"],\
	        @mybloc[prop]["__path__"],prop)
            @myobj["_xmlpath"][prop] = mystr
            @myobj["local"][prop] = myval
	 }
         return(myval)
      }
      else {
        p "c_extractByProp: " mybloc " array has no key[" prop "][__value__]"
        return("__error__")
      }
   }
   else {
      return("__error__")
   }
}'


#%UU%(id,motorname,type,name)
#%MDESC% registers this motor in spechw object 'id' property list 
#'allrealmotor' (if type 'real')
#or 'allmacromotor' (if type 'macro'). If type 'macro', checks that
#the motor in the config is a macromotor of type 'name'
#%BR%If the motor is not in the config, does not include it in the
#corresponding list, and returns -1
#%BR% - returns 0 if OK
#%BR% - returns -1 if NOT in the config
#%BR% - returns -2 if NOT macromotor of type 'name'
#%BR% - returns -3 if 'id' is not an object or 'type' undefined
def c_registerMotor(id,motname,type,name)'{
   local mystr cont contname

#  Refuse, if motor is not in the config
   if (motor_num(motname) <0) {
      return(-1)
   }   
   myobj = c_getObjName(id)
   if (myobj != "__error__") {
      if (type == "real") {
         if (c_hasObjProp(id,"allrealmotor") == 1) {
            mystr = concatstring(motname, @myobj["local"]["allrealmotor"])
         }
         else {
            mystr = motname
         }
         @myobj["local"]["allrealmotor"] = mystr
         return(0)
      }
      else if (type == "macro") {
         if (c_hasObjProp(id,"allmacromotor") == 1) {
            mystr = concatstring(motname, @myobj["local"]["allmacromotor"])
         }
         else {
            mystr = motname
         }
         @myobj["local"]["allmacromotor"] = mystr
         cont = motor_par(motor_num(motname),"controller") 
	 contname = motor_par(motor_num(motname),"device_id")
	 if (cont != "PSE_MAC_MOT" || contname != name) {
            return(-2)
	 }
         return(0)      
      }
      else {
#        list unknown
         return(-3)
      }
   }
   else {
   
   }
}'



#%UU%(id,motorname,type)
#%MDESC% checks if the motor was registered as 'type'
#%BR% - returns 1 if YES
#%BR% - returns 0 if NO
def c_hasMotor(id,motorname,type)'{
   local mystr
   
   myobj = c_getObjName(id)
   if (myobj != "__error__") {
      if (type == "real") {
         if (c_hasObjProp(id,"allrealmotor") == 1) {
            if ( isonstring(motorname,c_getObjProp(id,"allrealmotor")) == 1) {
               return(1)
	    }
         }
      }
      else if (type == "macro") {
         if (c_hasObjProp(id,"allmacromotor") == 1) {
            if ( isonstring(motorname,c_getObjProp(id,"allmacromotor")) == 1) {
               return(1)
	    }
         }      
      }
   }
   return(0)
}'



#%UU% (id,prop)
#%MDESC% writes a property of a spechw object to the
#corresponding xml file
def c_writeObj(id,prop)'{

   local mystring myobj mypath arr hw_obj ipath nb
   
   myobj = sprintf("_OBJ_%s",id)
   mypath = @myobj["_xmlpath"][prop]
   myval = c_getObjProp(id,prop)
   p myval
   nb = split(mypath,arr,":")
   hw_obj = arr[0]
   ipath = arr[1]

   mystring = sprintf("xml_write(\"%s/%s\",\"%s\",\"%s\")",_XML_lp,hw_obj,ipath,myval)
   p mystring
   
   remote_eval(HWR_dev,mystring)

   return(0)
}'


#%UU% (id,hw_obj)
#%MDESC% This reads a hardware object  being of a particular type:
#containing the list of controllers of that type for a spec session.
#This is typically for a macromotor modules definition in the spec
#configuration.
#%BR%It stores this information in the spechw object 'id' with
#key,value being 'numerical index',controller name
#%BR%returns 0 if OK
#%BR%returns -1 if NOT OK
def c_createEquipList(id,hw_obj)'{
   local ii mytmp mystr ret

   c_newObj(id)   
   mystr = ""
   ret =  xml_read(hw_obj,"/unit/equipment/@hwrid","__value__")
   if ("__error__" in XML_tmp) {
      return(-1)
   }
   for (ii in XML_tmp) {
      mystr = sprintf("%s %s",XML_tmp[ii],mystr)
   }
   c_setObjProp(id,"modules",mystr)
}'


#%IU%
#%MDESC% writes as print does, if DEBUG has bit 0x80 selected
def dbgp'{
   if ((DEBUG & 0x80) != 0) {
      print "$*"
   }
}'


#%IU%(str1,str2)
#%MDESC%returns left pushing string str1 to str2 (setting
#a blank between them
def concatstring(str1,str2)'{
   local mys
   
   if (str1 == "") {
       mys = str2
   }
   else if (str2 == "") {
       mys = str1
   }
   else {
      mys = sprintf("%s %s",str1,str2)
   }
   return(mys)
}'

#%IU%(str1,str2)
#%MDESC% str2 being a string of names separated by blanks,
#this macro checks if str1 is one of them. This macro differs
#from index as index looks at an occurence of str1 (possibly
#itself inside a string)
def isonstring(str1,str2)'{
   local myarr nb ii
   
#   p str1 " isonstrig ? " str2
   nb = split(str2,arr)
   for (ii=0; ii<nb; ii++) {
      if ( arr[ii] == str1) {
         return(1)
      }
   }
   return(0)
   
}'


#%IU% (arr)
#%MDESC%Check if arr is an existing global associative array
#%BR%returns 1 if OK
#%BR%returns 0 if not
def is_ass(arr)'{
   local myobj mywhat

   mywhat = whatis(arr)
   if ( (mywhat & 0x5000004) == 0x5000004) {
      return(1)
   }
   else {
#      p arr " is not an existing global associative array")
      return(0)
   }
}'



#%MACROS%
#%IMACROS%
#%DEPENDENCIES% XML_utils.mac
#  
#%AUTHOR% 
#%TOC%