class InputInterface(object):
    USE_GUI = True

    def __init__(self):
        self.cmd_func = None
        self.is_normalized = True
        self.current_pos = []
        self.is_chair_activated = False
        self.coaster = CoasterInterface()
        self.gui = CoasterGui(self.dispatch, self.pause, self.reset,
                              self.set_activate_state, self.quit)
        actions = {
            'detected remote': self.detected_remote,
            'activate': self.activate,
            'deactivate': self.deactivate,
            'pause': self.pause,
            'dispatch': self.dispatch,
            'reset': self.reset,
            'emergency_stop': self.emergency_stop
        }
        self.RemoteControl = SerialRemote(actions)
        self.prev_movement_time = 0  # holds the time of last reported movement from NoLimits
        self.isNl2Paused = False
        self.coasterState = State(self.process_state_change)
        self.rootTitle = "NL2 Coaster Ride Controller"  # the display name in tkinter

    def init_gui(self, master, limits):
        self.gui.init_gui(master, limits)
        self.master = master

    def _sleep_func(self, duration):
        start = time.time()
        while time.time() - start < duration:
            self.master.update_idletasks()
            self.master.update()
            win32gui.PumpWaitingMessages()

    def check_is_stationary(self, speed):
        if speed < 0.001:
            if time.time() - self.prev_movement_time > 3:
                return True
        else:
            self.prev_movement_time = time.time()
        return False

    def command(self, cmd):
        if self.cmd_func is not None:
            print "Requesting command with", cmd
            self.cmd_func(cmd)

    def dispatch(self):
        if self.is_chair_activated and self.coasterState.state == MoveState.READY_FOR_DISPATCH:
            print 'dispatch'
            self.coasterState.coaster_event(CoasterEvent.DISPATCHED)
            self.coaster.close_harness()
            #  self.command("activate")
            self._sleep_func(2)
            self.coaster.dispatch()
            self.prev_movement_time = time.time(
            )  # set time that train started to move

    def pause(self):
        if self.coasterState.state in (MoveState.RUNNING, MoveState.PAUSED,
                                       MoveState.EMERGENCY_STOPPED):
            self.coaster.toggle_pause()

    def reset(self):
        if self.coasterState.state == MoveState.EMERGENCY_STOPPED:
            #  here after disabling while coaster is RUNNING
            self.coaster.toggle_pause()
            if self.is_chair_activated is True:
                self.command(
                    "disable")  # should already be deactivated but to be sure
            self.coasterState.coaster_event(CoasterEvent.RESETEVENT)
            #  self.openHarness()
            print 'Moving train to station at high speed'
            self.coaster.increase_speed(4)  # 4x is max speed
        elif self.coasterState.state == MoveState.RESETTING or self.coasterState.state == MoveState.READY_FOR_DISPATCH:
            #  here if reset pressed after estop and before dispatching
            print "command in PlatformOutput to move from current to wind down, wait, then back to current pos"
            self.command("swellForStairs")

    def emergency_stop(self):
        print "legacy emergency stop callback"
        self.deactivate()

    def set_activate_state(self, state):
        #  print "in setActivatedState", state
        if state:
            self.activate()
        else:
            self.deactivate()

    def activate(self):
        #  only activate if coaster is ready for dispatch
        if self.coasterState.state == MoveState.READY_FOR_DISPATCH:
            #  print "in activate "
            self.is_chair_activated = True
            self.coasterState.set_is_chair_active(True)
            self.command("enable")
            self.gui.set_activation_buttons(True)
            self.gui.process_state_change(self.coasterState.state, True)
            self.coaster.set_normal_speed(
            )  # sets speed to 1 if set higher after estop
        else:
            print "Not activating because not ready for dispatch"

    def deactivate(self):
        #  print "in deactivate "
        self.command("disable")
        self.gui.set_activation_buttons(False)
        self.is_chair_activated = False
        self.coasterState.set_is_chair_active(False)
        if self.coasterState.state == MoveState.RUNNING:
            self.pause()
            print 'emergency stop '
            self.coasterState.coaster_event(CoasterEvent.ESTOPPED)
        else:
            self.coasterState.coaster_event(CoasterEvent.DISABLED)
        self.gui.process_state_change(self.coasterState.state, False)

    def quit(self):
        self.command("quit")

    def detected_remote(self, info):
        if "Detected Remote" in info:
            self.set_remote_status_label((info, "green3"))
        elif "Looking for Remote" in info:
            self.set_remote_status_label((info, "orange"))
        else:
            self.set_remote_status_label((info, "red"))

    def set_coaster_connection_label(self, label):
        self.gui.set_coaster_connection_label(label)

    def chair_status_changed(self, chair_status):
        self.gui.chair_status_changed(chair_status)

    def set_remote_status_label(self, label):
        self.gui.set_remote_status_label(label)

    def process_state_change(self, new_state):
        if new_state == MoveState.READY_FOR_DISPATCH and self.is_chair_activated:
            #  here at the end of a ride
            self.command("disembark")
        self.gui.process_state_change(new_state, self.is_chair_activated)

    def begin(self, cmd_func, move_func):
        self.cmd_func = cmd_func
        self.move_func = move_func
        self.coaster.begin()
        while not self.coaster.is_NL2_accessable():
            self.master.update_idletasks()
            self.master.update()
            result = tkMessageBox.askquestion(
                "Waiting for NoLimits Coaster",
                "Coaster Sim not found, Start NoLimits and press Yes to retry, No to quit",
                icon='warning')
            if result == 'no':
                sys.exit(0)

        while True:
            self.master.update_idletasks()
            self.master.update()
            if self.coaster.connect_to_coaster():
                #  print "connected"
                self.coaster.set_manual_mode()
                break
            else:
                print "Failed to connect to coaster"
                print "Use shortcut to run NoLimits2 in Telemetry mode"

        if self.coaster.is_NL2_accessable():
            self.gui.set_coaster_connection_label(
                ("Coaster Software Connected", "green3"))
        else:
            self.gui.set_coaster_connection_label(
                ("Coaster Software Not Found"
                 "(start NL2 or maximize window if already started)", "red"))

    def fin(self):
        # client exit code goes here
        pass

    def get_current_pos(self):
        return self.current_pos

    def service(self):
        self.RemoteControl.service()
        input_field = self.coaster.get_telemetry()
        #print "data from coaster", input_field
        if self.coaster.get_telemetry_status() and input_field and len(
                input_field) == 3:
            self.gui.set_coaster_connection_label(
                ("Receiving Coaster Telemetry", "green3"))
            isRunning = input_field[0]
            speed = float(input_field[1])
            self.isNl2Paused = not isRunning
            if isRunning:
                if self.check_is_stationary(speed):
                    self.coasterState.coaster_event(CoasterEvent.STOPPED)
                    #  here if coaster not moving and not paused
                    #  print "Auto Reset"
                else:
                    if self.coasterState.state == MoveState.UNKNOWN:
                        # coaster is moving at startuo
                        self.coasterState.coaster_event(
                            CoasterEvent.RESETEVENT)
                    else:
                        self.coasterState.coaster_event(CoasterEvent.UNPAUSED)

            else:
                self.coasterState.coaster_event(CoasterEvent.PAUSED)
            #  print isRunning, speed

            if len(input_field[2]) == 6:
                self.current_pos = [float(f) for f in input_field[2]]
            if self.is_chair_activated and self.coasterState.state != MoveState.READY_FOR_DISPATCH:
                # only send if activated and not waiting in station
                if self.move_func is not None:
                    self.move_func(self.current_pos)
        else:
            errMsg = format("Telemetry error: %s" %
                            self.coaster.get_telemetry_err_str())
            #  print errMsg
            self.gui.set_coaster_connection_label((errMsg, "red"))
