예제 #1
0
    def evaluate_and_subscribe_template(self, template, parameters, text=None):
        """Evaluate and subscribe template."""
        if self.machine.stop_future.done():
            # return a canceled future if machine is already stopping
            future = asyncio.Future()
            future.cancel()
            return None, future

        try:
            value, subscriptions = self._eval(template, parameters, True)
        except TemplateEvalError as e:
            value = e
            subscriptions = e.subscriptions
        except ConfigFileError:  # pylint: disable-msg=try-except-raise
            raise
        except ValueError as e:
            raise AssertionError(
                "Failed to evaluate and subscribe template {} with parameters {}. "
                "See error above.".format(text, parameters)) from e

        if not subscriptions:
            future = self.machine.wait_for_stop()
        else:
            subscriptions.append(self.machine.wait_for_stop())
            future = Util.any(subscriptions)
        future = asyncio.ensure_future(future)
        return value, future
예제 #2
0
    def track_eject(self, eject_tracker: EjectTracker, already_left):
        """Remove one ball from count."""
        ball_left = self._wait_for_ball_to_leave(
        ) if not already_left else None
        ball_activity = self.wait_for_ball_activity()
        # we are stable from here on
        eject_tracker.set_ready()
        count = self._entrance_count
        while True:
            if ball_left:
                futures = [ball_activity, ball_left]
            else:
                futures = [ball_activity]

            yield from Util.any(futures, loop=self.machine.clock.loop)

            if ball_left and ball_left.done():
                ball_left = False
                eject_tracker.track_ball_left()
                self.debug_log(
                    "Device ejected a ball. Reducing ball count by one.")
                self._entrance_count -= 1
                count -= 1
                if self._entrance_count < 0:
                    self._entrance_count = 0
                    self.ball_device.log.warning("Entrance count went below 0")

            if ball_activity.done() and self._entrance_count > count:
                for _ in range(self._entrance_count - count):
                    yield from eject_tracker.track_ball_entrance()

                count = self._entrance_count
                ball_activity = self.wait_for_ball_activity()
예제 #3
0
    def _eject_ball(self, eject_request: OutgoingBall, eject_try: int) -> Generator[int, None, bool]:
        # inform the counter that we are ejecting now
        self.info_log("Ejecting ball to %s", eject_request.target)
        yield from self._post_ejecting_event(eject_request, eject_try)
        ball_eject_process = yield from self.ball_device.ball_count_handler.start_eject()
        try:
            yield from ball_eject_process.will_eject()
            self.debug_log("Wait for ball to leave device")
            # eject the ball

            ball_left = ball_eject_process.wait_for_ball_left()
            waiters = [ball_left]
            trigger = None
            tilt = None
            if self.ball_device.ejector:
                # eject on tilt
                if eject_request.mechanical:
                    tilt = self.machine.events.wait_for_event("tilt")
                    waiters.append(tilt)

                # wait for trigger event
                if eject_request.mechanical and self.ball_device.config['player_controlled_eject_event']:
                    trigger = self.machine.events.wait_for_event(
                        self.ball_device.config['player_controlled_eject_event'])
                    waiters.append(trigger)
                elif eject_request.mechanical and self.ball_device.config['mechanical_eject']:
                    # do nothing
                    pass
                else:
                    yield from self.ball_device.ejector.eject_one_ball(ball_eject_process.is_jammed(), eject_try)

            # wait until the ball has left
            if (self.ball_device.config['mechanical_eject'] or
                    self.ball_device.config['player_controlled_eject_event']) and eject_request.mechanical:
                timeout = None
            else:
                timeout = eject_request.eject_timeout
            try:
                yield from Util.any(waiters, timeout=timeout, loop=self.machine.clock.loop)
            except asyncio.TimeoutError:
                # timeout. ball did not leave. failed
                yield from self.ball_device.ball_count_handler.end_eject(ball_eject_process, False)
                return False

            if (trigger and trigger.done()) or (tilt and tilt.done()):
                yield from self.ball_device.ejector.eject_one_ball(ball_eject_process.is_jammed(), eject_try)
                # TODO: add timeout here
                yield from ball_left

            self.ball_device.set_eject_state("ball_left")
            self.debug_log("Ball left")
            incoming_ball_at_target = self._add_incoming_ball_to_target(eject_request.target)
            result = yield from self._handle_confirm(eject_request, ball_eject_process, incoming_ball_at_target,
                                                     eject_try)
            yield from self.ball_device.ball_count_handler.end_eject(ball_eject_process, result)
            return result
        except asyncio.CancelledError:
            ball_eject_process.cancel()
            raise
