Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/TCC/html/axis_device_set_8py_source.html
Дата изменения: Tue Sep 15 02:25:37 2015
Дата индексирования: Sun Apr 10 03:33:33 2016
Кодировка:

Поисковые слова: star
lsst.tcc: python/tcc/axis/axisDeviceSet.py Source File
lsst.tcc  1.2.2-3-g89ecb63
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
axisDeviceSet.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
2 
3 import itertools
4 
5 from twistedActor import DeviceSet, log, LinkCommands, UserCmd, expandUserCmd
6 
7 import tcc.base
8 from tcc.util import secInDayFromDate
9 from tcc.msg import formatAxisCmdStateAndErr
10 from .axisDevice import AxisStatus, AxisDevice
11 
12 __all__ = ["AxisDeviceSet"]
13 
14 StatusDelay = 0.1 # delay of status after MOVE P V T or other commands that change status
15 
16 class AxisDeviceSet(DeviceSet):
17  """!Axis devices
18  """
19  DefaultTimeLim = AxisDevice.DefaultTimeLim
20  DefaultInitTimeLim = AxisDevice.DefaultInitTimeLim
21  SlotList = ("az", "alt", "rot")
22  def __init__(self, actor, devList):
23  """!Construct an AxisDeviceSet
24 
25  @param[in] actor actor (instance of twistedActor.BaseActor);
26  items used include writeToUsers, queueStatus, obj, inst and axeLim
27  @param[in] devList az, alt and rot device; any can be None if it does not exist
28 
29  @throw RuntimeError if len(devList) != 3
30  """
31  DeviceSet.__init__(self,
32  actor = actor,
33  slotList = self.SlotList,
34  devList = devList,
35  connStateKeyword = "axisConnState",
36  )
37  self._currStatusCmd = None
38  self._prevReportedStatusList = [AxisStatus() for slot in self.slotList]
39 
40  def connect(self, slotList=None, userCmd=None, timeLim=DefaultInitTimeLim):
41  """Connect the specified axis controllers
42 
43  Overridden because connecting can be slow, presumably due to the multiplexor
44  """
45  return DeviceSet.connect(self, slotList=slotList, userCmd=userCmd, timeLim=timeLim)
46 
47  def connectOrInit(self, slotList=None, userCmd=None, timeLim=DefaultInitTimeLim):
48  """!Connect and initialize axis controllers
49 
50  Specified axis controllers that are already connected are simply initialized.
51 
52  @param[in] slotList collection of slot names, or None for all filled slots
53  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
54  if None a new UserCmd is created and returned
55  @param[in] timeLim time limit for init and connect command (sec)
56  uses a longer than default time limit because connecting can be slow due to the multiplexor
57  @return userCmd: the supplied userCmd or a newly created UserCmd
58  """
59  # print "connectOrInit(slotList=%r, userCmd=%r, timeLim=%s)" % (slotList, userCmd, timeLim)
60  expSlotList = self.expandSlotList(slotList)
61  connSlotList = [slot for slot in expSlotList if self.get(slot).isConnected]
62  notConnSlotList = list(set(expSlotList) - set(connSlotList))
63  initUserCmd = self.init(connSlotList, timeLim=timeLim)
64  connUserCmd = self.connect(notConnSlotList, timeLim=timeLim)
65  if userCmd is None:
66  userCmd = UserCmd()
67  LinkCommands(userCmd, (initUserCmd, connUserCmd))
68  return userCmd
69 
70  def disconnect(self, slotList=None, userCmd=None, timeLim=DefaultInitTimeLim):
71  """Disconnect the specified axis controllers
72 
73  Overridden because disconnecting can be slow
74  """
75  return DeviceSet.disconnect(self, slotList=slotList, userCmd=userCmd, timeLim=timeLim)
76 
77  def drift(self, slotList=None, userCmd=None, timeLim=DefaultTimeLim):
78  """!Execute a DRIFT command and update self.actor.obj
79 
80  If drift fails for any axes then initialize all axes and update self.actor.obj
81 
82  @param[in] slotList collection of slot names, or None for all filled slots
83  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
84  if None a new UserCmd is created and returned
85  @param[in] timeLim time limit for command (sec)
86  @return userCmd: the supplied userCmd or a newly created UserCmd
87 
88  @throw RuntimeError if slotList has empty or non-existent slots
89  """
90  return self.startCmd(cmdStrOrList="DRIFT", slotList=slotList, userCmd=userCmd, callFunc=self._initAllOnFailure, timeLim=timeLim)
91 
92  def init(self, slotList=None, userCmd=None, timeLim=DefaultInitTimeLim):
93  """!Initialize the axes controllers
94 
95  @param[in] slotList collection of slot names, or None for all filled slots
96  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
97  if None a new UserCmd is created and returned
98  @param[in] timeLim time limit for init and connect command (sec)
99  @return userCmd: the supplied userCmd or a newly created UserCmd
100  """
101  # print "%s.init(slotList=%s)"%(self, slotList)
102  slotList = self.expandSlotList(slotList)
103  userCmd = expandUserCmd(userCmd)
104  subCmdList = []
105  # update axes state to halting
106  self._setObjForInit(slotList=slotList, halted=False)
107  for slot in slotList:
108  dev = self.get(slot)
109  subCmdList.append(dev.init(timeLim=timeLim))
110  LinkCommands(userCmd, subCmdList)
111  return userCmd
112 
113  def movePVT(self, pvtList, userCmd=None, timeLim=DefaultTimeLim):
114  """!Execute a MOVE Pos Vel Time or MOVE command for each axis
115 
116  If any axis fails, INIT that axis and update self.actor.obj
117 
118  As soon as the MOVE Pos Vel Time command is sent, schedule a status command.
119 
120  @param[in] pvtList list of PVTs or PVAJTs, one per axis; isfinite() must be false for nonexistent axes
121  and any axis you don't want moved
122  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
123  if None a new UserCmd is created and returned
124  @param[in] timeLim time limit for command (sec)
125  @return userCmd: the supplied userCmd or a newly created UserCmd
126  """
127  if len(pvtList) != len(self):
128  raise RuntimeError("pvtList must have %d items; pvtList=%s" % (len(self), pvtList))
129 
130  cmdDict = dict()
131  for pvt, (slot, dev) in itertools.izip(pvtList, self._slotDevDict.iteritems()):
132  if dev:
133  if pvt.isfinite():
134  cmdDict[slot] = "MOVE %0.7f %0.7f %0.5f" % (pvt.pos, pvt.vel, secInDayFromDate(pvt.t))
135  else:
136  cmdDict[slot] = "MOVE"
137  self.actor.queueStatus(StatusDelay)
138  return self.startCmdDict(cmdDict=cmdDict, userCmd=userCmd, timeLim=timeLim)
139 
140  def plusMovePV(self, pvtList, userCmd=None, timeLim=DefaultTimeLim):
141  """!Execute a +MOVE Pos Vel or MOVE command for each axis
142 
143  If any axis fails, INIT that axis and update self.actor.obj
144 
145  As soon as the +MOVE Pos Vel command is sent, schedule a status command.
146 
147  @param[in] pvtList list of PVTs or PVAJTs, one per axis; isfinite() must be false for nonexistent axes
148  and any axis you don't want moved
149  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
150  if None a new UserCmd is created and returned
151  @param[in] timeLim time limit for command (sec)
152  @return userCmd: the supplied userCmd or a newly created UserCmd
153  """
154  if len(pvtList) != len(self):
155  raise RuntimeError("pvtList must have %d items; pvtList=%s" % (len(self), pvtList))
156 
157  cmdDict = dict()
158  for pvt, (slot, dev) in itertools.izip(pvtList, self._slotDevDict.iteritems()):
159  if dev:
160  if pvt.isfinite():
161  cmdDict[slot] = "+MOVE %0.7f %0.7f" % (pvt.pos, pvt.vel)
162  else:
163  cmdDict[slot] = "MOVE"
164  self.actor.queueStatus(StatusDelay)
165  return self.startCmdDict(cmdDict=cmdDict, userCmd=userCmd, timeLim=timeLim)
166 
167  def startSlew(self, pathList, doAbsRefCorr, userCmd=None, timeLim=DefaultTimeLim):
168  """!Execute a set if MOVE Pos Vel Time commands or one MOVE command for each axis
169 
170  If any axis fails, INIT that axis and update self.actor.obj
171 
172  As soon as the commands are sent, schedule a status command.
173 
174  @param[in] pathList list of pvtLists, one per slot;
175  if pathList[slot] is an empty list, then that device is halted immediately (if it exists);
176  pathList[slot] must be an empty list if that slot has no device
177  @param[in] doAbsRefCorr apply absolute fiducial corrections during this slew?
178  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
179  if None a new UserCmd is created and returned
180  @param[in] timeLim time limit for command (sec)
181  @return userCmd: the supplied userCmd or a newly created UserCmd
182  """
183  if len(pathList) != len(self):
184  raise RuntimeError("pathList must have %d items; pathList=%s" % (len(self), pathList))
185 
186  cmdDict = dict()
187  for pvtList, (slot, dev) in itertools.izip(pathList, self._slotDevDict.iteritems()):
188  if dev:
189  if len(pvtList) > 0:
190  cmdDict[slot] = ["MOVE %0.7f %0.7f %0.5f" % (pvt.pos, pvt.vel, secInDayFromDate(pvt.t)) for pvt in pvtList]
191  if doAbsRefCorr:
192  cmdDict[slot] += ["MS.ON", "MS.OFF %0.5f" % (secInDayFromDate(pvtList[-1].t),)]
193  else:
194  cmdDict[slot] = ["MOVE"]
195  self.actor.queueStatus(StatusDelay)
196  return self.startCmdDict(cmdDict=cmdDict, userCmd=userCmd, timeLim=timeLim)
197 
198  def status(self, slotList=None, userCmd=None, timeLim=DefaultTimeLim):
199  """!Execute a STATUS command and update self.actor.obj
200 
201  @param[in] slotList collection of slot names, or None for all filled and connected slots
202  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
203  if None a new UserCmd is created and returned
204  @param[in] timeLim time limit for command (sec)
205  @return userCmd: the supplied userCmd or a newly created UserCmd
206 
207  @throw RuntimeError if slotList has empty or non-existent slots
208  """
209  self.showConnState(userCmd=userCmd)
210  slotList = self.expandSlotList(slotList, connOnly=True)
211  self.actor.queueStatus()
212  self._currStatusCmd = userCmd
213  return self.startCmd(cmdStrOrList="STATUS", slotList=slotList, userCmd=userCmd, timeLim=timeLim)
214 
215  def stop(self, slotList=None, userCmd=None, timeLim=DefaultTimeLim):
216  """!Halt one or more axes and udpate self.actor.obj
217 
218  If any axis fails, INIT that axis and update self.actor.obj
219 
220  @param[in] slotList collection of slot names, or None for all filled slots
221  @param[in] userCmd user command whose set state is set to Done or Failed when all device commands are done;
222  if None a new UserCmd is created and returned
223  @param[in] timeLim time limit for command (sec)
224  @return userCmd: the supplied userCmd or a newly created UserCmd
225 
226  @throw RuntimeError if slotList has empty or non-existent slots
227  """
228  # slotList = self.expandSlotList(slotList)
229  # update axes state to halting
230  self._setObjForInit(slotList=self.expandSlotList(slotList), halted=False)
231  return self.startCmd(cmdStrOrList="MOVE", slotList=slotList, userCmd=userCmd, timeLim=timeLim)
232 
233  def _addDevCallbacks(self, dev, slot):
234  """!Called when adding a device
235 
236  Called after device is registered in slot dictionary, but possibly before it is connected.
237  Use to add callbacks to the device.
238 
239  @param[in] dev device that has been removed
240  @param[in] slot slot the device occupied
241  """
242  DeviceSet._addDevCallbacks(self, dev, slot)
243  dev.driftCallFunc = self._driftCallback
244  dev.initCallFunc = self._initCallback
245  dev.statusCallFunc = self._statusCallback
246 
247  def _removeDevCallbacks(self, dev, slot):
248  """!Called when removing a device
249 
250  Called after the device is deregistered from the slot dictionarhy, but before it is disconnected.
251  Use this to remove all callbacks from the device and clear information about it.
252 
253  @param[in] dev device that has been removed
254  @param[in] slot slot the device occupied
255  """
256  DeviceSet._removeDevCallbacks(self, dev, slot)
257  dev.driftCallFunc = None
258  dev.initCallFunc = None
259  dev.statusCallFunc = None
260 
261  ind = self.getIndex(slot)
262  currTAI = tcc.base.tai()
263  self.actor.obj.actMount[ind].invalidate(currTAI)
264  self.actor.obj.axisStatusWord[ind] = 0
265  self.actor.obj.axisStatusTime[ind] = currTAI
266 
267  def _initAllOnFailure(self, cmdInfo):
268  """!Callback for a command that, if it fails, all axes should be initialized
269 
270  This will work with any command, though I suspect only the DRIFT command is sufficiently dangerous
271  to justify initializing all axes if DRIFT fails for one axis. One might argument that MOVE P V T
272  also qualifies, but at least the axis controller will halt an axis once time runs outo n a MOVE P V T,
273  wheras it won't halt for DRIFT until the axis reaches a limit.
274 
275  @param[in] cmdInfo info for device command, an instance of twistedActor.DevCmdInfo
276  """
277  if cmdInfo.devCmd.didFail:
278  if not cmdInfo.userCmd.isDone:
279  cmdInfo.userCmd.setState(
280  cmdInfo.userCmd.Failed,
281  textMsg = "%s %s failed, initializing ALL axes: %s" % \
282  (cmdInfo.devCmd.dev.name, cmdInfo.devCmd.cmdStr, cmdInfo.devCmd.getMsg()),
283  )
284  log.error("%s %s failed; initializing ALL axes" % (self, cmdInfo.devCmd))
285  self.init()
286 
287  def _driftCallback(self, dev):
288  """!Callback when device parses reply from DRIFT
289 
290  This callback does nothing unless this device is currently in use;
291  that is why this function is in AxisDeviceSet instead of AxisDevice.
292  """
293  # print "%s._driftCallback(dev=%r)" % (self, dev)
294  slot = self.slotFromDevName(dev.name)
295  if slot is None:
296  return
297 
298  ind = self.getIndex(slot)
299  self.actor.obj.actMount[ind] = dev.status.pvt
300  log.info("%s._driftCallback set self.actor.obj.actMount[%s] = %s" % (self, ind, self.actor.obj.actMount[ind]))
301 
302  def _setObjForInit(self, slotList, halted=True):
303  """!Set command state, error code, and target mount for each axis
304  in devList.
305 
306  @param[in] slotList: list of device slots for which to update state
307  @param[in] halted: bool, if True set axes to halted, else set to Halting
308  """
309  # print("_setObjForInit", slotList, str(halted))
310  axisState = tcc.base.AxisState_Halted if halted else tcc.base.AxisState_Halting
311  for slot in slotList:
312  ind = self.getIndex(slot)
313  # print("setting axisState", ind, "to", axisState, "from", self.actor.obj.axisCmdState[ind])
314  # print("setting axisErrCode", ind, "to", tcc.base.AxisErr_HaltRequested, "from", self.actor.obj.axisErrCode[ind])
315  if self.actor.obj.axisCmdState[ind] != tcc.base.AxisState_Halted:
316  # if the obj block is already halted, don't set the axis state.
317  self.actor.obj.axisCmdState[ind] = axisState
318  self.actor.obj.axisErrCode[ind] = tcc.base.AxisErr_HaltRequested
319  self.actor.obj.targetMount[ind].invalidate(tcc.base.tai())
320  msgCode, msgStr = formatAxisCmdStateAndErr(self.actor.obj)
321  if msgStr:
322  self.actor.writeToUsers(msgCode=msgCode, msgStr=msgStr)
323 
324  def _initCallback(self, dev):
325  """!Callback when a device sends INIT or MOVE
326 
327  This callback does nothing unless this device is currently in use;
328  that is why this function is in AxisDeviceSet instead of AxisDevice.
329  """
330  # print "%s._initCallback(dev=%r)" % (self, dev)
331  slot = self.slotFromDevName(dev.name)
332  if slot is None:
333  return
334  self._setObjForInit(slotList=[slot], halted=True)
335  self.actor.queueStatus(1)
336 
337  def _statusCallback(self, dev):
338  """!Callback when device parses new status
339 
340  This callback does nothing unless this device is currently in use;
341  that is why this function is in AxisDeviceSet instead of AxisDevice.
342  """
343  # print "%s._statusCallback(dev=%r)" % (self, dev)
344  slot = self.slotFromDevName(dev.name)
345  if slot is None:
346  return
347 
348  ind = self.getIndex(slot)
349  self.actor.obj.actMount[ind] = dev.status.pvt
350  self.actor.obj.axisStatusWord[ind] = dev.status.statusWord
351  self.actor.obj.axisStatusTime[ind] = tcc.base.tai() # TCC's idea of time, not axis controllers
352  prevRepStatus = self._prevReportedStatusList[ind]
353  if self._currStatusCmd and not self._currStatusCmd.isDone:
354  userCmd = self._currStatusCmd
355  else:
356  userCmd = None
357 
358  if userCmd or prevRepStatus.wordOrDTimeChanged(dev.status):
359  msgCode, msgStr = dev.status.formatStatus(name=slot, axeLim=self.actor.axeLim)
360  self._prevReportedStatusList[ind] = dev.status.copy()
361  self.actor.writeToUsers(msgCode, msgStr, cmd=userCmd)
def connectOrInit
Connect and initialize axis controllers.
def startSlew
Execute a set if MOVE Pos Vel Time commands or one MOVE command for each axis.
def _setObjForInit
Set command state, error code, and target mount for each axis in devList.
def status
Execute a STATUS command and update self.actor.obj.
def stop
Halt one or more axes and udpate self.actor.obj.
def init
Initialize the axes controllers.
def _initAllOnFailure
Callback for a command that, if it fails, all axes should be initialized.
def _statusCallback
Callback when device parses new status.
def _initCallback
Callback when a device sends INIT or MOVE.
def __init__
Construct an AxisDeviceSet.
def _driftCallback
Callback when device parses reply from DRIFT.
def drift
Execute a DRIFT command and update self.actor.obj.
def movePVT
Execute a MOVE Pos Vel Time or MOVE command for each axis.
def secInDayFromDate
Convert a date to seconds in the day (losing day information)
Definition: time.py:19
def plusMovePV
Execute a +MOVE Pos Vel or MOVE command for each axis.