Beispiel #2
0
class InputInterface(object):
    USE_GUI = True

    def __init__(self):
        self.cmd_func = None
        self.is_normalized = True
        self.current_pos = []
        self.is_chair_activated = False
        self.coaster = CoasterInterface()
        self.gui = CoasterGui(self.dispatch, self.pause, self.reset, self.set_activate_state, self.quit)
        actions = {'detected remote': self.detected_remote, 'activate': self.activate,
                   'deactivate': self.deactivate, 'pause': self.pause, 'dispatch': self.dispatch,
                   'reset': self.reset, 'emergency_stop': self.emergency_stop, 'intensity' : self.set_intensity}
        self.RemoteControl = SerialRemote(actions)
        self.prev_movement_time = 0  # holds the time of last reported movement from NoLimits
        self.isNl2Paused = False
        self.speed = 0
        self.isLeavingStation = False  # set true on dispatch, false when no longer in station
        self.coasterState = State(self.process_state_change)
        self.rootTitle = "NL2 Coaster Ride Controller"  # the display name in tkinter
        self.prev_heartbeat = 0
        self.server_address = None # set on receipt of hearbeat from server

    def init_gui(self, master):
        self.gui.init_gui(master)
        self.master = master

    def connection_msgbox(self, msg):
        result = tkMessageBox.askquestion(msg, icon='warning')
        return result != 'no'

    def _sleep_func(self, duration):
        start = time.time()
        while time.time() - start < duration:
            self.master.update_idletasks()
            self.master.update()

    def command(self, cmd):
        if self.cmd_func is not None:
            print "Requesting command:", cmd
            self.cmd_func(cmd)

    def dispatch(self):
        if self.is_chair_activated and self.coasterState.state == RideState.READY_FOR_DISPATCH:
            print 'dispatch'
            self.coasterState.coaster_event(CoasterEvent.DISPATCHED)
            print "preparing to dispatch"
            while not self.coaster.prepare_for_dispatch():
                 self._sleep_func(1)
            self.command("ready")  # slow rise of platform
            self.command("unparkPlatform")
            print "todo check delay is needed to free platform"
            #  self._sleep_func(1)
            self.coaster.dispatch()
            print "dispatched"
            self.prev_movement_time = time.time()  # set time that train started to move
            self.isLeavingStation = True
            while self.coaster.is_train_in_station():
                print "Leaving station"
                pass
            """
            while self.coaster.train_in_station:
                self.coaster.get_station_state()
                print "sent get station state"
                print "todo - exit and handle if not ready to dispatch"
                self.service()
            """
            self.isLeavingStation = False
            print "left station"

    def pause(self):
        if self.coasterState.state  == RideState.RUNNING:
            self.coaster.set_pause(True)
        elif self.coasterState.state == RideState.PAUSED:
            self.coaster.set_pause(False)
        elif self.coasterState.state == RideState.READY_FOR_DISPATCH:
            self.command("swellForStairs")

    def reset(self):
        self.coaster.reset_rift()

    def set_intensity(self, intensity_msg):
        self.command(intensity_msg)

    def emergency_stop(self):
        print "legacy emergency stop callback"
        self.deactivate()

    def set_activate_state(self, state):
        #  print "in setActivatedState", state
        if state:
            self.activate()
        else:
            self.deactivate()

    def activate(self):
        #  only activate if coaster is ready for dispatch
        #  print "in activate state= ", self.coasterState.state
        print "resetting park in manual mode"
        #self.coaster.set_manual_mode()
        self.coaster.reset_park(False)
        self.coasterState.coaster_event(CoasterEvent.RESETEVENT)
        ####if self.coasterState.state == RideState.READY_FOR_DISPATCH:
        #  print "in activate "
        self.is_chair_activated = True
        self.coasterState.set_is_chair_active(True)
        self.command("enable")
        self.gui.set_activation_buttons(True)
        self.gui.process_state_change(self.coasterState.state, True)
        #  print "in activate", str(RideState.READY_FOR_DISPATCH), RideState.READY_FOR_DISPATCH
        self.RemoteControl.send(str(RideState.READY_FOR_DISPATCH))

    def deactivate(self):
        #  print "in deactivate "
        if self.coasterState.state == RideState.READY_FOR_DISPATCH:
            self.RemoteControl.send(str(RideState.DISABLED))
        self.command("disable")
        self.gui.set_activation_buttons(False)
        self.is_chair_activated = False
        self.coasterState.set_is_chair_active(False)
        if self.coasterState.state == RideState.RUNNING or self.coasterState.state == RideState.PAUSED:
            if self.coasterState.state != RideState.PAUSED:
                self.pause()
            print 'emergency stop '
            self.coasterState.coaster_event(CoasterEvent.ESTOPPED)
        else:
            self.coasterState.coaster_event(CoasterEvent.DISABLED)
        self.gui.process_state_change(self.coasterState.state, False)

    def quit(self):
        self.command("quit")

    def detected_remote(self, info):
        if "Detected Remote" in info:
            self.set_remote_status_label((info, "green3"))
        elif "Looking for Remote" in info:
            self.set_remote_status_label((info, "orange"))
        else:
            self.set_remote_status_label((info, "red"))

    def set_coaster_connection_label(self, label):
        self.gui.set_coaster_connection_label(label)

    def chair_status_changed(self, status):
        self.gui.chair_status_changed(status)

    def temperature_status_changed(self, status):
        self.gui.temperature_status_changed(status)

    def intensity_status_changed(self, status):
        self.gui.intensity_status_changed(status)

    def set_remote_status_label(self, label):
        self.gui.set_remote_status_label(label)

    def process_state_change(self, new_state):
        #  print "in process state change", new_state, self.is_chair_activated
        if new_state == RideState.READY_FOR_DISPATCH:
            if self.is_chair_activated:
                #  here at the end of a ride
                self.command("idle")  # slow drop of platform
                self.RemoteControl.send(str(RideState.READY_FOR_DISPATCH))
            else:
                self.RemoteControl.send(str(RideState.DISABLED)) # at station but deactivated
        else: 
            self.RemoteControl.send(str(new_state))

        self.gui.process_state_change(new_state, self.is_chair_activated)

    def load_park(self, isPaused, park, seat):

        print "load park", park, "seat",seat
        self.coasterState.coaster_event(CoasterEvent.RESETEVENT) 
        self.gui.set_coaster_connection_label(("loading: " + park, "orange"))
        self._sleep_func(2)
        self.coaster.load_park(isPaused, park)
        while self.coaster.check_coaster_status(ConnectStatus.is_in_play_mode) == False:
            self.service()
        print "selecting seat", seat
        self.coaster.select_seat(int(seat))
        self.coasterState.coaster_event(CoasterEvent.STOPPED)

    def fin(self):
        # client exit code goes here
        heartbeat.fin()

    def get_current_pos(self):
        return self.current_pos

    def begin(self, cmd_func, move_func, limits):      
        self.cmd_func = cmd_func
        self.move_func = move_func
        #self.limits = limits
        heartbeat.begin()
        self.coaster.begin()
        self.gui.set_park_callback(self.load_park)
        while not self.connect():
             self._sleep_func(0.1)
        self.coaster.reset_park(False)
        return True  # now always returns true, connections are completed in service if necessary
    
    def check_heartbeat(self):
        addr, heartbeat_status, warning = heartbeat.read()
        #  print "in connect, addr = ", addr,  addr[1] == 10011
        if len(addr[0]) > 6 and addr[1]  == 10011: #  server sends on port 10011
            self.prev_heartbeat = time.time()
            if self.server_address != addr[0]:
                self.server_address = addr[0]
                print "first time connection to server @", self.server_address
            #  print format("heartbeat {%s:%s} {%s} {%s}" % (addr[0], addr[1], heartbeat_status, warning))
            self.gui.set_coaster_connection_label((heartbeat_status,colors[warning]))
            self.temperature_status_changed((heartbeat_status, colors[warning]))
            self.coaster.set_coaster_status(ConnectStatus.is_pc_connected, True)

        # print "t=", time.time() - self.prev_heartbeat
        duration = time.time() - self.prev_heartbeat
        if duration > 3.2: # if no heartbeat after three seconds
            self.coaster.set_coaster_status(ConnectStatus.is_pc_connected, False)
            self.temperature_status_changed(("Lost heartbeat with server", "red"))
            return False
        elif duration > 2.2: # if no heartbeat after two seconds
            self.temperature_status_changed(("Missed Heartbeat from Server", "orange"))
            self.gui.set_coaster_connection_label(("Attempting to connect to No Limits", "red"))
        return True

    def connect(self):
        if not self.check_heartbeat():
            return False
        elif not self.coaster.check_coaster_status(ConnectStatus.is_nl2_connected):
            if not self.coaster.connect_to_coaster(self.server_address):
                print "coaster connect returned false!!!!!!" 
                self.gui.set_coaster_connection_label(("No connection to NoLimits, is it running?", "red"))
                self._sleep_func(1)
            return False
            """    
            elif not self.coaster.check_coaster_status(ConnectStatus.is_in_play_mode):
                print "!!!NL2 not in play mode"
                return False
            """
        else:
            #  print "All connections ok"
            # self.coasterState.coaster_event(CoasterEvent.STOPPED)
            return True


    def check_is_stationary(self, speed):
        if speed < 0.1:
            #if self.coaster.get_station_status(bit_train_in_station | bit_current_train_in_station):
            if self.coaster.is_train_in_station():
                #  print "in station check, leaving flag is", self.isLeavingStation, speed
                if self.isLeavingStation == False:
                   #  print "in station check, state is ",  self.coasterState
                   if self.coasterState.state == RideState.RUNNING:
                       print "train arrived in station"
                       self.command("parkPlatform")
                       print "Todo check if swell or delay is needed here"
                       return True
                ##print "CAN DISPATCH"
            else:
                #  print "in station check, setting leaving flag to false"  
                self.isLeavingStation = False

            if time.time() - self.prev_movement_time > 3:
                #  print "speed", speed
                return True
        else:
            self.prev_movement_time = time.time()
            self.gui.set_coaster_status_label(speed)
        return False

    def service(self):
        self.RemoteControl.service()
        if self.connect():
            self.coaster.service()
            status  = self.coaster.get_coaster_status()
            self.gui.set_coaster_connection_label((status[1], status[2]))
            input_field = self.coaster.get_telemetry()
            # print len(input_field), "data fieldsfrom coaster", input_field 
            #if self.coaster.get_telemetry_status() and input_field and len(input_field) == 3:
            if input_field and len(input_field) == 4:
                is_in_play_mode = input_field[0]
                # print "is_in_play_mode",  is_in_play_mode
                if is_in_play_mode:
                    self.gui.set_coaster_connection_label(("Receiving Coaster Telemetry", "green3"))
                    isRunning = input_field[1]
                    self.speed = float(input_field[2])
                    self.isNl2Paused = not isRunning
                    if isRunning:
                        # print "is running"
                        if self.check_is_stationary(self.speed):
                            #  print "is stopped??"
                            self.coasterState.coaster_event(CoasterEvent.STOPPED)
                            #  here if coaster not moving and not paused
                            #  print "Auto Reset"
                        else:
                            if self.coasterState.state == RideState.DISABLED:
                                # coaster is moving at startup
                                self.coasterState.coaster_event(CoasterEvent.RESETEVENT)
                            else:                                
                                self.coasterState.coaster_event(CoasterEvent.UNPAUSED)
                    else:
                        self.coasterState.coaster_event(CoasterEvent.PAUSED)
                    #  print isRunning, speed
                    """  
                        if self.coasterState.state == RideState.PAUSED:
                             self.coasterState.coaster_event(CoasterEvent.UNPAUSED)
                        if self.speed < 0.1:
                            print "speed", self.speed
                            if not self.isLeavingStation:
                                print "not leaving station"
                                if self.coaster.is_train_in_station():
                                    print "coaster is in station"
                                    if self.coaster.is_in_play_mode():
                                        print "setting stop state because in station"
                                        self.coasterState.coaster_event(CoasterEvent.STOPPED)
                                    else:
                                        self.gui.set_coaster_connection_label(("Coaster not in play mode", "red"))
                                        return
                                else:
                                    print "train is not in station ??, status=",  self.coaster.is_train_in_station()
                        self.coasterState.coaster_event(CoasterEvent.PAUSED)
                    """
                    #  print isRunning, speed
                else:
                    self.gui.set_coaster_connection_label(("Coaster not in play mode", "red"))

                if  input_field[3] and len(input_field[3]) == 6:  # check if we have data for all 6 DOF
                        self.current_pos = [float(f) for f in input_field[3]]
                if self.is_chair_activated and self.coasterState.state != RideState.READY_FOR_DISPATCH:
                        # only send if activated and not waiting in station
                        if self.move_func is not None:
                            self.move_func(self.current_pos)

            else:
                errMsg = format("Telemetry error: %s" % self.coaster.get_telemetry_err_str())
                #  print errMsg
                self.gui.set_coaster_connection_label((errMsg, "red"))