예제 #4
0
    def track_eject(self, eject_tracker: EjectTracker, already_left):
        """Return eject_process dict."""
        # count active switches
        while True:
            waiter = self.wait_for_ball_activity()
            try:
                active_switches = self._count_switches_sync()
                waiter.cancel()
                break
            except ValueError:
                yield from waiter

        ball_left_future = Util.ensure_future(
            self._wait_for_ball_to_leave(active_switches),
            loop=self.machine.clock.loop) if not already_left else None

        # all switches are stable. we are ready now
        eject_tracker.set_ready()

        jam_active_before_eject = self.is_jammed()
        jam_active_after_eject = False
        active_switches = active_switches
        count = len(active_switches)
        while True:
            ball_count_change = Util.ensure_future(
                self.wait_for_ball_count_changes(count),
                loop=self.machine.clock.loop)
            if ball_left_future:
                futures = [ball_count_change, ball_left_future]
            else:
                futures = [ball_count_change]
            yield from Util.any(futures, loop=self.machine.clock.loop)

            if ball_left_future and ball_left_future.done():
                ball_left_future = None
                eject_tracker.track_ball_left()
                count -= 1
                ball_count_change.cancel()
            elif ball_count_change.done():
                new_count = ball_count_change.result()
                # check jam first
                if not jam_active_after_eject and not jam_active_before_eject and self.is_jammed(
                ):
                    eject_tracker.track_ball_returned()
                    jam_active_after_eject = True
                    count += 1
                if new_count > count:
                    # TODO: add some magic to detect entrances
                    pass
                if new_count > count:
                    eject_tracker.track_unknown_balls(new_count - count)
                elif count > new_count:
                    eject_tracker.track_lost_balls(count - new_count)
                count = new_count
예제 #5
0
 def evaluate_and_subscribe(self, parameters) -> Tuple[str, asyncio.Future]:
     """Evaluate placeholder to string and subscribe to changes."""
     f = MpfFormatter(self.machine, parameters, True)
     value = f.format(self.text)
     subscriptions = f.subscriptions
     if not subscriptions:
         future = asyncio.Future()  # type: asyncio.Future
     elif len(subscriptions) == 1:
         future = subscriptions[0]
     else:
         future = Util.any(subscriptions)
     future = asyncio.ensure_future(future)
     return value, future
예제 #6
0
    def evaluate_and_subscribe_template(self, template, parameters):
        """Evaluate and subscribe template."""
        try:
            value, subscriptions = self._eval(template, parameters, True)
        except TemplateEvalError as e:
            value = e
            subscriptions = e.subscriptions

        if not subscriptions:
            future = asyncio.Future(loop=self.machine.clock.loop)
        elif len(subscriptions) == 1:
            future = subscriptions[0]
        else:
            future = Util.any(subscriptions, loop=self.machine.clock.loop)
        future = Util.ensure_future(future, loop=self.machine.clock.loop)
        return value, future
예제 #7
0
    def evaluate_and_subscribe_template(self, template, parameters, text=None):
        """Evaluate and subscribe template."""
        try:
            value, subscriptions = self._eval(template, parameters, True)
        except TemplateEvalError as e:
            value = e
            subscriptions = e.subscriptions
        except ValueError as e:
            raise AssertionError("Failed to evaluate and subscribe template {} with parameters {}. "
                                 "See error above.".format(text, parameters)) from e

        if not subscriptions:
            future = asyncio.Future()
        elif len(subscriptions) == 1:
            future = subscriptions[0]
        else:
            future = Util.any(subscriptions)
        future = asyncio.ensure_future(future)
        return value, future