Changeset 641


Ignore:
Timestamp:
Sep 30, 2011 3:19:00 AM (12 years ago)
Author:
jemian
Message:

most code moved over to PyEpics? -- moxy.py is next

Location:
moxy/trunk/src/moxy
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • moxy/trunk/src/moxy/moxy

    r635 r641  
    22
    33# TODO: refactor this
    4 /APSshare/bin/python  /APSshare/pythonlib/moxy/moxy.py $*
     4#/APSshare/bin/python  /APSshare/pythonlib/moxy/moxy.py $*
    55
     6echo "This code is not ready to be used yet"
    67
    78########### SVN repository information ###################
  • moxy/trunk/src/moxy/moxy.py

    r635 r641  
    5050
    5151----
    52  @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
     52: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
    5656'''
    5757
    5858
    5959import wx
    60 import wxmtxy_root
    61 import pvConnect
     60import root
     61#import pvConnect
    6262import sys
    6363
    6464
    65 modules ={u'wxmtxy_htmlview': [0,
     65modules ={u'htmlview': [0,
    6666                      '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,
    6969                  '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']}
    7575
    7676
     
    8080    def OnInit(self):
    8181        '''demonstrate the use of this tool'''
    82         self.main = wxmtxy_root.create(None)
     82        self.main = root.create(None)
    8383        self.main.Show()
    8484        self.SetTopWindow(self.main)
     
    8686
    8787
    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)
     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)
    9797
    9898
     
    103103    if len(sys.argv) == 2:
    104104        settingsFile = sys.argv[1]
    105     wxmtxy_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()
     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()
    110110    application.MainLoop()
    111     on_exit(capoll_timer, None)
     111    #on_exit(capoll_timer, None)
    112112
    113113
  • moxy/trunk/src/moxy/moxy_axis.py

    r631 r641  
    2424
    2525
    26 import pvConnect
     26import epics
    2727import pprint
    2828import copy
     
    3434
    3535class 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    '''
    3751
    3852    def __init__(self):
    3953        '''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
    4358        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)
    4580
    4681    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        '''
    4988        failures = 0
     89       
     90        # First, find actual PV names for each field
     91        isMotorRec = self.config['isMotorRec']
     92        base = self.config['VAL'].split('.')[0]
    5093        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
    61113
    62114    def Disconnect(self):
    63115        '''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] = ""
    68121
    69122    def Stop(self):
    70123        '''Send a STOP to EPICS'''
    71124        field = 'STOP'
    72         ch = self.db[field].GetConnection()
    73         ch.chan.putw(1)
     125        ch = self.db[field]
     126        ch.put(1)
    74127
    75128    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        '''
    77134        field = 'VAL'
    78         ch = self.db[field].GetConnection()
     135        ch = self.db[field]
    79136        #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)
    147185
    148186
    149187# example code follows
    150188
     189def 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']
    151197
    152198def _main_callback(epics_args, user_args):
     
    161207    config = {
    162208        'x': {
    163             # USAXS a1y: 32idbLAX:m58:c1:m1
    164209            'isMotorRec': True,
    165             'VAL': '32idbLAX:m58:c1:m1.VAL'
     210            'VAL': 'prj:m1.VAL'
    166211        },
    167212        'y': {
    168             # USAXS a2y: 32idbLAX:m58:c1:m2
    169213            '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'
    176220        },
    177         'sr': {
    178             # USAXS a1y: 32idbLAX:m58:c1:m1
    179             'isMotorRec': False,
    180             'VAL': 'S:SRcurrentAI'
    181         }
    182221    }
    183222    axes = {}
    184223    for axis in config:
    185         item = Axis()
    186         axes[axis] = item
     224
     225        axes[axis] = item = Axis()
    187226        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']
    195231        print 'axis', axis
    196         interval = 5
    197         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   
    203239    for axis in config:
    204240        axes[axis].Disconnect()
    205     pvConnect.on_exit()
  • moxy/trunk/src/moxy/moxy_xml.py

    r635 r641  
    1010#*************************************************************************
    1111
    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
    1322
    1423This Python file provides routines to read and write XML settings
     
    2029dictionary with the EPICS configuration is shown below.
    2130
    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
    7274    example_dictionary = {
    7375        'x': {
     
    99101    def __init__(self, settingsFile=None):
    100102        '''prepare the settings file
    101             @param settingsFile: [string] name of XML file with settings'''
     103            :param settingsFile: [string] name of XML file with settings'''
    102104        self.rootElement = 'moxy'
    103105        # TODO: consider supporting legacy 'wxmtxy' root elements, too
     
    106108
    107109    def GetDb(self):
    108         '''@return: database'''
     110        ''':return: database'''
    109111        return self.db
    110112
    111113    def GetSettingsFile(self):
    112         '''@return: name of XML settings file'''
     114        ''':return: name of XML settings file'''
    113115        return self.settingsFile
    114116
    115117    def SetSettingsFile(self, thefile):
    116118        '''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'''
    118120        self.settingsFile = thefile
    119121
     
    126128            and sets defaults for fields
    127129
    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'''
    130132        if self.CountPairs() == -1:
    131133            self.db[u"pairs"] = []
     
    138140    def GetPairTitle(self, pairnum):
    139141        '''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'''
    141143        return self.db[u"pairs"][pairnum][u"@name"]
    142144
    143145    def SetPairTitle(self, pairnum, title):
    144146        '''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'''
    147149        self.db[u"pairs"][pairnum][u"@name"] = title
    148150
    149151    def SelectPair(self, pairnum):
    150152        '''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'''
    152154        for pair in self.db[u"pairs"]:   # first, deselect all pairs
    153155            pair[u"@selected"] = False
     
    155157
    156158    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)'''
    158160        selected = -1
    159161        try:
     
    168170
    169171    def CountPairs(self):
    170         '''@return: number of pairs'''
     172        ''':return: number of pairs'''
    171173        try:
    172174            return len(self.db[u"pairs"])
     
    176178    def NewEpicsConfig(self, pairnum):
    177179        '''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'''
    179181        pairdb = self.db[u"pairs"][pairnum]
    180182        pairdb[u"epics"] = {}
     
    189191    def GetEpicsConfig(self, pairnum):
    190192        '''Get a deep copy Python dictionary of the current EPICS PV config.
    191             @param pairnum: [int] index number of the XY_pair
    192             @return: the current EPICS configuration'''
     193            :param pairnum: [int] index number of the XY_pair
     194            :return: the current EPICS configuration'''
    193195        return copy.deepcopy(self.db[u"pairs"][pairnum][u"epics"])
    194196
    195197    def SetEpicsConfig(self, pairnum, config):
    196198        '''set the current EPICS configuration
    197             @param pairnum: [int] index number of the XY_pair
    198             @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'''
    199201        pairdb = self.db[u"pairs"][pairnum]
    200202        deep = copy.deepcopy(config)
     
    203205    def SetEpicsField(self, pairnum, axis, field, value):
    204206        '''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'''
    209211        try:
    210212            axisdb = self.db[u"pairs"][pairnum][u"epics"][axis]
     
    218220            and sets defaults for fields
    219221
    220             @param pairnum: [int] index number of the XY_pair
    221             @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'''
    223225        pairdb = self.db[u"pairs"][pairnum]
    224226        if not pairdb.has_key(u"tabs"):
     
    232234    def GetTabTitle(self, pairnum, tabnum):
    233235        '''return the name of the tab
    234             @param pairnum: [int] index number of the XY_pair
    235             @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'''
    236238        return self.db[u"pairs"][pairnum][u"tabs"][tabnum][u"@name"]
    237239
    238240    def SetTabTitle(self, pairnum, tabnum, title):
    239241        '''set the name attribute of the tab
    240             @param pairnum: [int] index number of the XY_pair
    241             @param tabnum: [int] index number of the Tab object
    242             @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'''
    243245        self.db[u"pairs"][pairnum][u"tabs"][tabnum]["@name"] = title
    244246
    245247    def SelectTab(self, pairnum, tabnum):
    246248        '''set the selected attribute of the pair
    247             @param pairnum: [int] index number of the XY_pair
    248             @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'''
    249251        pairdb = self.db[u"pairs"][pairnum]
    250252        for tab in pairdb[u"tabs"]:   # first, deselect all tabs
     
    254256    def GetSelectedTab(self, pairnum):
    255257        '''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'''
    257259        selected = -1
    258260        try:
     
    268270    def CountTabs(self, pairnum):
    269271        '''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'''
    271273        try:
    272274            return len(self.db[u"pairs"][pairnum][u"tabs"])
     
    278280            and sets defaults for fields
    279281
    280             @param pairnum: [int] index number of the XY_pair
    281             @param tabnum: [int] index number of the Tab object
    282             @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'''
    284286        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    285287        if not tabdb.has_key(u"rows"):
     
    295297    def GetRowTitle(self, pairnum, tabnum, rownum):
    296298        '''return the name of the row
    297             @param pairnum: [int] index number of the XY_pair
    298             @param tabnum: [int] index number of the Tab object
    299             @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'''
    300302        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    301303        return tabdb[u"rows"][rownum][u"@name"]
     
    303305    def SetRowTitle(self, pairnum, tabnum, rownum, title):
    304306        '''set the name attribute of the row
    305             @param pairnum: [int] index number of the XY_pair
    306             @param tabnum: [int] index number of the Tab object
    307             @param rownum: [int] index number of the Row object
    308             @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'''
    309311        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    310312        tabdb[u"rows"][rownum][u"@name"] = title
     
    312314    def GetRowXY(self, pairnum, tabnum, rownum):
    313315        '''return the name of the row
    314             @param pairnum: [int] index number of the XY_pair
    315             @param tabnum: [int] index number of the Tab object
    316             @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'''
    317319        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    318320        x = tabdb[u"rows"][rownum][u"@x"]
     
    322324    def SetRowXY(self, pairnum, tabnum, rownum, x, y):
    323325        '''set the name attribute of the row
    324             @param pairnum: [int] index number of the XY_pair
    325             @param tabnum: [int] index number of the Tab object
    326             @param x: [float] X axis position
    327             @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'''
    328330        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    329331        tabdb[u"rows"][rownum][u"@x"] = x
     
    332334    def CountRows(self, pairnum, tabnum):
    333335        '''return the number of rows
    334             @param pairnum: [int] index number of the XY_pair
    335             @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'''
    336338        try:
    337339            return len(self.db[u"pairs"][pairnum][u"tabs"][tabnum][u"rows"])
     
    341343    def GetSelectedRow(self, pairnum, tabnum):
    342344        '''return the index number of the selected row
    343             @param pairnum: [int] index number of the XY_pair
    344             @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'''
    345347        selected = -1
    346348        try:
     
    356358    def SelectRow(self, pairnum, tabnum, rownum):
    357359        '''set the selected attribute of the pair
    358             @param pairnum: [int] index number of the XY_pair
    359             @param tabnum: [int] index number of the Tab object
    360             @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'''
    361363        tabdb = self.db[u"pairs"][pairnum][u"tabs"][tabnum]
    362364        for row in tabdb[u"rows"]:   # first, deselect all rows
     
    367369        '''read the settings from a file into an internal dictionary (self.db)
    368370
    369             @note: this method uses xml.dom.minidom (built into all Pythons)
     371            :note: this method uses xml.dom.minidom (built into all Pythons)
    370372            @see: http://docs.python.org/library/xml.dom.minidom.html
    371373        '''
     
    427429    def _get_attribute(self, node, key, default):
    428430        '''get a specific attribute or return the default
    429             @param node: XML Node object
    430             @param key: [string] name of attribute to find
    431             @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'''
    432434        value = default
    433435        if node.attributes.has_key(key):
     
    437439    def SaveXmlFile(self):
    438440        '''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?
    440442           @see: http://www.boddie.org.uk/python/XML_intro.html
    441443        '''
     
    451453    def _SetAttr(self, node, attribute, value):
    452454        '''add attributes that are not empty (but do not strip the whitespace)
    453             @param node: XML Node object
    454             @param attribute: [string] name of attribute
    455             @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'''
    456458        if len(value) > 0:
    457459            node.setAttribute(attribute, value)
     
    459461    def _makeTextNode(self, doc, tag, value):
    460462        '''create a text node for the XML file
    461             @param doc: [xml.dom.minidom documentElement object]
    462             @param tag: [string] element name
    463             @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'''
    464466        node = doc.createElement(tag)
    465467        text = doc.createTextNode(value)
     
    469471    def __repr__(self):
    470472        '''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?
    473475        '''
    474476        t = datetime.datetime.now()
  • moxy/trunk/src/moxy/pvsetup.py

    r635 r641  
    1414Provides Python Class: PvDialog
    1515   Dialog to configure the EPICS PVs for an X,Y pair
    16 
    17 @version:
     16'''
     17
     18
    1819########### SVN repository information ###################
    1920# $Date$
     
    2324# $Id$
    2425########### SVN repository information ###################
    25 '''
    2626
    2727
    2828import wx
    29 import pvConnect
     29import epics
    3030import pprint
    3131import moxy_axis
     
    264264
    265265    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'''
    269271        # first, find the directory where this code is installed
    270272        # so the bitmaps can be found
     
    286288
    287289    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
    289292           
    290             @param xref:  self.widget[axis] where axis is either "x" or "y"
    291             @param config:  dictionary of values for this axis
     293        :param xref:  self.widget[axis] where axis is either "x" or "y"
     294        :param config:  dictionary of values for this axis
    292295        '''
    293296        field = 'isMotorRec'
     
    304307            pv = xref[field].GetValue()
    305308            if len(pv) > 0:
    306                 state = pvConnect.testConnect(pv)
     309                state = self._testConnect(pv)
    307310                #print pv, state
    308311            self._SetPvColor(xref[field], state, isMotorRec)
     
    312315           Also base color choice on whether the PV is part
    313316           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? 
    317321        '''
    318322        map = {
     
    325329
    326330    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        '''
    330337        pv = self.widget[axis][field].GetValue()
    331338        isMotorRec = self.widget[axis]['isMotorRec'].GetValue()
    332339        state = False
    333340        if len(pv) > 0:
    334             state = pvConnect.testConnect(pv)
     341            state = self._testConnect(pv)
    335342        self._SetPvColor(self.widget[axis][field], state, isMotorRec)
    336343
    337344    def _pv_base_name(self, pv):
    338345        '''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        '''
    345353        return pv.split('.')[0]
    346354
    347355    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'''
    349357        config = {'x': {}, 'y': {}}
    350358        for axis in ['x', 'y']:
     
    356364
    357365    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        '''
    360371        for axis in ['x', 'y']:
    361372            if config.has_key(axis):
     
    363374
    364375    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"
    367380        '''
    368381        base = self._pv_base_name(self.widget[axis]['VAL'].GetValue())
     
    370383        self.widget[axis]['isMotorRec'].SetValue(isMotorRec)
    371384
     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
    372412    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'
    376419
    377420    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        '''
    380426        config = {'isMotorRec': False}
    381427        for field in moxy_axis.field_list:
     
    388434
    389435    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        '''
    392441        self.SetColor('x', 'DMOV')
    393442
    394443    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        '''
    397449        self.SetColor('y', 'DMOV')
    398450
    399451    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        '''
    402457        self.SetColor('x', 'VAL')
    403458        self._SetIsMotorCheckbox_('x')
    404459
    405460    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        '''
    408466        self.SetColor('y', 'VAL')
    409467        self._SetIsMotorCheckbox_('y')
    410468
    411469    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        '''
    414475        self.SetColor('x', 'RBV')
    415476
    416477    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        '''
    419483        self.SetColor('y', 'RBV')
    420484
    421485    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        '''
    424491        self.SetColor('x', 'DESC')
    425492
    426493    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        '''
    429499        self.SetColor('y', 'DESC')
    430500
    431501    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        '''
    434507        self.SetColor('x', 'EGU')
    435508
    436509    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        '''
    439515        self.SetColor('y', 'EGU')
    440516
    441517    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        '''
    444523        self.SetColor('x', 'STOP')
    445524
    446525    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        '''
    449531        self.SetColor('y', 'STOP')
    450532
    451533    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
    456539        '''
    457540        event.Skip()
    458541
    459542    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
    469553        '''
    470554        event.Skip()
    471555
    472556    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        '''
    475562        self._clear_axis('x')
    476563
    477564    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        '''
    480570        self._clear_axis('y')
    481571
    482572    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        '''
    485578        self.SetConfiguration(self.original_config)
    486579
     
    490583    config = {
    491584        'x': {
    492             # USAXS a1y: 32idbLAX:m58:c1:m1
    493585            'isMotorRec': True,
    494             'VAL': '32idbLAX:m58:c1:m1.VAL'
     586            'VAL': 'prj:m1.VAL'
    495587        },
    496588        'y': {
    497             # USAXS a2y: 32idbLAX:m58:c1:m2
    498589            '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'
    505596        }
    506597    }
     
    517608        dlg.Destroy()
    518609    app.MainLoop()
    519     pvConnect.on_exit()
  • moxy/trunk/src/moxy/version.py

    r635 r641  
    3131       "",
    3232       "other contributors:",
    33        "Geoff Savage/FNAL and John Hammonds/APS for CaChannel",
     33       "Matt Newville/CARS for PyEpics",
    3434       "Tim Mooney/APS for ca_util"]
    3535__company_name__ = "Advanced Photon Source"
    36 __version__ = "0.5"
    37 __copyright__ = "(c) 2009, 2010"
     36__version__ = "0.6"
     37__copyright__ = "(c) 2009 - 2011"
    3838#fp = open('LICENSE', 'r')
    3939#__license__ = fp.read()
Note: See TracChangeset for help on using the changeset viewer.