Beispiel #3
0
class InputInterface(object):
    USE_GUI = True  # set True if using tkInter
    print "USE_GUI", USE_GUI

    def __init__(self):
        #  set True if input range is -1 to +1
        self.is_normalized = True
        self.expect_degrees = False  # convert to radians if True
        self.HOST = "localhost"
        self.PORT = 10009
        if self.is_normalized:
            print 'Platform Input is UDP with normalized parameters'
        else:
            print 'Platform Input is UDP with realworld parameters'
        self.levels = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
        self.rootTitle = "UDP Platform Interface"
        self.inQ = Queue()
        t = threading.Thread(target=self.listener_thread, args=(self.inQ, self.HOST, self.PORT))
        t.daemon = True
        t.start()
        actions = {'detected remote': self.detected_remote, 'activate': self.activate,
                   'deactivate': self.deactivate, 'pause': self.pause, 'dispatch': self.dispatch,
                   'reset': self.reset, 'emergency_stop': self.emergency_stop, 'intensity': self.set_intensity}
        self.RemoteControl = SerialRemote(actions)

    def init_gui(self, master):
        self.master = master
        frame = tk.Frame(master)
        frame.pack()
        self.label0 = tk.Label(frame, text="Accepting UDP messages on port " + str(self.PORT))
        self.label0.pack(fill=tk.X, pady=10)

        """ 
        self.units_label = tk.Label(frame, text=t)
        self.units_label.pack(side="top", pady=10)
        """

        self.msg_label = tk.Label(frame, text="")
        self.msg_label.pack(side="top", pady=10)

        self.cmd_label = tk.Label(frame, text="")
        self.cmd_label.pack(side="top", pady=10)

    def chair_status_changed(self, chair_status):
        print(chair_status[0])

    def begin(self, cmd_func, move_func, limits):
        self.cmd_func = cmd_func
        self.move_func = move_func


    def fin(self):
        # client exit code goes here
        pass

    def get_current_pos(self):
        return self.levels

    def intensity_status_changed(self, status):
        pass

    def service(self):
        self.RemoteControl.service()
        # move request returns translations as mm and angles as radians
        msg = None
        # throw away all but most recent message
        while not self.inQ.empty():
            msg = self.inQ.get()
        try:
            if msg is not None:
                msg = msg.rstrip()
                # print msg
                fields = msg.split(",")
                field_list = list(fields)
                if field_list[0] == "xyzrpy":
                    # self.msg_label.config(text="got: " + msg)
                    try:
                        r = [float(f) for f in field_list[1:7]]
                        # remove next 3 lines if angles passed as radians 
                        if self.move_func:
                            # print r
                            self.move_func(r)
                            self.levels = r
                    except:  # if not a list of floats, process as command
                        e = sys.exc_info()[0]
                        print "UDP svc err", e
                elif field_list[0] == "command":
                    print "command is {%s}:" % (field_list[1])
                    self.cmd_label.config(text="Most recent command: " + field_list[1])
                    if self.cmd_func:
                        self.cmd_func(field_list[1])
        except:
            #  print error if input not a string or cannot be converted into valid request
            e = sys.exc_info()[0]
            s = traceback.format_exc()
            print e, s

    def detected_remote(self, info):
        print info

    def activate(self):
        self.cmd_func("enable")
        print "activate"

    def deactivate(self):
        self.pause()
        self.cmd_func("disable")
        # directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
        keys.PressKey(0x01)
        time.sleep(0.05)#Keep the sleep at 50ms to prevent double click of esc button
        keys.ReleaseKey(0x01)
        print "deactivate"

    def pause(self):
        # directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
        keys.PressKey(0x01)
        time.sleep(0.05)#Keep the sleep at 50ms to prevent double click of esc button
        keys.ReleaseKey(0x01)
        print "pause"

    def dispatch(self):
        # directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
        keys.PressKey(0x1C)
        time.sleep(0.05)#Keep the sleep at 50ms to prevent double click of esc button
        keys.ReleaseKey(0x1C)
        print "dispatch"

    def reset(self):
        # directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
        keys.PressKey(0xC7)
        time.sleep(0.05)#Keep the sleep at 50ms to prevent double click of esc button
        keys.ReleaseKey(0xC7)
        print "reset"

    def emergency_stop(self):
        self.deactivate()
        self.pause()
        print "stop"

    def set_intensity(self, intensity):
        self.cmd_func(intensity)
        print "intensity ", intensity

    def listener_thread(self, inQ, HOST, PORT):
        try:
            self.MAX_MSG_LEN = 1024
            client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            client.bind((HOST, PORT))
            print "opening socket on", PORT
            self.inQ = inQ
        except:
            e = sys.exc_info()[0]
            s = traceback.format_exc()
            print "thread init err", e, s
        while True:
            try:
                msg = client.recv(self.MAX_MSG_LEN)
                self.inQ.put(msg)
            except:
                e = sys.exc_info()[0]
                s = traceback.format_exc()
                print "listener err", e, s