Beispiel #1
0
class RosDaemon():
    '''
        Monitors a toggle switch connected to a GPIO pin, mirroring its state
        on an LED (likewise connected to a GPIO pin).

        This state is used to enable or disable the ROS. This replaces rather
        than reuses the Status class (as a reliable simplification).
    '''
    def __init__(self, config, gpio, level):
        self._log = Logger("rosd", level)
        self._log.warning('initialising rosd...')
        self._gpio = gpio
        self._gpio.setmode(GPIO.BCM)
        self._gpio.setwarnings(False)
        if config is None:
            raise ValueError('no configuration provided.')
        self._log.info('configuration provided.')
        self._config = config['rosd']
        self._switch_pin  = self._config.get('switch_pin') # default 14
        self._led_pin     = self._config.get('led_pin')    # default 27
        self._application = self._config.get('application') # 'ros' | 'gamepad'
        self._log.info('initialising with switch on pin {} and LED on pin {}.'.format(self._switch_pin, self._led_pin))
        self._gpio.setup(self._switch_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        self._gpio.setup(self._led_pin, GPIO.OUT, initial=GPIO.LOW)
        self._counter = itertools.count()
        self._old_state  = False
        self._ros        = None
        self._gamepad    = None
        self._loop_count = 0
        self._thread_timeout_delay_sec = 1
        _rosd_mask = os.umask(0)
        os.umask(_rosd_mask)
        self._log.info('mask: {}'.format(_rosd_mask))
        self._log.info('uid:  {}'.format(os.getuid()))
        self._log.info('gid:  {}'.format(os.getgid()))
        self._log.info('cwd:  {}'.format(os.getcwd()))
        self._log.info('pid file: {}'.format(PIDFILE))
        self._log.info('rosd ready.')

    # ..........................................................................
    def _get_timestamp(self):
        return datetime.utcfromtimestamp(datetime.utcnow().timestamp()).isoformat()

    # ..........................................................................
    def read_state(self):
        '''
            Reads the state of the toggle switch, sets the LED accordingly,
            then returns the value. This only calls enable() or disable()
            if the value has changed since last reading.
        '''
        self._state = not GPIO.input(self._switch_pin)
        self._loop_count = next(self._counter)
        if self._loop_count % 10 == 0:
            self._log.info('[{}] ros daemon waiting...'.format(self._loop_count))
        if self._state is not self._old_state: # if low
            if self._state:
                self._log.info('enabling from state: {}'.format(self._state))
                self.enable()
            else:
                self._log.info('disabling from state: {}'.format(self._state))
                self.disable()
        self._old_state = self._state
        return self._state

    # ..........................................................................
    def enable(self):
        if self._application == 'ros':
            self._enable_ros()
        elif self._application == 'gamepad':
            self._enable_gamepad()
        else:
            raise Exception('unrecognised application: "{}"'.format(self._application))

    # ..........................................................................
    def disable(self):
        if self._application == 'ros':
            self._disable_ros()
        elif self._application == 'gamepad':
            self._disable_gamepad()
        else:
            raise Exception('unrecognised application: "{}"'.format(self._application))

    def _set_status_led(self, enable):
        if enable:
            self._gpio.output(self._led_pin, True)
        else:
            self._gpio.output(self._led_pin, False)

    # ..........................................................................
    def _enable_ros(self):
        self._log.info('ros state enabled at: {}'.format(self._get_timestamp()))
        if self._ros is None:
            self._log.info('starting ros thread...')
            self._ros = ROS()
            self._ros._log.set_mutex(self._log.get_mutex())
            self._ros.start()
            self._log.info('ros started.')
            time.sleep(1.0)
            if self._ros.has_connected_gamepad():
                self._log.info('gamepad is available and connected.')
            else:
                self._log.warning('no connected gamepad.')
        else:
            self._log.info('enabling ros arbitrator...')
            _arbitrator = self._ros.get_arbitrator()
            _arbitrator.set_suppressed(False)
        self._set_status_led(True)

    # ..........................................................................
    def _disable_ros(self):
        self._log.info('ros state disabled at: {}'.format(self._get_timestamp()))
        if self._ros is not None:
            self._log.info('suppressing ros arbitrator... ')
            _arbitrator = self._ros.get_arbitrator()
            _arbitrator.set_suppressed(True)
            self._log.info('ros arbitrator suppressed.')
        self._set_status_led(False)
        # TODO make it flash instead

    # ..........................................................................
    def _enable_gamepad(self):
        if self._gamepad is None:
            self._log.info('instantiating gamepad...')
            self._gamepad = GamepadDemo(Level.INFO)
        self._gamepad.enable()
        self._set_status_led(True)
        self._log.info('gamepad enabled at: {}'.format(self._get_timestamp()))

    # ..........................................................................
    def _disable_gamepad(self):
        if self._gamepad is not None:
            self._gamepad.disable()
        self._set_status_led(False)
        self._log.info('gamepad disabled at: {}'.format(self._get_timestamp()))

    # ..........................................................................
    def close(self):
        self._log.info('closing rosd...')
        if self._ros is not None:
            self._log.info('closing ros...')
            self._ros.close()
            self._log.info('ros closed.')
        else:
            self._log.warning('ros thread was null.')
        self._set_status_led(False)
        self._log.info('rosd closed.')