Changeset 641
- Timestamp:
- Sep 30, 2011 3:19:00 AM (12 years ago)
- Location:
- moxy/trunk/src/moxy
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
moxy/trunk/src/moxy/moxy
r635 r641 2 2 3 3 # TODO: refactor this 4 /APSshare/bin/python /APSshare/pythonlib/moxy/moxy.py $*4 #/APSshare/bin/python /APSshare/pythonlib/moxy/moxy.py $* 5 5 6 echo "This code is not ready to be used yet" 6 7 7 8 ########### SVN repository information ################### -
moxy/trunk/src/moxy/moxy.py
r635 r641 50 50 51 51 ---- 52 @note: wxPython does not provide standard tear-off windows53 @see: http://wiki.python.org/moin/Distutils/Tutorial54 @see: http://www.py2exe.org/index.cgi/Tutorial55 @note: for an undo example, see: http://wiki.wxpython.org/AnotherTutorial52 :note: wxPython does not provide standard tear-off windows 53 :see: http://wiki.python.org/moin/Distutils/Tutorial 54 :see: http://www.py2exe.org/index.cgi/Tutorial 55 :note: for an undo example, see: http://wiki.wxpython.org/AnotherTutorial 56 56 ''' 57 57 58 58 59 59 import wx 60 import wxmtxy_root61 import pvConnect60 import root 61 #import pvConnect 62 62 import sys 63 63 64 64 65 modules ={u' wxmtxy_htmlview': [0,65 modules ={u'htmlview': [0, 66 66 'HtmlView to view HTML-formatted help files', 67 u' wxmtxy_htmlview.py'],68 u'wxmtxy_pair': [0,67 u'htmlview.py'], 68 u'pair': [0, 69 69 'configuration for X,Y pair of EPICS positioners', 70 u' wxmtxy_pair.py'],71 u'wxmtxy_pvsetup': [0, 'configure EPICS for X,Y pair', u'wxmtxy_pvsetup.py'],72 u'wxmtxy_root': [1, 'Main frame of Application', u'wxmtxy_root.py'],73 u'wxmtxy_row': [0, 'one row of settings', u'wxmtxy_row.py'],74 u'wxmtxy_tab': [0, 'set of rows with positioner settings', u'wxmtxy_tab.py']}70 u'pair.py'], 71 u'pvsetup': [0, 'configure EPICS for X,Y pair', u'pvsetup.py'], 72 u'root': [1, 'Main frame of Application', u'root.py'], 73 u'row': [0, 'one row of settings', u'row.py'], 74 u'tab': [0, 'set of rows with positioner settings', u'tab.py']} 75 75 76 76 … … 80 80 def OnInit(self): 81 81 '''demonstrate the use of this tool''' 82 self.main = wxmtxy_root.create(None)82 self.main = root.create(None) 83 83 self.main.Show() 84 84 self.SetTopWindow(self.main) … … 86 86 87 87 88 def on_exit(timer, epics_db):89 '''Exit handler to stop the ca.poll()90 @param timer: CaPollWx object91 @param epics_db: Python list of pvConnect.EpicsPv objects to be released'''92 #print __name__, "exit handler"93 #for item in epics_db:94 # item.release()95 if pvConnect.IMPORTED_CACHANNEL:96 pvConnect.on_exit(timer)88 #def on_exit(timer, epics_db): 89 # '''Exit handler to stop the ca.poll() 90 # @param timer: CaPollWx object 91 # @param epics_db: Python list of pvConnect.EpicsPv objects to be released''' 92 # #print __name__, "exit handler" 93 # #for item in epics_db: 94 # # item.release() 95 # if pvConnect.IMPORTED_CACHANNEL: 96 # pvConnect.on_exit(timer) 97 97 98 98 … … 103 103 if len(sys.argv) == 2: 104 104 settingsFile = sys.argv[1] 105 wxmtxy_root.root(None, settingsFile).Show()106 capoll_timer = None107 if pvConnect.IMPORTED_CACHANNEL:108 capoll_timer = pvConnect.CaPollWx(0.1)109 capoll_timer.start()105 root.root(None, settingsFile).Show() 106 #capoll_timer = None 107 #if pvConnect.IMPORTED_CACHANNEL: 108 # capoll_timer = pvConnect.CaPollWx(0.1) 109 # capoll_timer.start() 110 110 application.MainLoop() 111 on_exit(capoll_timer, None)111 #on_exit(capoll_timer, None) 112 112 113 113 -
moxy/trunk/src/moxy/moxy_axis.py
r631 r641 24 24 25 25 26 import pvConnect26 import epics 27 27 import pprint 28 28 import copy … … 34 34 35 35 class Axis: 36 '''EPICS PVs and connections for one axis''' 36 ''' 37 EPICS PVs and connections for one axis 38 39 Example use:: 40 41 axis = moxy_axis.Axis() 42 axis.SetConfigure(config_dict): 43 if axis.Connect() 44 # ... 45 axis.Move(new_position) 46 # ... 47 axis.Stop() 48 # ... 49 axis.Disconnect() 50 ''' 37 51 38 52 def __init__(self): 39 53 '''declare initial storage''' 40 self.db = {} 41 self.config = None 42 self.isMotorRec = False 54 self.db = {} # internal data 55 self.pvname = {} # actual PV name for each field 56 self.cb_index = {} # callback index each field 57 self.config = None # user-supplied configuration of PV names 43 58 for field in field_list: 44 self.db[field] = _data() 59 self.db[field] = None # PyEpics.PV connection for this field's pv 60 self.pvname[field] = "" # actual PV name for this field 61 self.cb_index[field] = None 62 63 def GetConfigure(self): 64 ''' 65 Get the EPICS PVs for this X,Y pair 66 67 :return: Python dictionary of EPICS PV configuration 68 ''' 69 return copy.deepcopy(self.config) 70 71 def SetConfigure(self, config): 72 ''' 73 Define the EPICS PVs for this X,Y pair 74 75 :param config: Python dictionary of EPICS PV configuration 76 ''' 77 if 'isMotorRec' not in config: 78 raise RuntimeError, "need to define ``isMotorRec``" 79 self.config = copy.deepcopy(config) 45 80 46 81 def Connect(self): 47 '''Try to initiate EPICS connection with named PVs 48 @return: [Boolean] if all axes connected''' 82 ''' 83 Try to initiate EPICS connection with named PVs 84 85 :return: if all axes connected 86 :rtype: bool 87 ''' 49 88 failures = 0 89 90 # First, find actual PV names for each field 91 isMotorRec = self.config['isMotorRec'] 92 base = self.config['VAL'].split('.')[0] 50 93 for field in field_list: 51 # TODO: Can these connections be done together? 52 ch = self.db[field].GetConnection() 53 if ch != None: 54 try: 55 ch.connectw() 56 ch.monitor() 57 except: 58 failures += 1 59 print "Could not connect with PV: " + self.db[field].pv 60 return failures > 0 94 if field in self.config and len(self.config[field].strip()) > 0: 95 self.pvname[field] = self.config[field] 96 elif isMotorRec: 97 self.pvname[field] = "%s.%s" % (base, field) 98 else: 99 raise RuntimeError, "Must specify PV for %s field" % field 100 101 # Now, connect and monitor each PV 102 for field, pv in self.pvname.items(): 103 ch = epics.PV(pv) 104 self.db[field] = ch 105 kw = {'index': None, 106 'with_ctrlvars': True, 107 'field': field, 108 } 109 i = ch.add_callback(onChanges, **kw) 110 self.cb_index[field] = i # use later to disconnect 111 112 return failures == 0 61 113 62 114 def Disconnect(self): 63 115 '''Terminate EPICS connection with named PVs''' 64 for field in field_list: 65 ch = self.db[field].GetConnection() 66 if ch != None: 67 ch.release() 116 for field, ch in self.db.items(): 117 ch.remove_callback(self.cb_index[field]) 118 self.cb_index[field] = None 119 self.db[field] = None 120 self.pvname[field] = "" 68 121 69 122 def Stop(self): 70 123 '''Send a STOP to EPICS''' 71 124 field = 'STOP' 72 ch = self.db[field] .GetConnection()73 ch. chan.putw(1)125 ch = self.db[field] 126 ch.put(1) 74 127 75 128 def Move(self, position): 76 '''Send new position to VAL field of EPICS''' 129 ''' 130 Send new position to VAL field of EPICS 131 132 :param number position: new target (commanded) position 133 ''' 77 134 field = 'VAL' 78 ch = self.db[field] .GetConnection()135 ch = self.db[field] 79 136 #print __name__, 'Move:', position 80 ch.chan.putw(position) 81 82 def GetConfigure(self): 83 '''Get the EPICS PVs for this X,Y pair 84 @return: Python dictionary of EPICS PV configuration''' 85 return copy.deepcopy(self.config) 86 87 def SetConfigure(self, config): 88 '''Define the EPICS PVs for this X,Y pair 89 @param config: Python dictionary of EPICS PV configuration''' 90 # pprint.pprint(config) 91 self.config = copy.deepcopy(config) 92 if not self.config.has_key('isMotorRec'): 93 return 94 self.isMotorRec = self.config['isMotorRec'] 95 base = self.config['VAL'].split('.')[0] 96 for field in self.config: 97 if field in field_list: 98 self.db[field].SetPv(self.config[field]) 99 if self.isMotorRec: 100 # fill in default fields of motor records 101 for field in field_list: 102 pv = self.db[field].GetPv() 103 if pv == None or len(pv) == 0: 104 self.db[field].SetPv(base + '.' + field) 105 # What about checking to see how many fields have connected? 106 # And then dumping if not all fields connect? 107 108 109 class _data: 110 '''the internal data associated with a single PV''' 111 112 def __init__(self): 113 '''only create the space''' 114 self.pv = None 115 self.connection = None 116 self.widget = None 117 118 def GetPv(self): 119 '''@return: [string] EPICS PV name''' 120 return self.pv 121 122 def SetPv(self, pv): 123 '''set the PV name 124 @param pv: [string] EPICS PV name''' 125 self.pv = pv 126 self.connection = pvConnect.EpicsPv(pv) 127 128 def GetConnection(self): 129 '''@return: pvConnect.EpicsPv object''' 130 return self.connection 131 132 def GetWidget(self): 133 '''@return: widget object''' 134 return self.widget 135 136 def SetWidget(self, widget): 137 '''set widget object to be used in a callback 138 @param widget: used as self.widget(value)''' 139 self.widget = widget 140 141 def _callback(self, value): 142 '''receive EPICS CA monitor value 143 @param value: from epics_get['pv_value']''' 144 # print __name__, self.pv, value, self.connection.epics_args, self.connection.user_args 145 if self.widget != None: 146 self.widget(value) 137 ch.put(position) 138 139 140 #class _data: 141 # '''the internal data associated with a single PV''' 142 # 143 # def __init__(self): 144 # '''only create the space''' 145 # self.pv = None 146 # self.connection = None 147 # self.widget = None 148 # 149 # def GetPv(self): 150 # ''':return: [string] EPICS PV name''' 151 # return self.pv 152 # 153 # def SetPv(self, pv): 154 # ''' 155 # set the PV name 156 # 157 # :param str pv: EPICS PV name 158 # :see: http://cars9.uchicago.edu/software/python/pyepics3/pv.html 159 # ''' 160 # self.pv = pv 161 # self.connection = epics.PV(pv) 162 # 163 # def GetConnection(self): 164 # '''@return: pyEpics.PV object''' 165 # return self.connection 166 # 167 # def GetWidget(self): 168 # '''@return: widget object''' 169 # return self.widget 170 # 171 # def SetWidget(self, widget): 172 # '''set widget object to be used in a callback 173 # :param widget: used as self.widget(value)''' 174 # self.widget = widget 175 # 176 # def _callback(self, value): 177 # ''' 178 # receive EPICS CA monitor value 179 # 180 # :param value: from epics_get['pv_value'] 181 # ''' 182 # # print __name__, self.pv, value, self.connection.epics_args, self.connection.user_args 183 # if self.widget != None: 184 # self.widget(value) 147 185 148 186 149 187 # example code follows 150 188 189 def onChanges(**kw): 190 ''' 191 simple PyEpics monitor callback routine 192 193 :param dict kw: see http://cars9.uchicago.edu/software/python/pyepics3/pv.html#pv-callbacks-label 194 ''' 195 # print kw 196 print kw['timestamp'], kw['pvname'], kw['value'] 151 197 152 198 def _main_callback(epics_args, user_args): … … 161 207 config = { 162 208 'x': { 163 # USAXS a1y: 32idbLAX:m58:c1:m1164 209 'isMotorRec': True, 165 'VAL': ' 32idbLAX:m58:c1:m1.VAL'210 'VAL': 'prj:m1.VAL' 166 211 }, 167 212 'y': { 168 # USAXS a2y: 32idbLAX:m58:c1:m2169 213 'isMotorRec': False, 170 'VAL': ' 32idbLAX:m58:c1:m2.VAL',171 'RBV': ' 32idbLAX:m58:c1:m2.RBV',172 'EGU': ' 32idbLAX:m58:c1:m2.EGU',173 'DESC': ' 32idbLAX:m58:c1:m2.DESC',174 'DMOV': ' 32idbLAX:m58:c1:m2.DMOV',175 'STOP': ' 32idbLAX:m58:c1:m2.STOP'214 'VAL': 'prj:m2.VAL', 215 'RBV': 'prj:m2.RBV', 216 'EGU': 'prj:m2.EGU', 217 'DESC': 'prj:m2.DESC', 218 'DMOV': 'prj:m2.DMOV', 219 'STOP': 'prj:m2.STOP' 176 220 }, 177 'sr': {178 # USAXS a1y: 32idbLAX:m58:c1:m1179 'isMotorRec': False,180 'VAL': 'S:SRcurrentAI'181 }182 221 } 183 222 axes = {} 184 223 for axis in config: 185 item = Axis() 186 axes[axis] = item 224 225 axes[axis] = item = Axis() 187 226 item.SetConfigure(config[axis]) 188 ch = item.db['VAL'].GetConnection() 189 ch.SetUserArgs(axis) 190 ch.SetUserCallback(_main_callback) 191 cfg = item.GetConfigure() 192 cfg['AXIS'] = axis 193 # pprint.pprint(cfg) 194 item.Connect() 227 if not item.Connect(): 228 raise RuntimeError, "Did not connect %s axis" % axis 229 230 ch = item.db['RBV'] 195 231 print 'axis', axis 196 interval = 5197 for seconds in range(interval):198 time.sleep(1)199 ch.chan.pend_event()200 print interval - seconds - 1, ch.GetPv(), '=', ch.GetValue()201 # pprint.pprint(ch.epics_args)202 # pprint.pprint(cfg)232 233 interval = 15 234 for seconds in range(interval): 235 time.sleep(1) 236 #ch.poll() 237 print interval - seconds - 1, ch.pvname, '=', ch.get() 238 203 239 for axis in config: 204 240 axes[axis].Disconnect() 205 pvConnect.on_exit() -
moxy/trunk/src/moxy/moxy_xml.py
r635 r641 10 10 #************************************************************************* 11 11 12 '''@note: support the XML settings file for the moxy application 12 ########### SVN repository information ################### 13 # $Date$ 14 # $Author$ 15 # $Revision$ 16 # $URL$ 17 # $Id$ 18 ########### SVN repository information ################### 19 20 ''' 21 :note: support the XML settings file for the moxy application 13 22 14 23 This Python file provides routines to read and write XML settings … … 20 29 dictionary with the EPICS configuration is shown below. 21 30 22 @version: 23 ########### SVN repository information ################### 24 # $Date$ 25 # $Author$ 26 # $Revision$ 27 # $URL$ 28 # $Id$ 29 ########### SVN repository information ################### 30 31 @note: for help with xml.dom, see http://docs.python.org/library/xml.dom.html 32 33 @note: Here is an example XML file: 34 <?xml version="1.0" ?> 35 <moxy date="2009-04-09" time="10:27:00" version="1.0"> 36 <XYpair name="example" selected="True"> 37 <EPICS_configuration> 38 <axis name="x"> 39 <flag isMotorRec="False" /> 40 <field name="VAL" pv="32idbLAX:float1" /> 41 <field name="RBV" pv="32idbLAX:float2" /> 42 <field name="DESC" pv="32idbLAX:string1" /> 43 <field name="EGU" pv="32idbLAX:string2" /> 44 <field name="DMOV" pv="32idbLAX:bit1" /> 45 <field name="STOP" pv="32idbLAX:bit2" /> 46 </axis> 47 <axis name="y"> 48 <flag isMotorRec="True" /> 49 <field name="VAL" pv="32idbLAX:m58:c1:m1" /><!-- USAXS a1y --> 50 </axis> 51 </EPICS_configuration> 52 <tab name="page 1"> 53 <row name="page 1, row 0" x="1.0" y="-1.0" selected="True"/> 54 <row name="page 1, row 1" x="1.1" y="-1.1"/> 55 <row/> 56 </tab> 57 <tab name="page 2" selected="True"> 58 <row name="page 2, row 0" x="2.0" y="-2.0"/> 59 <row name="page 2, row 1" x="2.1" y="-2.1"/> 60 <row name="page 2, row 2" x="2.2" y="-2.2" selected="True"/> 61 <row name="page 2, row 3" x="2.3" y="-2.3"/> 62 <row name="page 2, row 4" x="2.4" y="-2.4"/> 63 <row name="page 2, row 5" x="2.5" y="-2.5"/> 64 <row name="page 2, row 6" x="2.6" y="-2.6"/> 65 </tab> 66 <tab name="empty page"/> 67 <tab name="page 3"> 68 </XYpair> 69 </moxy> 70 71 @note: Here is an example Python dictionary of the EPICS configuration above: 31 :note: for help with xml.dom, see http://docs.python.org/library/xml.dom.html 32 33 :note: Here is an example XML file:: 34 35 <?xml version="1.0" ?> 36 <moxy date="2009-04-09" time="10:27:00" version="1.0"> 37 <XYpair name="example" selected="True"> 38 <EPICS_configuration> 39 <axis name="x"> 40 <flag isMotorRec="False" /> 41 <field name="VAL" pv="32idbLAX:float1" /> 42 <field name="RBV" pv="32idbLAX:float2" /> 43 <field name="DESC" pv="32idbLAX:string1" /> 44 <field name="EGU" pv="32idbLAX:string2" /> 45 <field name="DMOV" pv="32idbLAX:bit1" /> 46 <field name="STOP" pv="32idbLAX:bit2" /> 47 </axis> 48 <axis name="y"> 49 <flag isMotorRec="True" /> 50 <field name="VAL" pv="32idbLAX:m58:c1:m1" /><!-- USAXS a1y --> 51 </axis> 52 </EPICS_configuration> 53 <tab name="page 1"> 54 <row name="page 1, row 0" x="1.0" y="-1.0" selected="True"/> 55 <row name="page 1, row 1" x="1.1" y="-1.1"/> 56 <row/> 57 </tab> 58 <tab name="page 2" selected="True"> 59 <row name="page 2, row 0" x="2.0" y="-2.0"/> 60 <row name="page 2, row 1" x="2.1" y="-2.1"/> 61 <row name="page 2, row 2" x="2.2" y="-2.2" selected="True"/> 62 <row name="page 2, row 3" x="2.3" y="-2.3"/> 63 <row name="page 2, row 4" x="2.4" y="-2.4"/> 64 <row name="page 2, row 5" x="2.5" y="-2.5"/> 65 <row name="page 2, row 6" x="2.6" y="-2.6"/> 66 </tab> 67 <tab name="empty page"/> 68 <tab name="page 3"> 69 </XYpair> 70 </moxy> 71 72 :note: Here is an example Python dictionary of the EPICS configuration above:: 73 72 74 example_dictionary = { 73 75 'x': { … … 99 101 def __init__(self, settingsFile=None): 100 102 '''prepare the settings file 101 @param settingsFile: [string] name of XML file with settings'''103 :param settingsFile: [string] name of XML file with settings''' 102 104 self.rootElement = 'moxy' 103 105 # TODO: consider supporting legacy 'wxmtxy' root elements, too … … 106 108 107 109 def GetDb(self): 108 ''' @return: database'''110 ''':return: database''' 109 111 return self.db 110 112 111 113 def GetSettingsFile(self): 112 ''' @return: name of XML settings file'''114 ''':return: name of XML settings file''' 113 115 return self.settingsFile 114 116 115 117 def SetSettingsFile(self, thefile): 116 118 '''set the name of XML settings file 117 @param thefile: [string] name of XML file with settings'''119 :param thefile: [string] name of XML file with settings''' 118 120 self.settingsFile = thefile 119 121 … … 126 128 and sets defaults for fields 127 129 128 @param title: [string] the title of the XY_pair set (default="")129 @return: the index number'''130 :param title: [string] the title of the XY_pair set (default="") 131 :return: the index number''' 130 132 if self.CountPairs() == -1: 131 133 self.db[u"pairs"] = [] … … 138 140 def GetPairTitle(self, pairnum): 139 141 '''return the name of the XY_pair 140 @param pairnum: [int] index number of the XY_pair'''142 :param pairnum: [int] index number of the XY_pair''' 141 143 return self.db[u"pairs"][pairnum][u"@name"] 142 144 143 145 def SetPairTitle(self, pairnum, title): 144 146 '''set the name of the XY_pair 145 @param pairnum: [int] index number of the XY_pair'146 @param title: [string] name of the XY_pair'''147 :param pairnum: [int] index number of the XY_pair' 148 :param title: [string] name of the XY_pair''' 147 149 self.db[u"pairs"][pairnum][u"@name"] = title 148 150 149 151 def SelectPair(self, pairnum): 150 152 '''set the "selected" attribute of the pair 151 @param pairnum: [int] index number of the XY_pair'''153 :param pairnum: [int] index number of the XY_pair''' 152 154 for pair in self.db[u"pairs"]: # first, deselect all pairs 153 155 pair[u"@selected"] = False … … 155 157 156 158 def GetSelectedPair(self): 157 ''' @return: index number of the "selected" pair (-1 if none selected)'''159 ''':return: index number of the "selected" pair (-1 if none selected)''' 158 160 selected = -1 159 161 try: … … 168 170 169 171 def CountPairs(self): 170 ''' @return: number of pairs'''172 ''':return: number of pairs''' 171 173 try: 172 174 return len(self.db[u"pairs"]) … … 176 178 def NewEpicsConfig(self, pairnum): 177 179 '''Create internal space for a new EPICS configuration 178 @param pairnum: [int] index number of the XY_pair'''180 :param pairnum: [int] index number of the XY_pair''' 179 181 pairdb = self.db[u"pairs"][pairnum] 180 182 pairdb[u"epics"] = {} … … 189 191 def GetEpicsConfig(self, pairnum): 190 192 '''Get a deep copy Python dictionary of the current EPICS PV config. 191 @param pairnum: [int] index number of the XY_pair192 @return: the current EPICS configuration'''193 :param pairnum: [int] index number of the XY_pair 194 :return: the current EPICS configuration''' 193 195 return copy.deepcopy(self.db[u"pairs"][pairnum][u"epics"]) 194 196 195 197 def SetEpicsConfig(self, pairnum, config): 196 198 '''set the current EPICS configuration 197 @param pairnum: [int] index number of the XY_pair198 @param config: Python dictionary of EPICS PV configuration'''199 :param pairnum: [int] index number of the XY_pair 200 :param config: Python dictionary of EPICS PV configuration''' 199 201 pairdb = self.db[u"pairs"][pairnum] 200 202 deep = copy.deepcopy(config) … … 203 205 def SetEpicsField(self, pairnum, axis, field, value): 204 206 '''Define the EPICS config for a specific field 205 @param pairnum: [int] index number of the XY_pair'206 @param axis: [string] "x" or "y"'207 @param field: [string] member of moxy_axis.field_list'208 @param value: [string] value of this field'''207 :param pairnum: [int] index number of the XY_pair' 208 :param axis: [string] "x" or "y"' 209 :param field: [string] member of moxy_axis.field_list' 210 :param value: [string] value of this field''' 209 211 try: 210 212 axisdb = self.db[u"pairs"][pairnum][u"epics"][axis] … … 218 220 and sets defaults for fields 219 221 220 @param pairnum: [int] index number of the XY_pair221 @param title: the title of the pair set (default="")222 @return the index number'''222 :param pairnum: [int] index number of the XY_pair 223 :param title: the title of the pair set (default="") 224 :return the index number''' 223 225 pairdb = self.db[u"pairs"][pairnum] 224 226 if not pairdb.has_key(u"tabs"): … … 232 234 def GetTabTitle(self, pairnum, tabnum): 233 235 '''return the name of the tab 234 @param pairnum: [int] index number of the XY_pair235 @param tabnum: [int] index number of the Tab object'''236 :param pairnum: [int] index number of the XY_pair 237 :param tabnum: [int] index number of the Tab object''' 236 238 return self.db[u"pairs"][pairnum][u"tabs"][tabnum][u"@name"] 237 239 238 240 def SetTabTitle(self, pairnum, tabnum, title): 239 241 '''set the name attribute of the tab 240 @param pairnum: [int] index number of the XY_pair241 @param tabnum: [int] index number of the Tab object242 @param title: [string] title the Tab object'''242 :param pairnum: [int] index number of the XY_pair 243 :param tabnum: [int] index number of the Tab object 244 :param title: [string] title the Tab object''' 243 245 self.db[u"pairs"][pairnum][u"tabs"][tabnum]["@name"] = title 244 246 245 247 def SelectTab(self, pairnum, tabnum): 246 248 '''set the selected attribute of the pair 247 @param pairnum: [int] index number of the XY_pair248 @param tabnum: [int] index number of the Tab object'''249 :param pairnum: [int] index number of the XY_pair 250 :param tabnum: [int] index number of the Tab object''' 249 251 pairdb = self.db[u"pairs"][pairnum] 250 252 for tab in pairdb[u"tabs"]: # first, deselect all tabs … … 254 256 def GetSelectedTab(self, pairnum): 255 257 '''return the index number of the selected tab 256 @param pairnum: [int] index number of the XY_pair'''258 :param pairnum: [int] index number of the XY_pair''' 257 259 selected = -1 258 260 try: … … 268 270 def CountTabs(self, pairnum): 269 271 '''return the number of tabs 270 @param pairnum: [int] index number of the XY_pair'''272 :param pairnum: [int] index number of the XY_pair''' 271 273 try: 272 274 return len(self.db[u"pairs"][pairnum][u"tabs"]) … … 278 280 and sets defaults for fields 279 281 280 @param pairnum: [int] index number of the XY_pair281 @param tabnum: [int] index number of the Tab object282 @param title: the title of the Tab object (default="")283 @return the index number'''282 :param pairnum: [int] index number of the XY_pair 283 :param tabnum: [int] index number of the Tab object 284 :param title: the title of the Tab object (default="") 285 :return the index number''' 284 286 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 285 287 if not tabdb.has_key(u"rows"): … … 295 297 def GetRowTitle(self, pairnum, tabnum, rownum): 296 298 '''return the name of the row 297 @param pairnum: [int] index number of the XY_pair298 @param tabnum: [int] index number of the Tab object299 @param rownum: [int] index number of the Row object'''299 :param pairnum: [int] index number of the XY_pair 300 :param tabnum: [int] index number of the Tab object 301 :param rownum: [int] index number of the Row object''' 300 302 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 301 303 return tabdb[u"rows"][rownum][u"@name"] … … 303 305 def SetRowTitle(self, pairnum, tabnum, rownum, title): 304 306 '''set the name attribute of the row 305 @param pairnum: [int] index number of the XY_pair306 @param tabnum: [int] index number of the Tab object307 @param rownum: [int] index number of the Row object308 @param title: [string] title the Tab object'''307 :param pairnum: [int] index number of the XY_pair 308 :param tabnum: [int] index number of the Tab object 309 :param rownum: [int] index number of the Row object 310 :param title: [string] title the Tab object''' 309 311 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 310 312 tabdb[u"rows"][rownum][u"@name"] = title … … 312 314 def GetRowXY(self, pairnum, tabnum, rownum): 313 315 '''return the name of the row 314 @param pairnum: [int] index number of the XY_pair315 @param tabnum: [int] index number of the Tab object316 @param rownum: [int] index number of the Row object'''316 :param pairnum: [int] index number of the XY_pair 317 :param tabnum: [int] index number of the Tab object 318 :param rownum: [int] index number of the Row object''' 317 319 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 318 320 x = tabdb[u"rows"][rownum][u"@x"] … … 322 324 def SetRowXY(self, pairnum, tabnum, rownum, x, y): 323 325 '''set the name attribute of the row 324 @param pairnum: [int] index number of the XY_pair325 @param tabnum: [int] index number of the Tab object326 @param x: [float] X axis position327 @param y: [float] Y axis position'''326 :param pairnum: [int] index number of the XY_pair 327 :param tabnum: [int] index number of the Tab object 328 :param x: [float] X axis position 329 :param y: [float] Y axis position''' 328 330 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 329 331 tabdb[u"rows"][rownum][u"@x"] = x … … 332 334 def CountRows(self, pairnum, tabnum): 333 335 '''return the number of rows 334 @param pairnum: [int] index number of the XY_pair335 @param tabnum: [int] index number of the Tab object'''336 :param pairnum: [int] index number of the XY_pair 337 :param tabnum: [int] index number of the Tab object''' 336 338 try: 337 339 return len(self.db[u"pairs"][pairnum][u"tabs"][tabnum][u"rows"]) … … 341 343 def GetSelectedRow(self, pairnum, tabnum): 342 344 '''return the index number of the selected row 343 @param pairnum: [int] index number of the XY_pair344 @param tabnum: [int] index number of the Tab object'''345 :param pairnum: [int] index number of the XY_pair 346 :param tabnum: [int] index number of the Tab object''' 345 347 selected = -1 346 348 try: … … 356 358 def SelectRow(self, pairnum, tabnum, rownum): 357 359 '''set the selected attribute of the pair 358 @param pairnum: [int] index number of the XY_pair359 @param tabnum: [int] index number of the Tab object360 @param rownum: [int] index number of the Row object'''360 :param pairnum: [int] index number of the XY_pair 361 :param tabnum: [int] index number of the Tab object 362 :param rownum: [int] index number of the Row object''' 361 363 tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum] 362 364 for row in tabdb[u"rows"]: # first, deselect all rows … … 367 369 '''read the settings from a file into an internal dictionary (self.db) 368 370 369 @note: this method uses xml.dom.minidom (built into all Pythons)371 :note: this method uses xml.dom.minidom (built into all Pythons) 370 372 @see: http://docs.python.org/library/xml.dom.minidom.html 371 373 ''' … … 427 429 def _get_attribute(self, node, key, default): 428 430 '''get a specific attribute or return the default 429 @param node: XML Node object430 @param key: [string] name of attribute to find431 @param default: [string] default value to return'''431 :param node: XML Node object 432 :param key: [string] name of attribute to find 433 :param default: [string] default value to return''' 432 434 value = default 433 435 if node.attributes.has_key(key): … … 437 439 def SaveXmlFile(self): 438 440 '''save the internal dictionary (self.db) to an XML file 439 @note: What about using/saving a default stylesheet?441 :note: What about using/saving a default stylesheet? 440 442 @see: http://www.boddie.org.uk/python/XML_intro.html 441 443 ''' … … 451 453 def _SetAttr(self, node, attribute, value): 452 454 '''add attributes that are not empty (but do not strip the whitespace) 453 @param node: XML Node object454 @param attribute: [string] name of attribute455 @param value: [string] value of attribute'''455 :param node: XML Node object 456 :param attribute: [string] name of attribute 457 :param value: [string] value of attribute''' 456 458 if len(value) > 0: 457 459 node.setAttribute(attribute, value) … … 459 461 def _makeTextNode(self, doc, tag, value): 460 462 '''create a text node for the XML file 461 @param doc: [xml.dom.minidom documentElement object]462 @param tag: [string]element name463 @param value: [string]element text'''463 :param doc: [xml.dom.minidom documentElement object] 464 :param str tag: element name 465 :param str value: element text''' 464 466 node = doc.createElement(tag) 465 467 text = doc.createTextNode(value) … … 469 471 def __repr__(self): 470 472 '''default representation of this structure is XML 471 @return: XML representation of internal database (db)472 @note: What about a default stylesheet?473 :return: XML representation of internal database (db) 474 :note: What about a default stylesheet? 473 475 ''' 474 476 t = datetime.datetime.now() -
moxy/trunk/src/moxy/pvsetup.py
r635 r641 14 14 Provides Python Class: PvDialog 15 15 Dialog to configure the EPICS PVs for an X,Y pair 16 17 @version: 16 ''' 17 18 18 19 ########### SVN repository information ################### 19 20 # $Date$ … … 23 24 # $Id$ 24 25 ########### SVN repository information ################### 25 '''26 26 27 27 28 28 import wx 29 import pvConnect29 import epics 30 30 import pprint 31 31 import moxy_axis … … 264 264 265 265 def __init__(self, parent, original_config): 266 '''establish the dialog box 267 @param parent: widget that owns this class 268 @param original_config: Python dictionary with axes configurations''' 266 ''' 267 establish the dialog box 268 269 :param parent: widget that owns this class 270 :param original_config: Python dictionary with axes configurations''' 269 271 # first, find the directory where this code is installed 270 272 # so the bitmaps can be found … … 286 288 287 289 def _applyConfiguration_(self, xref, config): 288 '''load/configure the widgets with the configuration of one axis 290 ''' 291 load/configure the widgets with the configuration of one axis 289 292 290 @param xref: self.widget[axis] where axis is either "x" or "y"291 @param config: dictionary of values for this axis293 :param xref: self.widget[axis] where axis is either "x" or "y" 294 :param config: dictionary of values for this axis 292 295 ''' 293 296 field = 'isMotorRec' … … 304 307 pv = xref[field].GetValue() 305 308 if len(pv) > 0: 306 state = pvConnect.testConnect(pv)309 state = self._testConnect(pv) 307 310 #print pv, state 308 311 self._SetPvColor(xref[field], state, isMotorRec) … … 312 315 Also base color choice on whether the PV is part 313 316 of a motor record or not. 314 @param widget: used as widget.SetBackgroundColour(map[state]) 315 @param state: [Boolean] Moving = True 316 @param ismotor: [Boolean] Is it an EPICS "motor" record? 317 318 :param widget: used as widget.SetBackgroundColour(map[state]) 319 :param bool state: Moving = True 320 :param bool ismotor: Is it an EPICS "motor" record? 317 321 ''' 318 322 map = { … … 325 329 326 330 def SetColor(self, axis, field): 327 '''change the background color on the given widgets 328 @param axis: [string] "x" or "y" 329 @param field: [string] member of moxy_axis.field_list''' 331 ''' 332 change the background color on the given widgets 333 334 :param str axis: "x" or "y" 335 :param str field: member of moxy_axis.field_list 336 ''' 330 337 pv = self.widget[axis][field].GetValue() 331 338 isMotorRec = self.widget[axis]['isMotorRec'].GetValue() 332 339 state = False 333 340 if len(pv) > 0: 334 state = pvConnect.testConnect(pv)341 state = self._testConnect(pv) 335 342 self._SetPvColor(self.widget[axis][field], state, isMotorRec) 336 343 337 344 def _pv_base_name(self, pv): 338 345 '''given an EPICS PV name, return the base name 339 @param pv: [string] EPICS Process Variable name 340 @return: base part of PV name 341 342 @note: _pv_base_name("the:pv:name.VAL") = "the:pv:name" 343 @note: _pv_base_name("another:name") = "another:name" 344 ''' 346 347 :param str pv: EPICS Process Variable name 348 :return: base part of PV name 349 350 :note: _pv_base_name("the:pv:name.VAL") = "the:pv:name" 351 :note: _pv_base_name("another:name") = "another:name" 352 ''' 345 353 return pv.split('.')[0] 346 354 347 355 def GetConfiguration(self): 348 ''' @return Python dictionary containing the PV info for X & Y axes'''356 ''':return Python dictionary containing the PV info for X & Y axes''' 349 357 config = {'x': {}, 'y': {}} 350 358 for axis in ['x', 'y']: … … 356 364 357 365 def SetConfiguration(self, config): 358 '''Set the configuration of the widgets. 359 @param config: Python dictionary containing the PV info for X & Y axes''' 366 ''' 367 Set the configuration of the widgets. 368 369 :param config: Python dictionary containing the PV info for X & Y axes 370 ''' 360 371 for axis in ['x', 'y']: 361 372 if config.has_key(axis): … … 363 374 364 375 def _SetIsMotorCheckbox_(self, axis): 365 '''Set/clear the "isMotorRec" checkbox if the VAL PV is/not from a motor record. 366 @param axis: [string] "x" or "y" 376 ''' 377 Set/clear the "isMotorRec" checkbox if the VAL PV is/not from a motor record. 378 379 :param str axis: "x" or "y" 367 380 ''' 368 381 base = self._pv_base_name(self.widget[axis]['VAL'].GetValue()) … … 370 383 self.widget[axis]['isMotorRec'].SetValue(isMotorRec) 371 384 385 def _testConnect(self, pv): 386 ''' 387 load/configure the widgets with the configuration of one axis 388 389 :param str pv: EPICS process variable name 390 :return: Is this PV available? 391 :rtype: bool 392 ''' 393 ch = epics.PV(pv) 394 return ch.connect() 395 396 def _getRTYP(self, pv): 397 ''' 398 Returns the record type of "pv" 399 400 :param str pv: EPICS process variable name 401 :return: EPICS record type or None if cannot connect 402 :rtype: str 403 ''' 404 if len(pv) == 0: 405 return None 406 base = pv.split('.')[0] 407 if self._testConnect(base): 408 return epics.caget(base + '.RTYP') 409 else: 410 return None 411 372 412 def _isMotorRec_(self, pv): 373 '''test if the given PV is a motor record 374 @param pv: [string] EPICS Process Variable name''' 375 return pvConnect.GetRTYP(pv) == 'motor' 413 ''' 414 test if the given PV is a motor record 415 416 :param pv: [string] EPICS Process Variable name 417 ''' 418 return self._getRTYP(pv) == 'motor' 376 419 377 420 def _clear_axis(self, axis): 378 '''clear all the fields on the named axis 379 @param axis: [string] "x" or "y"''' 421 ''' 422 clear all the fields on the named axis 423 424 :param str axis: "x" or "y" 425 ''' 380 426 config = {'isMotorRec': False} 381 427 for field in moxy_axis.field_list: … … 388 434 389 435 def OnPv_x_dmovTextEnter(self, event): 390 '''set background color 391 @param event: wxPython event object''' 436 ''' 437 set background color 438 439 :param event: wxPython event object 440 ''' 392 441 self.SetColor('x', 'DMOV') 393 442 394 443 def OnPv_y_dmovTextEnter(self, event): 395 '''set background color 396 @param event: wxPython event object''' 444 ''' 445 set background color 446 447 :param event: wxPython event object 448 ''' 397 449 self.SetColor('y', 'DMOV') 398 450 399 451 def OnPv_x_valTextEnter(self, event): 400 '''set background color and 'isMotorRec' checkbox for X axis 401 @param event: wxPython event object''' 452 ''' 453 set background color and 'isMotorRec' checkbox for X axis 454 455 :param event: wxPython event object 456 ''' 402 457 self.SetColor('x', 'VAL') 403 458 self._SetIsMotorCheckbox_('x') 404 459 405 460 def OnPv_y_valTextEnter(self, event): 406 '''set background color and 'isMotorRec' checkbox for Y axis 407 @param event: wxPython event object''' 461 ''' 462 set background color and 'isMotorRec' checkbox for Y axis 463 464 :param event: wxPython event object 465 ''' 408 466 self.SetColor('y', 'VAL') 409 467 self._SetIsMotorCheckbox_('y') 410 468 411 469 def OnPv_x_rbvTextEnter(self, event): 412 '''set background color 413 @param event: wxPython event object''' 470 ''' 471 set background color 472 473 :param event: wxPython event object 474 ''' 414 475 self.SetColor('x', 'RBV') 415 476 416 477 def OnPv_y_rbvTextEnter(self, event): 417 '''set background color 418 @param event: wxPython event object''' 478 ''' 479 set background color 480 481 :param event: wxPython event object 482 ''' 419 483 self.SetColor('y', 'RBV') 420 484 421 485 def OnPv_x_descTextEnter(self, event): 422 '''set background color 423 @param event: wxPython event object''' 486 ''' 487 set background color 488 489 :param event: wxPython event object 490 ''' 424 491 self.SetColor('x', 'DESC') 425 492 426 493 def OnPv_y_descTextEnter(self, event): 427 '''set background color 428 @param event: wxPython event object''' 494 ''' 495 set background color 496 497 :param event: wxPython event object 498 ''' 429 499 self.SetColor('y', 'DESC') 430 500 431 501 def OnPv_x_eguTextEnter(self, event): 432 '''set background color 433 @param event: wxPython event object''' 502 ''' 503 set background color 504 505 :param event: wxPython event object 506 ''' 434 507 self.SetColor('x', 'EGU') 435 508 436 509 def OnPv_y_eguTextEnter(self, event): 437 '''set background color 438 @param event: wxPython event object''' 510 ''' 511 set background color 512 513 :param event: wxPython event object 514 ''' 439 515 self.SetColor('y', 'EGU') 440 516 441 517 def OnPv_x_stopTextEnter(self, event): 442 '''set background color 443 @param event: wxPython event object''' 518 ''' 519 set background color 520 521 :param event: wxPython event object 522 ''' 444 523 self.SetColor('x', 'STOP') 445 524 446 525 def OnPv_y_stopTextEnter(self, event): 447 '''set background color 448 @param event: wxPython event object''' 526 ''' 527 set background color 528 529 :param event: wxPython event object 530 ''' 449 531 self.SetColor('y', 'STOP') 450 532 451 533 def OnButton_okButton(self, event): 452 '''Handler for the cancel button. 453 The default behavior will handle all that is needed here. 454 455 @param event: wxPython event object 534 ''' 535 Handler for the cancel button. 536 The default behavior will handle all that is needed here. 537 538 :param event: wxPython event object 456 539 ''' 457 540 event.Skip() 458 541 459 542 def OnButton_cancelButton(self, event): 460 '''Handler for the cancel button. 461 The default behavior will handle all that is needed here. 462 463 There is no chance to restore the original 464 configuration before the dialog returns. The calling 465 routine must determine if the result was wx.ID_OK 466 before calling dlg.GetConfiguration(). 467 468 @param event: wxPython event object 543 ''' 544 Handler for the cancel button. 545 The default behavior will handle all that is needed here. 546 547 There is no chance to restore the original 548 configuration before the dialog returns. The calling 549 routine must determine if the result was wx.ID_OK 550 before calling dlg.GetConfiguration(). 551 552 :param event: wxPython event object 469 553 ''' 470 554 event.Skip() 471 555 472 556 def OnButton_clear_x_Button(self, event): 473 '''clear all the fields on the X axis 474 @param event: wxPython event object''' 557 ''' 558 clear all the fields on the X axis 559 560 :param event: wxPython event object 561 ''' 475 562 self._clear_axis('x') 476 563 477 564 def OnButton_clear_y_Button(self, event): 478 '''clear all the fields on the Y axis 479 @param event: wxPython event object''' 565 ''' 566 clear all the fields on the Y axis 567 568 :param event: wxPython event object 569 ''' 480 570 self._clear_axis('y') 481 571 482 572 def OnButton_revertButton(self, event): 483 '''reset all the fields on both axes to original values 484 @param event: wxPython event object''' 573 ''' 574 reset all the fields on both axes to original values 575 576 :param event: wxPython event object 577 ''' 485 578 self.SetConfiguration(self.original_config) 486 579 … … 490 583 config = { 491 584 'x': { 492 # USAXS a1y: 32idbLAX:m58:c1:m1493 585 'isMotorRec': True, 494 'VAL': ' 32idbLAX:m58:c1:m1.VAL'586 'VAL': 'prj:m1.VAL' 495 587 }, 496 588 'y': { 497 # USAXS a2y: 32idbLAX:m58:c1:m2498 589 'isMotorRec': False, 499 'VAL': ' 32idbLAX:m58:c1:m2.VAL',500 'RBV': ' 32idbLAX:m58:c1:m2.RBV',501 'EGU': ' 32idbLAX:m58:c1:m2.EGU',502 'DESC': ' 32idbLAX:m58:c1:m2.DESC',503 'DMOV': ' 32idbLAX:m58:c1:m2.DMOV',504 'STOP': ' 32idbLAX:m58:c1:m2.STOP'590 'VAL': 'prj:m2.VAL', 591 'RBV': 'prj:m2.RBV', 592 'EGU': 'prj:m2.EGU', 593 'DESC': 'prj:m2.DESC', 594 'DMOV': 'prj:m2.DMOV', 595 'STOP': 'prj:m2.STOP' 505 596 } 506 597 } … … 517 608 dlg.Destroy() 518 609 app.MainLoop() 519 pvConnect.on_exit() -
moxy/trunk/src/moxy/version.py
r635 r641 31 31 "", 32 32 "other contributors:", 33 " Geoff Savage/FNAL and John Hammonds/APS for CaChannel",33 "Matt Newville/CARS for PyEpics", 34 34 "Tim Mooney/APS for ca_util"] 35 35 __company_name__ = "Advanced Photon Source" 36 __version__ = "0. 5"37 __copyright__ = "(c) 2009 , 2010"36 __version__ = "0.6" 37 __copyright__ = "(c) 2009 - 2011" 38 38 #fp = open('LICENSE', 'r') 39 39 #__license__ = fp.read()
Note: See TracChangeset
for help on using the changeset viewer.