def __call__(self): """If the script window exists, bring it to the front. Otherwise, load the script file into a new script window. """ # print "ScriptLoader.doMenu(); tlName=%s" % (tlName,) tl = self.tuiModel.tlSet.getToplevel(self.tlName) if tl: tl.makeVisible() else: try: self.tuiModel.tlSet.createToplevel( name=self.tlName, resizable=False, wdgFunc=self.makeWdg, ) except Exception as e: if self.showErrDialog: tkMessageBox.showerror( message= "Could not load script:\n%r\n%s\n(See console for more info.)" % (self.fullPath, strFromException(e)), ) else: self.tuiModel.logMsg( msgStr="Could not load script: %r: %s" % (self.fullPath, strFromException(e)), severity=RO.Constants.sevWarning, )
def parseAndDispatchCmd(self, cmd): """Dispatch the user command @param[in] cmd user command (a twistedActor.UserCmd) """ if not cmd.cmdBody: # echo to show alive self.writeToOneUser(":", "", cmd=cmd) return try: cmd.parsedCmd = self.cmdParser.parseLine(cmd.cmdBody) except Exception as e: cmd.setState(cmd.Failed, "Could not parse %r: %s" % (cmd.cmdBody, strFromException(e))) return #cmd.parsedCmd.printData() if cmd.parsedCmd.callFunc: cmd.setState(cmd.Running) try: cmd.parsedCmd.callFunc(self, cmd) except CommandError as e: cmd.setState("failed", textMsg=strFromException(e)) return except Exception as e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr,)) sys.stderr.write("function %s raised %s\n" % (cmd.parsedCmd.callFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) textMsg = strFromException(e) hubMsg = "Exception=%s" % (e.__class__.__name__,) cmd.setState("failed", textMsg=textMsg, hubMsg=hubMsg) else: raise RuntimeError("Command %r not yet implemented" % (cmd.parsedCmd.cmdVerb,))
def doGuide(self, filePath): """Centroid star on specified image and apply pointing correction """ if _Debug: print "doGuide(filePath=%r)" % (filePath,) try: starPos = [self.getEntryNum(wdg) for wdg in self.starPosWdgSet] centroidRadius = self.getEntryNum(self.centroidRadArcSecWdg) * self.getMeanInstScalePixPerArcSec() if centroidRadius < self.MinCentroidRadiusPix: centroidRadius = self.MinCentroidRadiusPix except RuntimeError as e: self.statusBar.setMsg("Cannot guide: %s" % (strFromException(e),), severity=RO.Constants.sevError) self.doGuideBtn.setBool(False) return self.pendingCmd = RO.KeyVariable.CmdVar( actor=self.gcamActor, cmdStr="centroid file=%r on=%0.1f,%0.1f cradius=%0.1f" % (filePath, starPos[0], starPos[1], centroidRadius), keyVars=(self.guideModel.star,), timeLim=self.FindTimeLim, ) self.pendingPath = filePath if _Debug: print "pending path = %s; pending command = %s" % (self.pendingPath, self.pendingCmd) self.statusBar.doCmd(self.pendingCmd) # add callback after doCmd so errors in this callback are reported in status bar self.pendingCmd.addCallback(self.centroidCmdDone)
def newCmd(self, sock): """!Called when a command is read from a user. Note: command name collisions are resolved as follows: - local commands (cmd_<foo> methods of this actor) - commands handled by devices - direct device access commands (device name) """ cmdStr = sock.readLine() log.info("%s.newCmd(%r)" % (self, cmdStr)) # print("%s.newCmd; cmdStr=%r" % (self, cmdStr,)) if not cmdStr: return userID = getSocketUserID(sock) try: cmd = UserCmd(userID, cmdStr, self.cmdCallback) except Exception as e: self.writeToUsers("f", "Could not parse the following as a command: %r"%cmdStr) return try: cmd = expandCommand(cmd) # gives write to users cmd.userCommanded = True # this command was generated from a socket read. self.parseAndDispatchCmd(cmd) except Exception as e: cmd.setState(cmd.Failed, "Command %r failed: %s" % (cmd.cmdBody, strFromException(e)))
def cmd_disconnDev(self, cmd=None): """[dev1 [dev2 [...]]]: disconnect one or more devices (all if none specified). Already-disconnected devices are ignored (except to output status). Command args: 0 or more device names, space-separated """ if cmd and cmd.cmdArgs: devNameList = cmd.cmdArgs.split() else: devNameList = self.dev.nameDict.keys() runInBackground = False subCmdList = [] for devName in devNameList: dev = self.dev.nameDict[devName] if not dev.isConnected: self.showOneDevConnStatus(dev, cmd=cmd) else: disconnSubCmd = UserCmd() subCmdList.append(disconnSubCmd) runInBackground = True dev.connReq = (False, disconnSubCmd) try: dev.disconnect() except Exception as e: self.writeToUsers("w", "text=could disconnect device %s: %s" % (devName, strFromException(e)), cmd=cmd) if subCmdList and cmd: LinkCommands(cmd, subCmdList) return runInBackground
def exposeFilesCallback(self, fileInfo, isCurrent, keyVar=None): """Handle the files keyword fileInfo = - cmdr (progID.username) - host - common root directory - program and date subdirectory - user subdirectory - file name(s) """ if _Debug: print "exposeFilesCallback(fileInfo=%s, isCurrent=%s)" % (fileInfo, isCurrent) if not isCurrent: return cmdr = fileInfo[0] prog = cmdr.split(".", 1)[0] filePath = "".join(fileInfo[2:6]) fileName = fileInfo[5] try: if self.tuiModel.getProgID() not in (prog, "APO"): raise RuntimeError("not my image") if self.isBusy: raise RuntimeError("I'm busy") instName = self.getKeyValues(self.tccModel.instName, 0, 1)[0] if not instName.lower().startswith(self.instName.lower()): raise RuntimeError("current instrument is %s, not %s" % (instName, self.instName)) except RuntimeError, e: self.logMsg("%s\tskipped: %s" % (fileName, strFromException(e))) return
def getSpecialFileStr(): """Return a string describing where the special files are """ def strFromPath(filePath): if os.path.exists(filePath): return filePath return "%s (not found)" % (filePath, ) outStrList = [] for name, func in ( ("Preferences", TUI.TUIPaths.getPrefsFile), ("Window Geom.", TUI.TUIPaths.getGeomFile), ): try: filePath = func() pathStr = strFromPath(filePath) except Exception as e: pathStr = "?: %s" % (strFromException(e), ) outStrList.append("%s: %s" % (name, pathStr)) tuiAdditionsDirs = TUI.TUIPaths.getAddPaths(ifExists=False) for ind, filePath in enumerate(tuiAdditionsDirs): pathStr = strFromPath(filePath) outStrList.append("%sAdditions %d: %s" % (TUI.Version.ApplicationName, ind + 1, pathStr)) outStrList.append("Error Log: %s" % (sys.stderr.name, )) return "\n".join(outStrList)
def _fixFocus(self, evt): """Call when the user types a character into the output pane. If the key is a navigation key, passes it through to the upper pane. Otherwise it switches focus to the lower pane, and if the key appears to be a character, passes the key event to the lower pane. """ if evt.keysym in frozenset( ("Home", "End", "Prior", "Next", "Up", "Down", "Left", "Right")): return self.inText.focus_set() if evt.keysym not in frozenset( ("Escape", "Backspace", "Delete", "Return", "Linefeed", "Tab", "Enter", "KP_Enter", "??")): try: self.inText.event_generate( "<KeyPress>", keysym=evt.keysym, keycode=evt.keycode, ) except Exception as e: sys.stderr.write("_fixFocus event_generate failed; evt.keysym=%r; evt.keycode=%r: %s\n" % \ (evt.keysym, evt.keycode, strFromException(e))) return "break"
def __call__(self): """If the script window exists, bring it to the front. Otherwise, load the script file into a new script window. """ # print "ScriptLoader.doMenu(); tlName=%s" % (tlName,) tl = self.tuiModel.tlSet.getToplevel(self.tlName) if tl: tl.makeVisible() else: try: self.tuiModel.tlSet.createToplevel( name = self.tlName, resizable = False, wdgFunc = self.makeWdg, ) except (SystemExit, KeyboardInterrupt): raise except Exception, e: if self.showErrDialog: tkMessageBox.showerror( message = "Could not load script:\n%r\n%s\n(See console for more info.)" % (self.fullPath, strFromException(e)), ) else: self.tuiModel.logMsg( msgStr = "Could not load script: %r: %s" % (self.fullPath, strFromException(e)), severity = RO.Constants.sevWarning, )
def getSpecialFileStr(): """Return a string describing where the special files are """ def strFromPath(filePath): if os.path.exists(filePath): return filePath return "%s (not found)" % (filePath,) outStrList = [] for name, func in ( ("Preferences", TUI.TUIPaths.getPrefsFile), ("Window Geom.", TUI.TUIPaths.getGeomFile), ): try: filePath = func() pathStr = strFromPath(filePath) except Exception as e: pathStr = "?: %s" % (strFromException(e),) outStrList.append("%s: %s" % (name, pathStr)) tuiAdditionsDirs = TUI.TUIPaths.getAddPaths(ifExists=False) for ind, filePath in enumerate(tuiAdditionsDirs): pathStr = strFromPath(filePath) outStrList.append("%sAdditions %d: %s" % (TUI.Version.ApplicationName, ind + 1, pathStr)) outStrList.append("Error Log: %s" % (sys.stderr.name,)) return "\n".join(outStrList)
def doCorrect(self, starMeas): """Compute correction and start correction command We are measuring position on the instrument plane, so apply the correction as a boresight offset (not ideal, but simplest). """ # positions are in binned pixels unless otherwise noted posErr = None try: instScalePixPerDeg = self.getInstScalePixPerDeg() meanInstScalePixPerArcSec = self.getMeanInstScalePixPerArcSec(instScalePixPerDeg) desPos = numpy.array([self.getEntryNum(self.starPosWdgSet[ii]) for ii in range(2)], dtype=float) measPos = numpy.array(starMeas.xyPos, dtype=float) userCorrFrac = self.getEntryNum(self.userCorrFracWdg) posErr = measPos - desPos # binned pixels azAltCmdState = [str(val).lower() for val in self.getKeyValues(self.tccModel.axisCmdState, 0, 2)] if azAltCmdState != ["tracking", "tracking"]: raise RuntimeError("not tracking") except Exception as e: self.logStarMeas(starMeas, posErr=posErr, errMsg=strFromException(e), severity=RO.Constants.sevError) return posErrDeg = posErr / instScalePixPerDeg fitErrMagArcSec = vecMag(starMeas.xyStdDev) / meanInstScalePixPerArcSec for fitErrThresh, autoCorrFrac in self.FitErrCorrFracList: if fitErrMagArcSec < fitErrThresh: if _Debug: print 'fitErr=%0.1f"; thresh=%0.1f"; autoCorrFrac=%0.1f' % ( fitErrMagArcSec, fitErrThresh, autoCorrFrac, ) break else: self.logStarMeas(starMeas, posErr=posErr, errMsg="fit error too large", severity=RO.Constants.sevWarning) return boresightOffsetDeg = -posErrDeg * autoCorrFrac * userCorrFrac if vecMag(boresightOffsetDeg) * 3600.0 < self.MinCorrArcSec: self.logStarMeas(starMeas, posErr=posErr, errMsg="offset too small") if _Debug: print "position error=%0.1f, %0.1f arcsec" % tuple(posErrDeg * 3600.0) print "boresight offset=%0.1f, %0.1f arcsec" % tuple(boresightOffsetDeg * 3600.0) return self.pendingCmd = RO.KeyVariable.CmdVar( actor="tcc", cmdStr="offset boresight %0.7f, %0.7f" % (boresightOffsetDeg[0], boresightOffsetDeg[1]), timeLim=self.OffsetTimeLim, # timeLimKeyword = "SlewDuration", # useful for computed offsets ) if _Debug: print "pending path = %s; pending command = %s" % (self.pendingPath, self.pendingCmd) self.statusBar.doCmd(self.pendingCmd) # add callback after doCmd so errors in this callback are reported in status bar self.pendingCmd.addCallback(self.offsetCmdDone) self.logStarMeas(starMeas, posErr=posErr, boresightOffsetDeg=boresightOffsetDeg)
def parseAndDispatchCmd(self, cmd): """Parse and dispatch a command Note: command name collisions are resolved as follows: - local commands (cmd_<foo> methods of this actor) - commands handled by devices - direct device access commands (device name) """ if not cmd.cmdBody: # echo to show alive self.writeToOneUser(":", "", cmd=cmd) return cmd.cmdVerb = "" cmd.cmdArgs = "" if cmd.cmdBody: res = cmd.cmdBody.split(None, 1) if len(res) > 1: cmd.cmdVerb, cmd.cmdArgs = res else: cmd.cmdVerb = res[0] # see if command is a local command cmdFunc = self.locCmdDict.get(cmd.cmdVerb) if cmdFunc is not None: # execute local command try: self.checkLocalCmd(cmd) retVal = cmdFunc(cmd) except CommandError, e: cmd.setState("failed", strFromException(e)) return except Exception, e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr,)) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd)
def startDevCmd(self, devCmdStr): """ @param[in] devCmdStr a line of text to send to the device """ devCmdStr = devCmdStr.lower() log.info("%s.startDevCmd(%r)" % (self, devCmdStr)) try: if self.conn.isConnected: log.info("%s writing %r" % (self, devCmdStr)) self.conn.writeLine(devCmdStr) else: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, "Not connected") except Exception as e: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, textMsg=strFromException(e))
def startDevCmd(self, devCmd): """ @param[in] devCmd a dev command """ log.info("%s.startDevCmd(%r)" % (self, devCmd.cmdStr)) #print("%s.startDevCmd(%r)" % (self, devCmd.cmdStr)) try: if self.conn.isConnected: log.info("%s writing %r" % (self, devCmd.cmdStr)) devCmd.setState(devCmd.Running) self.conn.writeLine(devCmd.cmdStr) else: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, "Not connected") except Exception as e: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, textMsg=strFromException(e))
def doGuide(self, filePath): """Centroid star on specified image and apply pointing correction """ if _Debug: print "doGuide(filePath=%r)" % (filePath,) try: starPos = [self.getEntryNum(wdg) for wdg in self.starPosWdgSet] centroidRadius = self.getEntryNum(self.centroidRadArcSecWdg) * self.getMeanInstScalePixPerArcSec() if centroidRadius < self.MinCentroidRadiusPix: centroidRadius = self.MinCentroidRadiusPix except RuntimeError, e: self.statusBar.setMsg("Cannot guide: %s" % (strFromException(e),), severity=RO.Constants.sevError) self.doGuideBtn.setBool(False) return
def startDevCmd(self, devCmdStr): """ @param[in] devCmdStr a line of text to send to the device """ log.info("%s.startDevCmd(%r)" % (self, devCmdStr)) try: if self.conn.isConnected: log.info("%s writing %r" % (self, devCmdStr)) self.conn.writeLine(devCmdStr) if devCmdStr == "init": self.waitingForInitEcho = True self.currDevCmdStr = devCmdStr else: self.currExeCmd.setState(self.currExeCmd.Failed, "Not connected") except Exception as e: self.currExeCmd.setState(self.currExeCmd.Failed, textMsg=strFromException(e))
def startCmd(self, cmdStr, callFunc=None, userCmd=None, timeLim=DefaultTimeLim, showReplies=False): """!Start a new command. @param[in] cmdStr command string @param[in] callFunc callback function: function to call when command succeeds or fails, or None; if specified it receives one argument: a device command @param[in] userCmd user command that tracks this command, if any @param[in] timeLim maximum time before command expires, in sec; None for no limit @param[in] showReplies show all replies as plain text? @return devCmd: the device command that was started (and may already have failed) @note: if callFunc and userCmd are both specified callFunc is called before userCmd is updated. @warning: subclasses must supplement or override this method to set the devCmd done when finished. Subclasses that use a command queue will usually replace this method. """ log.info( "%s.startCmd(cmdStr=%r, callFunc=%s, userCmd=%s, timeLim=%s)" % (self, cmdStr, callFunc, userCmd, timeLim)) devCmd = self.cmdClass( cmdStr=cmdStr, userCmd=userCmd, callFunc=callFunc, timeLim=timeLim, dev=self, showReplies=showReplies, ) if not self.conn.isConnected: devCmd.setState(devCmd.Failed, textMsg="%s %s failed: not connected" % (self.name, cmdStr)) else: fullCmdStr = devCmd.fullCmdStr try: self.conn.writeLine(fullCmdStr) except Exception as e: devCmd.setState(devCmd.Failed, textMsg="%s %s failed: %s" % (self.name, cmdStr, strFromException(e))) return devCmd
def startDevCmd(self, devCmdStr): """ @param[in] devCmdStr a line of text to send to the device """ devCmdStr = devCmdStr.upper() # lco uses all upper case log.info("%s.startDevCmd(%r)" % (self, devCmdStr)) try: if self.conn.isConnected: log.info("%s writing %r" % (self, devCmdStr)) if CMDOFF.upper() == devCmdStr: self.waitOffsetCmd.setState(self.waitOffsetCmd.Running) elif "CIR" in devCmdStr: self.waitRotCmd.setState(self.waitRotCmd.Running) self.conn.writeLine(devCmdStr) else: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, "Not connected to TCS") except Exception as e: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, textMsg=strFromException(e))
def getSpecialFileStr(): """Return a string describing where the special files are """ def strFromPath(filePath): if os.path.exists(filePath): return filePath return "%s (not found)" % (filePath, ) outStrList = [] for name, func in (("Preferences", TUI.TUIPaths.getPrefsFile), ("Window Geom.", TUI.TUIPaths.getGeomFile), ("User Presets", TUI.TUIPaths.getUserPresetsFile)): try: filePath = func() pathStr = strFromPath(filePath) except Exception, e: pathStr = "?: %s" % (strFromException(e), ) outStrList.append("%s: %s" % (name, pathStr))
def newCmd(self, sock): """Called when a command is read from a user. Note: command name collisions are resolved as follows: - local commands (cmd_<foo> methods of this actor) - commands handled by devices - direct device access commands (device name) """ cmdStr = sock.readLine() #print "%s.newCmd; cmdStr=%r" % (self, cmdStr,) if not cmdStr: return userID = getSocketUserID(sock) cmd = UserCmd(userID, cmdStr, self.cmdCallback) try: self.parseAndDispatchCmd(cmd) except Exception, e: cmd.setState(cmd.Failed, "Command %r failed: %s" % (cmd.cmdBody, strFromException(e)))
def getSpecialFileStr(): """Return a string describing where the special files are """ def strFromPath(filePath): if os.path.exists(filePath): return filePath return "%s (not found)" % (filePath,) outStrList = [] for name, func in ( ("Preferences", TUI.TUIPaths.getPrefsFile), ("Window Geom.", TUI.TUIPaths.getGeomFile), ("User Presets", TUI.TUIPaths.getUserPresetsFile) ): try: filePath = func() pathStr = strFromPath(filePath) except Exception, e: pathStr = "?: %s" % (strFromException(e),) outStrList.append("%s: %s" % (name, pathStr))
def doCorrect(self, starMeas): """Compute correction and start correction command We are measuring position on the instrument plane, so apply the correction as a boresight offset (not ideal, but simplest). """ # positions are in binned pixels unless otherwise noted posErr = None try: instScalePixPerDeg = self.getInstScalePixPerDeg() meanInstScalePixPerArcSec = self.getMeanInstScalePixPerArcSec(instScalePixPerDeg) desPos = numpy.array([self.getEntryNum(self.starPosWdgSet[ii]) for ii in range(2)], dtype=float) measPos = numpy.array(starMeas.xyPos, dtype=float) userCorrFrac = self.getEntryNum(self.userCorrFracWdg) posErr = measPos - desPos # binned pixels azAltCmdState = [str(val).lower() for val in self.getKeyValues(self.tccModel.axisCmdState, 0, 2)] if azAltCmdState != ["tracking", "tracking"]: raise RuntimeError("not tracking") except Exception, e: self.logStarMeas(starMeas, posErr=posErr, errMsg=strFromException(e), severity=RO.Constants.sevError) return
def startDevCmd(self, devCmd): """ @param[in] devCmdStr a line of text to send to the device """ devCmdStr = devCmd.cmdStr.lower() # m2 uses all lower case log.info("%s.startDevCmd(%r)" % (self, devCmdStr)) try: if self.conn.isConnected: log.info("%s writing %r" % (self, devCmdStr)) # set move command to running now. Bug if set earlier race condition # with status if "move" in devCmdStr.lower() or "offset" in devCmdStr.lower(): self.waitMoveCmd.setState(self.waitMoveCmd.Running) self.status.state = Moving self.writeToUsers("i", self.status.secStateStr(), devCmd.userCmd) # if "galil" in devCmdStr.lower(): # self.waitGalilCmd.setState(self.waitGalilCmd.Running) self.conn.writeLine(devCmdStr) else: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, "Not connected to M2") except Exception as e: self.currExeDevCmd.setState(self.currExeDevCmd.Failed, textMsg=strFromException(e))
def _fixFocus(self, evt): """Call when the user types a character into the output pane. If the key is a navigation key, passes it through to the upper pane. Otherwise it switches focus to the lower pane, and if the key appears to be a character, passes the key event to the lower pane. """ if evt.keysym in frozenset(("Home", "End", "Prior", "Next", "Up", "Down", "Left", "Right")): return self.inText.focus_set() if evt.keysym not in frozenset(("Escape", "Backspace", "Delete", "Return", "Linefeed", "Tab", "Enter", "KP_Enter", "??")): try: self.inText.event_generate( "<KeyPress>", keysym = evt.keysym, keycode = evt.keycode, ) except Exception as e: sys.stderr.write("_fixFocus event_generate failed; evt.keysym=%r; evt.keycode=%r: %s\n" % \ (evt.keysym, evt.keycode, strFromException(e))) return "break"
devCmdInfo = self.devCmdDict.get(cmd.cmdVerb) if devCmdInfo: # command verb is one handled by a device dev, devCmdVerb, cmdHelp = devCmdInfo devCmdStr = "%s %s" % (devCmdVerb, cmd.cmdArgs) else: dev = self.dev.nameDict.get(cmd.cmdVerb) if dev is not None: # command verb is the name of a device; # the command arguments are the string to send to the device devCmdStr = cmd.cmdArgs if dev and devCmdStr: try: dev.newCmd(devCmdStr, cmd=cmd) except CommandError, e: cmd.setState("failed", strFromException(e)) return except Exception, e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr,)) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd) return self.writeToOneUser("f", "UnknownCommand=%s" % (cmd.cmdVerb,), cmd=cmd) def newUser(self, sock): fakeCmd = BaseActor.newUser(self, sock) self.showDevConnStatus(cmd=fakeCmd, onlyOneUser=True, onlyIfNotConn=True)
def cmd_connDev(self, cmd=None): """[dev1 [dev2 [...]]]: connect one or more devices (all devices if none specified). Already-connected devices are ignored (except to output status). Command args: 0 or more device names, space-separated """ if cmd and cmd.cmdArgs: devNameList = cmd.cmdArgs.split() else: devNameList = self.dev.nameDict.keys() runInBackground = False for devName in devNameList: dev = self.dev.nameDict[devName] if dev.conn.isConnected: self.showOneDevConnStatus(dev, cmd=cmd) else: runInBackground = True dev.connReq = (True, cmd) try: dev.conn.connect() except Exception, e: self.writeToUsers("w", "Text=could not connect device %s: %s" % (devName, strFromException(e)), cmd=cmd)
def parseAndDispatchCmd(self, cmd): """!Parse and dispatch a command @param[in] cmd user command (twistedActor.UserCmd) Duplicate command names are resolved such that the first match in this list is used: - local commands (cmd_<foo> methods of this actor) - commands handled by devices - direct device access commands (device name) """ if not cmd.cmdBody: # echo to show alive self.writeToOneUser(":", "", cmd=cmd) return # if a commandSet was supplied use it! if self.commandSet is not None: cmd.parsedCommand = self.commandSet.parse(cmd.cmdBody) cmd.cmdVerb = "" cmd.cmdArgs = "" if cmd.cmdBody: res = cmd.cmdBody.split(None, 1) if len(res) > 1: cmd.cmdVerb, cmd.cmdArgs = res else: cmd.cmdVerb = res[0] cmd.cmdVerb = cmd.cmdVerb.lower() # see if command is a local command cmdFunc = self.locCmdDict.get(cmd.cmdVerb) if cmdFunc is not None: # execute local command try: self.checkLocalCmd(cmd) retVal = cmdFunc(cmd) except CommandError as e: cmd.setState("failed", strFromException(e)) return except Exception as e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr, )) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd) else: if not retVal and not cmd.isDone: cmd.setState("done") return # see if command is a device command dev = None devCmdStr = "" devCmdInfo = self.devCmdDict.get(cmd.cmdVerb) if devCmdInfo: # command verb is one handled by a device dev, devCmdVerb, cmdHelp = devCmdInfo devCmdStr = "%s %s" % (devCmdVerb, cmd.cmdArgs) if devCmdVerb else cmd.cmdArgs if dev and devCmdStr: try: dev.startCmd(devCmdStr, userCmd=cmd, timeLim=2) except CommandError as e: cmd.setState("failed", strFromException(e)) return except Exception as e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr, )) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd) return self.writeToOneUser("f", "UnknownCommand=%s" % (cmd.cmdVerb, ), cmd=cmd)
def parseAndDispatchCmd(self, cmd): """!Parse and dispatch a command @param[in] cmd user command (twistedActor.UserCmd) Duplicate command names are resolved such that the first match in this list is used: - local commands (cmd_<foo> methods of this actor) - commands handled by devices - direct device access commands (device name) """ if not cmd.cmdBody: # echo to show alive self.writeToOneUser(":", "", cmd=cmd) return # if a commandSet was supplied use it! if self.commandSet is not None: cmd.parsedCommand = self.commandSet.parse(cmd.cmdBody) cmd.cmdVerb = "" cmd.cmdArgs = "" if cmd.cmdBody: res = cmd.cmdBody.split(None, 1) if len(res) > 1: cmd.cmdVerb, cmd.cmdArgs = res else: cmd.cmdVerb = res[0] cmd.cmdVerb = cmd.cmdVerb.lower() # see if command is a local command cmdFunc = self.locCmdDict.get(cmd.cmdVerb) if cmdFunc is not None: # execute local command try: self.checkLocalCmd(cmd) retVal = cmdFunc(cmd) except CommandError as e: cmd.setState("failed", strFromException(e)) return except Exception as e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr,)) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd) else: if not retVal and not cmd.isDone: cmd.setState("done") return # see if command is a device command dev = None devCmdStr = "" devCmdInfo = self.devCmdDict.get(cmd.cmdVerb) if devCmdInfo: # command verb is one handled by a device dev, devCmdVerb, cmdHelp = devCmdInfo devCmdStr = "%s %s" % (devCmdVerb, cmd.cmdArgs) if devCmdVerb else cmd.cmdArgs if dev and devCmdStr: try: dev.startCmd(devCmdStr, userCmd=cmd, timeLim=2) except CommandError as e: cmd.setState("failed", strFromException(e)) return except Exception as e: sys.stderr.write("command %r failed\n" % (cmd.cmdStr,)) sys.stderr.write("function %s raised %s\n" % (cmdFunc, strFromException(e))) traceback.print_exc(file=sys.stderr) quotedErr = quoteStr(strFromException(e)) msgStr = "Exception=%s; Text=%s" % (e.__class__.__name__, quotedErr) self.writeToUsers("f", msgStr, cmd=cmd) return self.writeToOneUser("f", "UnknownCommand=%s" % (cmd.cmdVerb,), cmd=cmd)
def startCmd(self, cmdStr, callFunc=None, userCmd=None, timeLim=DefaultTimeLim, showReplies=False): """!Start a new command. @param[in] cmdStr command string @param[in] callFunc callback function: function to call when command succeeds or fails, or None; if specified it receives one argument: a device command @param[in] userCmd user command that tracks this command, if any @param[in] timeLim maximum time before command expires, in sec; None for no limit @param[in] showReplies show all replies as plain text? @return devCmd: the device command that was started (and may already have failed) @note: if callFunc and userCmd are both specified callFunc is called before userCmd is updated. @warning: subclasses must supplement or override this method to set the devCmd done when finished. Subclasses that use a command queue will usually replace this method. """ log.info("%s.startCmd(cmdStr=%r, callFunc=%s, userCmd=%s, timeLim=%s)" % (self, cmdStr, callFunc, userCmd, timeLim)) devCmd = self.cmdClass( cmdStr = cmdStr, userCmd = userCmd, callFunc = callFunc, timeLim = timeLim, dev = self, showReplies = showReplies, ) if not self.conn.isConnected: devCmd.setState(devCmd.Failed, textMsg="%s %s failed: not connected" % (self.name, cmdStr)) else: fullCmdStr = devCmd.fullCmdStr try: self.conn.writeLine(fullCmdStr) except Exception as e: devCmd.setState(devCmd.Failed, textMsg="%s %s failed: %s" % (self.name, cmdStr, strFromException(e))) return devCmd