Exemplo n.º 1
0
class application(object):
    ENABLED = 0
    DISABLED = 1
    UNCHANGED = 2

    def __init__(self):
        app.soar = self
        self.top = app.top
        app.top.wm_title('soar' + soar.version.format_version())
        app.top.protocol('WM_DELETE_WINDOW', self.exit)

        self.initializeNamespace()
        self.userfn = UserFunctionIF()
        io.configure_io(self.namespace)
        self.soar_toolbar_commands = formulae.FormulaPool()
        self.flowtriplets = [(self.startstepper, self.step, self.stopstepper)]
        soar_dir = soar.__path__[0]
        self.readConfigFile()
        if self.main_geom:
            app.top.geometry(self.main_geom[self.main_geom.find('+'):])
        media_dir = soar_dir + '/media'
        self.toolbar = widgets.ToolbarFrame(app.top,
                                            self.soar_toolbar_commands)
        self.toolbar.pack(side=TOP)
        start_images = {'normal': media_dir + "/start.gif"}
        step_images = {'normal': media_dir + "/step.gif"}
        stop_images = {'normal': media_dir + "/stop.gif"}
        simulator_images = {'normal': media_dir + "/simulator.gif"}
        eBot_images = {'normal': media_dir + "/eBot.gif"}
        robot_images = {'normal': media_dir + "/robot.gif"}
        brain_images = {'normal': media_dir + "/brain.gif"}
        joystick_images = {'normal': media_dir + "/joystick.gif"}
        oscillo_images = {'normal': media_dir + "/oscillo.gif"}
        Amigo_simulator_images = {'normal': media_dir + "/simulator.gif"}
        # if we're on the mac, the buttons won't stay pushed, so
        # we have a different image to indicate active buttons
        self.use_active_button_images = (platform.system() == 'Darwin')
        if (self.use_active_button_images):
            start_images['active'] = media_dir + "/start_active.gif"
            stop_images['active'] = media_dir + "/stop_active.gif"
            simulator_images['active'] = media_dir + "/simulator_active.gif"
            eBot_images['active'] = media_dir + "/eBot_active.gif"
            robot_images['active'] = media_dir + "/robot_active.gif"
            brain_images['active'] = media_dir + "/brain_active.gif"
            joystick_images['active'] = media_dir + "/joystick_active.gif"
            oscillo_images['active'] = media_dir + "/oscillo_active.gif"
            Amigo_simulator_images[
                'active'] = media_dir + "/simulator_active.gif"
        self.soar_toolbar_commands.addFormula(
            ('start', self.startall, 'Start', start_images, lambda: []))
        self.soar_toolbar_commands.addFormula(
            ('step', self.stepall, 'Step', step_images, lambda: []))
        self.soar_toolbar_commands.addFormula(
            ('stop', self.stopall, 'Stop', stop_images, lambda: []))
        self.pushToolbarButton('stop')
        self.disableToolbarButton('start')
        self.disableToolbarButton('step')

        Label(self.toolbar, text="Outputs:").pack(side=LEFT)

        #self.simulator_dir_default = soar_dir + "/6.01/worlds"
        self.soar_toolbar_commands.addFormula(
            ('simulator', self.openSimulator, 'Simulator', simulator_images,
             self.openSimulatorDialog))
        self.soar_toolbar_commands.addFormula(
            ('Amigosimulator', self.openAmigoSimulator, 'AmigoSimulator',
             Amigo_simulator_images, self.openAmigoSimulatorDialog))
        #self.soar_toolbar_commands.addFormula(('pioneer', self.openPioneer,
        #                                       'Pioneer', robot_images,
        #                                       lambda: []))
        self.soar_toolbar_commands.addFormula(
            ('eBot', self.openEBot, 'eBot', eBot_images, lambda: []))

        #CHANGED: robot name
        self.soar_toolbar_commands.addFormula(
            ('pioneer', self.openPioneer, 'Amigobot', robot_images,
             lambda: []))

        Label(self.toolbar, text="Controls:").pack(side=LEFT)

        #self.brain_dir_default = '~'
        self.soar_toolbar_commands.addFormula(
            ('brain', self.openBrain, 'Brain', brain_images,
             self.openBrainDialog))
        self.disableToolbarButton('brain')

        #CHANGED: commented out
        #self.soar_toolbar_commands.addFormula(('joystick', self.openJoystick,
        #                                       'Joystick', joystick_images,
        #                                       lambda: []))
        #self.disableToolbarButton('joystick')

        #    self.soar_toolbar_commands.addFormula(('oscillo', self.openOscillo,
        #                                           '    Oscilloscope ', oscillo_images,
        #                                           lambda: []))

        self.minibuffer = widgets.MiniBuffer(app.mainframe,
                                             self.namespace,
                                             width=78)
        self.minibuffer.pack(side=TOP, fill=X, expand=1)

        self.stderrbuffer = None
        #    self.stderrframe = app.tabframe.addFrameWithHideCB("errors",
        #                                                       self.clearErrors)
        #    self.stderrframe = app.tabframe.addFrame("errors")
        self.stderrbuffer = widgets.OutputBufferFrame(
            app.mainframe)  #self.stderrframe)
        self.stderrbuffer.box_.config(foreground='red')
        self.stderrbuffer.pack(fill=BOTH, expand=1)
        sys.stderr = parallel.PipeSyndicator([sys.stderr, self.stderrbuffer])
        self.clearErrors()

        self.stdoutbuffer = None
        #    self.stdoutframe = app.tabframe.addFrameWithHideCB("standard output",
        #                                                       self.clearOutput)
        #    self.stdoutframe = app.tabframe.addFrame("standard output")
        self.stdoutbuffer = widgets.OutputBufferFrame(
            app.mainframe)  #self.stdoutframe)
        self.stdoutbuffer.pack(fill=BOTH, expand=1)
        sys.stdout = parallel.PipeSyndicator([sys.stdout, self.stdoutbuffer])
        self.clearOutput()

        self.reloadAllButton = Button(app.mainframe,
                                      text="Reload Brain and World",
                                      command=self.reloadAll)
        self.reloadAllButton.pack()
        self.disableButton(self.reloadAllButton)

        self.reloadBrainButton = Button(app.mainframe,
                                        text="Reload Brain",
                                        command=self.reloadBrain)
        self.reloadBrainButton.pack()
        self.brainfile = ""
        self.disableButton(self.reloadBrainButton)
        #self.reloadWorldButton = Button(app.mainframe, text="Reload World",
        #                                command = self.reloadWorld)
        #self.reloadWorldButton.pack()
        #self.disableButton(self.reloadWorldButton)
        self.sonar_monitor = None
        self.oscope = None
        self.control = None
        self.output = None
        self.readfile = False
        self.writefile = False

    def readConfigFile(self):
        # defaults for if no file exists
        self.simulator_dir_default = soar.__path__[0] + "/worlds"
        self.brain_dir_default = '~'
        self.main_geom = None
        self.simulator_geom = None
        self.scope_geom = None
        self.sonarmon_geom = None
        homedir = os.path.expanduser('~')
        homedir.replace('\\', '/')
        try:
            f = open(homedir + "/.soarc")
        except:
            # it's okay if there's no config file; we'll write one at the end
            return
        vars = {}
        for line in f.readlines():
            if '=' in line:
                key, value = list(map(str.strip, line.split('=', 1)))
                vars[key] = value
        f.close()
        if 'OPEN_PATH' in vars and os.path.exists(vars['OPEN_PATH']):
            self.brain_dir_default = vars['OPEN_PATH']
        if 'WORLD_PATH' in vars and os.path.exists(vars['WORLD_PATH']):
            self.simulator_dir_default = vars['WORLD_PATH']
        # get geometry for the windows for each standard widget
        if 'MAIN_GEOM' in vars: self.main_geom = vars['MAIN_GEOM']
        if 'SIM_GEOM' in vars: self.simulator_geom = vars['SIM_GEOM']
        if 'SCOPE_GEOM' in vars: self.scope_geom = vars['SCOPE_GEOM']
        if 'SONAR_MON_GEOM' in vars:
            self.sonarmon_geom = vars['SONAR_MON_GEOM']

    def writeConfigFile(self):
        homedir = os.path.expanduser('~')
        homedir.replace('\\', '/')
        try:
            f = open(homedir + "/.soarc", "w")
            f.write('%s=%s\n' % ('OPEN_PATH', self.brain_dir_default))
            f.write('%s=%s\n' % ('WORLD_PATH', self.simulator_dir_default))
            f.write('%s=%s\n' % ('MAIN_GEOM', self.top.geometry()))
            if self.simulator_geom:
                f.write('%s=%s\n' % ('SIM_GEOM', self.simulator_geom))
            if self.scope_geom:
                f.write('%s=%s\n' % ('SCOPE_GEOM', self.scope_geom))
            if self.sonarmon_geom:
                f.write('%s=%s\n' % ('SONAR_MON_GEOM', self.sonarmon_geom))
        except:
            sys.stderr.write("Could not write soar config file .soarc\n")

    def exit(self):
        # askyesno seems to be broken in current Tk (always returns False)
        #answer = form.widgets.askyesno("Exit", "Are you sure you want to exit?")
        answer = form.widgets.askquestion("Exit",
                                          "Are you sure you want to exit?")
        if answer == 'no':
            return
        try:
            self.stopall()
        except:
            pass
        try:
            self.unloadModule(self.control)
        except:
            pass
        try:
            self.unloadModule(self.output)
        except:
            pass
        self.closeSonarMonitor()
        self.closeOscillo()
        self.writeConfigFile()
        form.main.tk.destroy()
        form.main.sys.exit(0)

    def clearErrors(self):
        self.stderrbuffer.clear()
        sys.stderr.write("Error output will appear in this window.\n")

    def clearOutput(self):
        self.stdoutbuffer.clear()
        print("Ordinary output will appear in this window.")

    def openSimulator(self, world):
        import soar.outputs.simulator
        if (len(world) > 0):
            #self.enableButton(self.reloadWorldButton)
            # do this before we try to read the file so we can reload even
            # if there is an error in the file
            if self.control:
                self.enableButton(self.reloadAllButton)
            try:
                self.setOutput(lambda: \
                                 soar.outputs.simulator.Simulator(world,
                                                                  self.simulator_geom))
            except:
                sys.stderr.write(
                    "Error loading world.  Perhaps you accidentally chose a brain file?\n"
                )
                return
            self.pushToolbarButton('simulator')
            self.unpushToolbarButton('Amigosimulator')
            self.unpushToolbarButton('pioneer')
            self.unpushToolbarButton('eBot')
            self.unpushToolbarButton('brain')
            #CHANGED commented out
            #self.unpushToolbarButton('joystick')
            self.reloadBrain(True)

    def openAmigoSimulator(self, world):
        import soar.outputs.amigo_simulator
        if (len(world) > 0):
            #self.enableButton(self.reloadWorldButton)
            # do this before we try to read the file so we can reload even
            # if there is an error in the file
            if self.control:
                self.enableButton(self.reloadAllButton)
            try:
                self.setOutput(lambda: \
                                 soar.outputs.amigo_simulator.amigo_simulator(world,
                                                                  self.simulator_geom))
            except:
                sys.stderr.write(
                    "Error loading world.  Perhaps you accidentally chose a brain file?\n"
                )
                return
            self.pushToolbarButton('Amigosimulator')
            self.unpushToolbarButton('simulator')
            self.unpushToolbarButton('pioneer')
            self.unpushToolbarButton('eBot')
            self.unpushToolbarButton('brain')
            #CHANGED commented out
            #self.unpushToolbarButton('joystick')
            self.reloadBrain(True)

    def openEBot(self):
        import soar.outputs.eBot
        # allow pioneer button to be unpushed to disconnect
        if self.toolbar.buttons['eBot'].cget('relief') == SUNKEN:
            self.closeEBot(False)
        else:
            if self.setOutput(lambda: soar.outputs.eBot.eBot()):
                sys.stderr.write("Set output to eBot.\n")
                #self.disableButton(self.reloadWorldButton)
                self.disableButton(self.reloadAllButton)
                # allowing reinit to pioneer is most likely to cause crashing, so don't
                self.pushToolbarButton('eBot', self.ENABLED)
                self.enableToolbarButton('brain')
                #CHANGED commented out
                #self.enableToolbarButton('joystick')
                # can't step the real robot
                self.disableToolbarButton('step')
                if self.brainfile != "":
                    self.enableButton(self.reloadBrainButton)
                    self.enableButton(self.reloadAllButton)
            self.unpushToolbarButton('simulator')
            self.unpushToolbarButton('Amigosimulator')
            self.reloadBrain(True)
        # print "Hello"
        # import soar.outputs.eBotDemo
        #from soar.outputs.eBotDemo import eBotDemo
        #eBotDemo()

    def closeEBot(self, callUserFn=True):
        self.stopall(callUserFn)
        self.setOutput(lambda: None)
        self.unpushToolbarButton('eBot')
        # don't have output, so disable brain loading
        #CHANGED commented out
        #self.disableToolbarButton('joystick')
        self.disableToolbarButton('brain')
        self.disableButton(self.reloadBrainButton)
        self.disableButton(self.reloadAllButton)

    def openPioneer(self):
        import soar.outputs.pioneer
        # allow pioneer button to be unpushed to disconnect
        if self.toolbar.buttons['pioneer'].cget('relief') == SUNKEN:
            self.closePioneer(False)
        else:
            if self.setOutput(lambda: soar.outputs.pioneer.Pioneer()):
                #self.disableButton(self.reloadWorldButton)
                self.disableButton(self.reloadAllButton)
                # allowing reinit to pioneer is most likely to cause crashing, so don't
                self.pushToolbarButton('pioneer', self.ENABLED)
                self.enableToolbarButton('brain')
                #CHANGED commented out
                #self.enableToolbarButton('joystick')
                # can't step the real robot
                self.disableToolbarButton('step')
                if self.brainfile != "":
                    self.enableButton(self.reloadBrainButton)
                    self.enableButton(self.reloadAllButton)
            self.unpushToolbarButton('simulator')
            self.reloadBrain(True)

    def closePioneer(self, callUserFn=True):
        self.stopall(callUserFn)
        self.setOutput(lambda: None)
        self.unpushToolbarButton('pioneer')
        # don't have output, so disable brain loading
        #CHANGED commented out
        #self.disableToolbarButton('joystick')
        self.disableToolbarButton('brain')
        self.disableButton(self.reloadBrainButton)
        self.disableButton(self.reloadAllButton)

    def openBrain(self, brainfile, reload=False):
        import soar.controls.brain
        if (len(brainfile) > 0):
            # clear error, output windows
            self.clearOutput()
            self.clearErrors()
            if (reload):
                print("***Reloading Brain***")
            else:
                print("***Loading Brain***")
            print("'" + brainfile + "'")
            self.setControl(
                lambda: soar.controls.brain.Brain(brainfile, reload),
                not reload)
            if self.control:
                self.pushToolbarButton('brain', self.ENABLED)
                self.enableButton(self.reloadBrainButton)
                self.chooseStop(self.output != None)
                if self.output:
                    #CHANGED commented out
                    #self.unpushToolbarButton('joystick')
                    self.enableButton(self.reloadAllButton)
                print("Successfully loaded brain file")
                print("'" + brainfile + "'")
            else:
                #self.disableButton(self.reloadBrainButton)
                print("Failed to load brain file '" + brainfile + "'")

    def reloadAll(self):
        self.reloadWorld()
        self.reloadBrain()

    def reloadBrain(self, quiet=False):
        if self.brainfile == "" and not quiet:
            sys.stderr.write("No valid brain filename to reload.\n")
        if self.control is not None:
            try:
                self.control.reload()
            except AttributeError:
                # we must have tried to reload the joystick (yes, this is ugly)
                if self.brainfile != "":
                    self.openBrain(self.brainfile, True)
        # if we failed, and we have a brainfile, just try loading the brain
        # as opposed to REloading
        if self.control is None and self.brainfile != "":
            self.openBrain(self.brainfile, False)

    def reloadWorld(self):
        if self.output is not None:
            try:
                self.output.initGlobals(True)
            except AttributeError:
                pass

    def openSonarMonitor(self):
        if not self.sonar_monitor:
            if self.toolbar.buttons['eBot'].cget('relief') == SUNKEN:
                self.sonar_monitor = SonarMonitor(
                    soar.outputs.eBot.EBOT_POINTS, self.sonarmon_geom)
            elif self.toolbar.buttons['Amigosimulator'].cget(
                    'relief') == SUNKEN:
                self.sonar_monitor = AmigoSonarMonitor(
                    soar.outputs.amigo_simulator.ROBOT_POINTS,
                    self.sonarmon_geom)
            elif self.toolbar.buttons['simulator'].cget('relief') == SUNKEN:
                self.sonar_monitor = SonarMonitor(
                    soar.outputs.simulator.ROBOT_POINTS, self.sonarmon_geom)
            elif self.toolbar.buttons['pioneer'].cget('relief') == SUNKEN:
                self.sonar_monitor = AmigoSonarMonitor(
                    soar.outputs.amigo_simulator.ROBOT_POINTS,
                    self.sonarmon_geom)
        self.sonar_monitor.openWindow()

    def closeSonarMonitor(self):
        if self.sonar_monitor:
            self.sonar_monitor.closeWindow()
            self.sonar_monitor = None

    def openJoystick(self):
        import soar.controls.joystick
        self.setControl(lambda: soar.controls.joystick.Joystick())
        #CHANGED commented out
        #self.pushToolbarButton('joystick')
        self.unpushToolbarButton('brain')

    def closeOscillo(self):
        if self.oscope:
            self.oscope.closeWindow()
        self.oscope = None

    def openOscillo(self):
        if not self.oscope:
            self.oscope = Oscilloscope(self.scope_geom)
        self.oscope.openWindow()

    def add_scope_probe_function(self, name, func):
        self.oscope.add_probeFunction(name, func)

    def clear_scope(self):
        if self.oscope:
            self.oscope.clearProbes()
            self.oscope.closeWindow()

    def openSimulatorDialog(self):
        filename = widgets.askopenfilename(
            title="Open a World File...",
            initialdir=self.simulator_dir_default,
            filetypes=[("World Files", "*.py")])
        if (len(filename) > 0):
            self.simulator_dir_default = filename[0:filename.rfind("/")]
        return [filename]

    def openAmigoSimulatorDialog(self):
        filename = widgets.askopenfilename(
            title="Open a World File...",
            initialdir=self.simulator_dir_default,
            filetypes=[("World Files", "*.py")])
        if (len(filename) > 0):
            self.simulator_dir_default = filename[0:filename.rfind("/")]
        return [filename]

    def openBrainDialog(self):
        filename = widgets.askopenfilename(title="Open a Brain File...",
                                           initialdir=self.brain_dir_default,
                                           filetypes=[("Brain Files", "*.py")])
        self.brainfile = filename
        if (len(filename) > 0):
            self.brain_dir_default = filename[0:filename.rfind("/")]
            os.chdir(self.brain_dir_default)
            self.enableButton(self.reloadBrainButton)
        return [filename]

    def removeFlowTriplet(self, trip):
        self.flowtriplets.remove(trip)

    def addFlowTriplet(self, trip):
        self.flowtriplets.append(trip)

    def setReadLog(self, f):
        self.control.readfile = open(f, 'rb')

    def setWriteLog(self, f):
        self.control.writefile = open(f, 'wb')

    def enableToolbarButton(self, name):
        self.enableButton(self.toolbar.buttons[name])

    def disableToolbarButton(self, name):
        self.disableButton(self.toolbar.buttons[name])

    def pushToolbarButton(self, name, state=DISABLED):
        self.pushButton(self.toolbar.buttons[name], state)
        self.toolbar.buttonImage(name, 'active')

    def unpushToolbarButton(self, name, state=ENABLED):
        self.unpushButton(self.toolbar.buttons[name], state)
        self.toolbar.buttonImage(name, 'normal')

    def flashToolbarButton(self, name):
        self.toolbar.buttons[name].flash()

    def enableButton(self, button):
        button.config(state=NORMAL)

    def disableButton(self, button):
        button.config(state=DISABLED)

    def buttonState(self, button, state):
        if state == self.DISABLED:
            self.disableButton(button)
        elif state == self.ENABLED:
            self.enableButton(button)

    def pushButton(self, button, state=DISABLED):
        button.config(relief=SUNKEN)
        self.buttonState(button, state)

    def unpushButton(self, button, state=ENABLED):
        button.config(relief=RAISED)
        self.buttonState(button, state)

    def chooseStart(self):
        self.pushToolbarButton('start')
        self.unpushToolbarButton('stop')
        self.pushToolbarButton('step')
        # can't choose control or output while running
        self.disableToolbarButton('simulator')
        self.disableToolbarButton('pioneer')
        self.disableToolbarButton('brain')
        #CHANGED commented out
        #self.disableToolbarButton('joystick')
        self.disableButton(self.reloadBrainButton)
        self.disableButton(self.reloadAllButton)

    def chooseStop(self, allowStart=1):
        if (allowStart):
            self.unpushToolbarButton('start')
            self.unpushToolbarButton('step')
        else:
            self.unpushToolbarButton('start', self.DISABLED)
            self.unpushToolbarButton('step', self.DISABLED)
        self.unpushToolbarButton('stop', self.DISABLED)
        # now we can choose control and output again
        self.enableToolbarButton('simulator')
        self.enableToolbarButton('Amigosimulator')
        self.enableToolbarButton('pioneer')
        self.enableToolbarButton('brain')
        #CHANGED commented out
        #self.enableToolbarButton('joystick')
        if self.brainfile != "":
            self.enableButton(self.reloadBrainButton)
            self.enableButton(self.reloadAllButton)

    def disableStartStop(self):
        self.unpushToolbarButton('start', self.DISABLED)
        self.unpushToolbarButton('stop', self.DISABLED)
        self.unpushToolbarButton('step', self.DISABLED)

    def setControl(self, lazy_control, allow_start=1):
        if self.readfile:
            self.readfile.close()
        if self.writefile:
            self.writefile.close()
        self.unloadModule(self.control)
        # try to read in the brain file.  if it fails, unload the module
        try:
            self.control = lazy_control()
        except Exception as e:
            self.disableStartStop()
            self.unloadModule(self.control)
            self.control = None
            raise e
        self.readfile = False
        self.writefile = False
        # if we did read in the file, try to call the setup function
        # if the setup function fails, unload the module
        if self.control != None:
            try:
                self.userfn.call_functions('setup')
                self.loadModule(self.control)
            except:
                self.unloadModule(self.control)
                self.control = None
        if ((self.output != None) and allow_start):
            self.chooseStop(True)
        elif (self.output is None):
            self.disableStartStop()

    def setOutput(self, lazy_output):
        self.unloadModule(self.output)
        try:
            self.output = lazy_output()
            if self.output == None:
                self.disableStartStop()
                return 0
            else:
                self.loadModule(self.output)
                self.logstep()
                if (self.control != None):
                    self.chooseStop(True)
                else:
                    self.disableStartStop()
                return 1
        except common.CancelGUIAction:
            self.output = None
            self.disableStartStop()
            return 0

    def register_user_function(self, type, f):
        self.userfn.registerFn(type, f)

    def initializeNamespace(self):
        if hasattr(self, 'namespace'):
            self.namespace.clear()
        else:
            self.namespace = {}
        self.setters = {}
        self.getters = {}
        self.cachedvalues = {}
        self.namespace["robot"] = common.Container()
        self.namespace["readLog"] = self.setReadLog
        self.namespace["writeLog"] = self.setWriteLog
        self.namespace["register_user_function"] = self.register_user_function

    def startall(self):
        for i in self.flowtriplets:
            i[0]()
        self.chooseStart()
        try:
            self.userfn.call_functions('brain_start')
            self.control.start()
        except AttributeError:
            pass
        self.disableButton(self.reloadBrainButton)
        self.disableButton(self.reloadAllButton)
        if (self.use_active_button_images):
            self.flashToolbarButton('stop')

    def stopall(self, callUserFn=True):
        for i in self.flowtriplets:
            i[2]()
        self.chooseStop()
        try:
            if callUserFn:
                self.userfn.call_functions('brain_stop')
        except AttributeError:
            pass
        try:
            self.control.stop()
        except AttributeError:
            pass
        if self.brainfile != "":
            self.enableButton(self.reloadBrainButton)
            self.enableButton(self.reloadAllButton)
        if (self.use_active_button_images):
            self.flashToolbarButton('start')

    def stepall(self, dt=0.1):
        for i in self.flowtriplets:
            i[1](dt)

    def stopstepper(self):
        try:
            self.currentstepper.stop()
        except AttributeError:
            pass

    def startstepper(self):
        self.stopstepper()
        self.currentstepper = parallel.Stepper(self.step, 20.0)
        self.currentstepper.start()

    def logstep(self):
        if self.readfile:
            try:
                for pair in pickle.load(self.readfile):
                    self.cachedvalues[pair[0]].set(pair[1])
            except KeyError:
                app.alert("Log from an incompatible getter/setter interface")
                self.stopall()
            except EOFError:
                app.alert("Log Finished")
                self.stopall()
        else:
            for k in self.getters:
                try:
                    self.cachedvalues[k].set(self.getters[k]())
                except:
                    common.formerror()
        if self.writefile:
            pickle.dump([(k, self.cachedvalues[k].get())
                         for k in self.cachedvalues[k]], self.writefile)

    def step(self, dt):
        if self.output is not None:
            try:
                self.userfn.call_functions('step')
                if self.sonar_monitor:
                    self.sonar_monitor.update(self.output.storedsonars.get())
                if self.oscope: self.oscope.step()
                self.logstep()
                self.control.step(dt)
            except KeyError:
                common.formerror()


#        self.stopall()
            except:
                self.stopall()
                #raise

    def unloadModule(self, obj):
        if (obj == None):
            return
        try:
            self.userfn.call_functions('shutdown')
            obj.shutdown()
            self.userfn.clearFunctions()
        except:
            pass
        try:
            for name in obj.getters:
                self.getters.pop(name)
                self.namespace.pop(name)
        except AttributeError:
            pass
        try:
            for name in obj.setters:
                self.setters.pop(name)
                self.namespace.pop(name)
        except AttributeError:
            pass
        try:
            obj.destroy()
        except AttributeError:
            pass  # OK if modules have no cleanup code
        except:
            common.formerror()

    def loadModule(self, obj):
        try:
            for name in obj.getters:
                self.getters[name] = obj.getters[name]
                self.cachedvalues[name] = parallel.SharedVar()
                self.namespace[name] = self.cachedvalues[name].get
        except AttributeError:
            obj.getters = {}
        try:
            for name in obj.setters:
                self.setters[name] = obj.setters[name]
                self.namespace[name] = obj.setters[name]
        except AttributeError:
            obj.setters = {}
        try:
            obj.setup()
        except AttributeError:
            pass