Ejemplo n.º 1
0
 def __init__(self, machine: "MachineController", name: str) -> None:
     """Initialise spinner device."""
     super().__init__(machine, name)
     self._active = False
     self._idle = True
     self._active_ms = None
     self.hits = None
     self.delay = DelayManager(machine)
     self.enabled = True  # Default to enabled
Ejemplo n.º 2
0
    def __init__(self, machine: MachineController, name: str) -> None:
        """Initialise counter."""
        super().__init__(machine, name)
        self.debug_log("Creating Counter LogicBlock")

        self.delay = DelayManager(self.machine)

        self.ignore_hits = False
        self.hit_value = -1
Ejemplo n.º 3
0
    def test_zero_ms_delay(self):
        self.called = False
        self.delay = DelayManager(self.machine.delayRegistry)

        self.delay.add(ms=0,
                       name="first",
                       callback=self.delay_zero_ms,
                       start=self.machine.clock.get_time())
        self.advance_time_and_run(10)
Ejemplo n.º 4
0
    def __init__(self, machine: MachineController, name: str) -> None:
        """Initialise driver."""
        self.hw_driver = None   # type: DriverPlatformInterface
        super().__init__(machine, name)
        self.delay = DelayManager(self.machine.delayRegistry)

        self.time_last_changed = -1
        self.time_when_done = -1
        self.platform = None                # type: DriverPlatform
Ejemplo n.º 5
0
    def __init__(self, machine, name):
        """Initialise multiball."""
        self.ball_locks = None
        self.source_playfield = None
        super().__init__(machine, name)

        self.delay = DelayManager(machine)
        self.balls_added_live = 0
        self.balls_live_target = 0
        self.shoot_again = False
Ejemplo n.º 6
0
    def __init__(self, machine, name):
        """Initialise drop target."""
        self.reset_coil = None
        self.knockdown_coil = None
        self.banks = None
        super().__init__(machine, name)

        self._in_ball_search = False
        self.complete = False
        self.delay = DelayManager(machine.delayRegistry)
Ejemplo n.º 7
0
 def __init__(self, machine, name):
     """Initialise servo."""
     self.hw_servo = None
     self.platform = None  # type: ServoPlatform
     self._position = None
     self.speed_limit = None
     self.acceleration_limit = None
     self._ball_search_started = False
     self.delay = DelayManager(machine)
     super().__init__(machine, name)
Ejemplo n.º 8
0
    def __init__(self, machine, name):
        """Initialise ball save."""
        self.unlimited_saves = None
        self.source_playfield = None
        super().__init__(machine, name)

        self.delay = DelayManager(machine.delayRegistry)
        self.enabled = False
        self.timer_started = False
        self.saves_remaining = 0
Ejemplo n.º 9
0
    def __init__(self, machine, name):
        """Initialize Combo Switch."""
        super().__init__(machine, name)
        self.states = ['inactive', 'both', 'one']
        self._state = 'inactive'
        self._switches_1_active = False
        self._switches_2_active = False

        self.delay_registry = DelayManagerRegistry(self.machine)
        self.delay = DelayManager(self.delay_registry)
Ejemplo n.º 10
0
    def __init__(self, machine: "MachineController", config, name: str, path) -> None:
        """Initialise mode.

        Args:
            machine: the machine controller
            config: config dict for mode
            name: name of mode
            path: path of mode
        """
        super().__init__()
        self.machine = machine                  # type: MachineController
        self.config = config                    # type: ignore
        self.name = name
        self.path = path
        self.priority = 0
        self._active = False
        self._starting = False
        self._mode_start_wait_queue = None      # type: QueuedEvent
        self.stop_methods = list()              # type: List[Tuple[Callable[[Any], None], Any]]
        self.start_callback = None              # type: Callable[[], None]
        self.stop_callbacks = []                # type: List[Callable[[], None]]
        self.event_handlers = set()             # type: Set[EventHandlerKey]
        self.switch_handlers = list()           # type: List[SwitchHandler]
        self.mode_stop_kwargs = dict()          # type: Dict[str, Any]
        self.mode_devices = set()               # type: Set[ModeDevice]
        self.start_event_kwargs = None          # type: Dict[str, Any]
        self.stopping = False

        self.delay = DelayManager(self.machine)
        '''DelayManager instance for delays in this mode. Note that all delays
        scheduled here will be automatically canceled when the mode stops.'''

        self.player = None                      # type: Player
        '''Reference to the current player object.'''

        self.configure_logging('Mode.' + name,
                               self.config['mode']['console_log'],
                               self.config['mode']['file_log'])

        self.configure_mode_settings(config.get('mode', dict()))

        self.auto_stop_on_ball_end = self.config['mode']['stop_on_ball_end']
        '''Controls whether this mode is stopped when the ball ends,
        regardless of its stop_events settings.
        '''

        self.restart_on_next_ball = self.config['mode']['restart_on_next_ball']
        '''Controls whether this mode will restart on the next ball. This only
        works if the mode was running when the ball ended. It's tracked per-
        player in the 'restart_modes_on_next_ball' player variable.
        '''

        if self.config['mode']['game_mode'] and not self.config['mode']['stop_on_ball_end']:
            self.raise_config_error("All game modes need to stop at ball end. If you want to set stop_on_ball_end to "
                                    "False also set game_mode to False.", 1)
Ejemplo n.º 11
0
 def __init__(self, machine: "MachineController", name: str) -> None:
     """Initialise autofire."""
     self._enabled = False
     self._rule = None  # type: HardwareRule
     super().__init__(machine, name)
     self.delay = DelayManager(self.machine)
     self._ball_search_in_progress = False
     self._timeout_watch_time = None
     self._timeout_max_hits = None
     self._timeout_disable_time = None
     self._timeout_hits = []  # type: List[float]
Ejemplo n.º 12
0
    def test_event_in_delay(self):
        self.machine.events.add_handler('event1', self.event1_cb)
        self.machine.events.add_handler('event2', self.event2_cb)
        self.machine.events.add_handler('event3', self.event3_cb)
        self.correct = False
        self.delay = DelayManager(self.machine)

        self.machine.events.post("event1")
        self.advance_time_and_run(1)

        self.assertTrue(self.correct)
Ejemplo n.º 13
0
    def __init__(self, machine, name):
        """Initialise blinkenlight."""
        super().__init__(machine, name)

        self._colors = []
        self.delay = DelayManager(machine)
        self._color_duration = None
        self._cycle_duration = None
        self.num_colors = 0
        self._light_key = 'blinkenlight_{}'.format(
            self.name)  # cache the key as string operations as expensive
Ejemplo n.º 14
0
    def __init__(self, config, ball_device, machine):
        """Initialise ejector."""
        for option in ["eject_coil", "eject_coil_enable_time"]:
            if option not in config and option in ball_device.config:
                config[option] = ball_device.config[option]

        super().__init__(config, ball_device, machine)
        self.delay = DelayManager(self.ball_device.machine)

        self.config = self.machine.config_validator.validate_config(
            "ball_device_ejector_enable", self.config)
Ejemplo n.º 15
0
    def __init__(self, machine, name):
        """Initialise score reel."""
        super().__init__(machine, name)
        self.delay = DelayManager(machine.delayRegistry)

        self.rollover_reel_advanced = False
        # True when a rollover pulse has been ordered

        self.value_switches = []
        # This is a list with each element corresponding to a value on the
        # reel. An entry of None means there's no value switch there. An entry
        # of a reference to a switch object (todo or switch name?) means there
        # is a switch there.
        self.num_values = 0
        # The number of values on this wheel. This starts with zero, so a
        # wheel with 10 values will have this value set to 9. (This actually
        # makes sense since most (all?) score reels also have a zero value.)

        self.physical_value = -999
        # The physical confirmed value of this reel. This will always be the
        # value of whichever switch is active or -999. This differs from
        # `self.assumed_value` in that assumed value will make assumptions about
        # where the reel is as it pulses through values with no swithces,
        # whereas this physical value will always be -999 if there is no switch
        # telling it otherwise.

        # Note this value will be initialized via self.check_hw_switches()
        # below.

        self.hw_sync = False
        # Specifies whether this reel has verified it's positions via the
        # switches since it was last advanced."""

        self.ready = True
        # Whether this reel is ready to advance. Typically used to make sure
        # it's not trying to re-fire a stuck position.

        self.assumed_value = -999
        # The assumed value the machine thinks this reel is showing. A value
        # of -999 indicates that the value is unknown.

        self.next_pulse_time = 0
        # The time when this reel next wants to be pulsed. The reel will set
        # this on its own (based on its own attribute of how fast pulses can
        # happen). If the ScoreReelController is ready to pulse this reel and
        # the value is in the past, it will do a pulse. A value of 0 means this
        # reel does not currently need to be pulsed.

        self.rollover_reel = None
        # A reference to the ScoreReel object of the next higher reel in the
        # group. This is used so the reel can notify its neighbor that it needs
        # to advance too when this reel rolls over.

        self._destination_index = 0
Ejemplo n.º 16
0
    def __init__(self, machine, name):
        """Initialise drop target bank."""
        super().__init__(machine, name)

        self.drop_targets = list()
        self.reset_coil = None
        self.reset_coils = set()
        self.complete = False
        self.down = 0
        self.up = 0
        self.delay = DelayManager(machine.delayRegistry)
        self._ignore_switch_hits = False
Ejemplo n.º 17
0
    def __init__(self, machine: "MachineController", name: str) -> None:
        """Initialise drop target bank."""
        super().__init__(machine, name)

        self.drop_targets = list()  # type: List[DropTarget]
        self.reset_coil = None  # type: Driver
        self.reset_coils = set()  # type: Set[Driver]
        self.complete = False
        self.down = 0
        self.up = 0
        self.delay = DelayManager(machine.delayRegistry)
        self._ignore_switch_hits = False
Ejemplo n.º 18
0
    def __init__(self, machine: "MachineController", name: str) -> None:
        """Initialise drop target."""
        self.reset_coil = None  # type: Driver
        self.knockdown_coil = None  # type: Driver
        self.banks = None  # type: Set[DropTargetBank]
        super().__init__(machine, name)

        self._in_ball_search = False
        self.complete = False
        self.delay = DelayManager(machine.delayRegistry)

        self._ignore_switch_hits = False
Ejemplo n.º 19
0
    def __init__(self, ball_device, config):
        """Initialise entrance switch counter."""
        for option in ["entrance_switch", "entrance_switch_ignore_window_ms", "entrance_switch_full_timeout",
                       "ball_capacity"]:
            if option not in config and option in ball_device.config:
                config[option] = ball_device.config[option]
        super().__init__(ball_device, config)
        self._settle_delay = DelayManager(self.machine)

        self.config = self.machine.config_validator.validate_config("ball_device_counter_entrance_switches",
                                                                    self.config)

        self.recycle_secs = self.config['entrance_switch_ignore_window_ms'] / 1000.0
        self.recycle_clear_time = {}

        for switch in self.config['entrance_switch']:
            # Configure switch handlers for entrance switch activity
            self.machine.switch_controller.add_switch_handler_obj(
                switch=switch, state=1,
                ms=0,
                callback=self._entrance_switch_handler,
                callback_kwargs={"switch_name": switch.name})

            self.machine.switch_controller.add_switch_handler_obj(
                switch=switch, state=0,
                ms=0,
                callback=self._entrance_switch_released_handler,
                callback_kwargs={"switch_name": switch.name})

        if self.config['entrance_switch_full_timeout'] and self.config['ball_capacity']:
            if len(self.config['entrance_switch']) > 1:
                raise AssertionError("entrance_switch_full_timeout not supported with multiple entrance switches.")
            self.machine.switch_controller.add_switch_handler_obj(
                switch=self.config['entrance_switch'][0], state=1,
                ms=self.config['entrance_switch_full_timeout'],
                callback=self._entrance_switch_full_handler)

        # Handle initial ball count with entrance_switch. If there is a ball on the entrance_switch at boot
        # assume that we are at max capacity.
        if (self.config['ball_capacity'] and self.config['entrance_switch_full_timeout'] and
                self.machine.switch_controller.is_active(self.config['entrance_switch'][0],
                                                         ms=self.config['entrance_switch_full_timeout'])):
            self._last_count = self.config['ball_capacity']
        else:
            self._last_count = 0
        self._count_stable.set()

        # TODO validate that we are not used with mechanical eject
        if not self.config['ball_capacity']:
            self.ball_device.raise_config_error("Need ball capacity if there are no switches.", 2)
        elif self.ball_device.config.get('ball_switches'):
            self.ball_device.raise_config_error("Cannot use capacity and ball switches.", 3)
Ejemplo n.º 20
0
class EnableCoilEjector(PulseCoilEjector):
    """Enable a coil to eject one ball."""

    __slots__ = ["delay"]

    def __init__(self, config, ball_device, machine):
        """Initialise ejector."""
        super().__init__(config, ball_device, machine)
        self.delay = DelayManager(self.ball_device.machine.delayRegistry)

    def _validate_config(self):
        # overwrite validation from pulse_coil_ejector
        pass

    @asyncio.coroutine
    def eject_one_ball(self, is_jammed, eject_try):
        """Enable eject coil."""
        del is_jammed
        del eject_try

        # If multiple eject_coil_enable_time values, they correspond to the # of balls
        if self.ball_device.balls <= len(
                self.ball_device.config['eject_coil_enable_time']):
            eject_time = self.ball_device.config['eject_coil_enable_time'][
                self.ball_device.balls - 1]
        else:
            eject_time = self.ball_device.config['eject_coil_enable_time'][-1]

        # default pulse
        self.ball_device.debug_log(
            "Enabling eject coil for %sms, Current balls: %s.", eject_time,
            self.ball_device.balls)

        self.ball_device.config['eject_coil'].enable()
        self.delay.reset(name="disable",
                         callback=self._disable_coil,
                         ms=eject_time)

    def _disable_coil(self):
        """Disable the coil."""
        self.ball_device.config['eject_coil'].disable()

    def _fire_coil_for_search(self, full_power):
        if full_power and self.ball_device.config['eject_coil_jam_pulse']:
            self.ball_device.config['eject_coil'].pulse()
        else:
            self.ball_device.config['eject_coil'].enable()
            self.delay.reset(
                name="disable",
                callback=self._disable_coil,
                ms=self.ball_device.config['eject_coil_enable_time'][0])
        return True
Ejemplo n.º 21
0
    def __init__(self, machine, name):
        """Initialise diverter."""
        super().__init__(machine, name)

        self.delay = DelayManager(machine)

        # Attributes
        self.active = False
        self.enabled = False

        self.diverting_ejects_count = 0
        self.eject_state = False
        self.eject_attempt_queue = deque()
Ejemplo n.º 22
0
 def __init__(self, machine, name):
     """Initialise stepper."""
     self.hw_stepper = None  # type: Optional[StepperPlatformInterface]
     self.platform = None  # type: Optional[Stepper]
     self._target_position = 0  # in user units
     self._current_position = 0  # in user units
     self._ball_search_started = False
     self._ball_search_old_target = 0
     self._is_homed = False
     self._is_moving = asyncio.Event(loop=machine.clock.loop)
     self._move_task = None  # type: Optional[asyncio.Task]
     self.delay = DelayManager(machine)
     super().__init__(machine, name)
Ejemplo n.º 23
0
    def __init__(self, machine: "MachineController", name: str) -> None:
        """Initialise ball save."""
        self.unlimited_saves = None  # type: bool
        self.source_playfield = None  # type: Playfield
        super().__init__(machine, name)

        self.delay = DelayManager(machine.delayRegistry)
        self.enabled = False
        self.timer_started = False
        self.saves_remaining = 0
        self.early_saved = 0
        self.state = 'disabled'
        self._scheduled_balls = 0
Ejemplo n.º 24
0
    def __init__(self, machine, mode, name, config):
        """Initialise mode timer."""
        self.machine = machine
        self.mode = mode
        self.name = name
        self.config = config

        self.running = False
        self.start_value = self.config['start_value'].evaluate([])
        self.restart_on_complete = self.config['restart_on_complete']
        self._ticks = 0
        self.tick_var = '{}_{}_tick'.format(self.mode.name, self.name)

        try:
            self.end_value = self.config['end_value'].evaluate([])
        except AttributeError:
            self.end_value = None

        self.ticks_remaining = 0
        self.max_value = self.config['max_value']
        self.direction = self.config['direction'].lower()
        self.tick_secs = self.config['tick_interval'] / 1000.0
        self.timer = None
        self.event_keys = set()
        self.delay = DelayManager(self.machine.delayRegistry)

        if self.config['debug']:
            self.configure_logging('Timer.' + name, 'full', 'full')
        else:
            self.configure_logging('Timer.' + name, self.config['console_log'],
                                   self.config['file_log'])

        if self.direction == 'down' and not self.end_value:
            self.end_value = 0  # need it to be 0 not None

        self.ticks = self.start_value

        self.debug_log("----------- Initial Values -----------")
        self.debug_log("running: %s", self.running)
        self.debug_log("start_value: %s", self.start_value)
        self.debug_log("restart_on_complete: %s", self.restart_on_complete)
        self.debug_log("_ticks: %s", self.ticks)
        self.debug_log("end_value: %s", self.end_value)
        self.debug_log("ticks_remaining: %s", self.ticks_remaining)
        self.debug_log("max_value: %s", self.max_value)
        self.debug_log("direction: %s", self.direction)
        self.debug_log("tick_secs: %s", self.tick_secs)
        self.debug_log("--------------------------------------")

        if self.config['control_events']:
            self._setup_control_events(self.config['control_events'])
Ejemplo n.º 25
0
    def __init__(self, machine, name):
        """Initialise light."""
        self.hw_drivers = {}
        self.platforms = set()  # type: Set[LightsPlatform]
        super().__init__(machine, name)
        self.machine.light_controller.initialise_light_subsystem()
        self.delay = DelayManager(self.machine.delayRegistry)

        self.default_fade_ms = None

        self._color_correction_profile = None

        self.stack = list()
        """A list of dicts which represents different commands that have come
Ejemplo n.º 26
0
    def __init__(self, machine, config, name: str, path) -> None:
        """Initialise mode.

        Args:
            machine(mpf.core.machine.MachineController): the machine controller
            config: config dict for mode
            name: name of mode
            path: path of mode

        Returns:

        """
        super().__init__()
        self.machine = machine
        self.config = config                    # type: ignore
        self.name = name.lower()
        self.path = path
        self.priority = 0
        self._active = False
        self._mode_start_wait_queue = None      # type: QueuedEvent
        self.stop_methods = list()              # type: List[Tuple[Callable[[Any], None], Any]]
        self.start_callback = None              # type: Callable[[], None]
        self.stop_callbacks = []                # type: List[Callable[[], None]]
        self.event_handlers = set()             # type: Set[EventHandlerKey]
        self.switch_handlers = list()           # type: List[SwitchHandler]
        self.mode_stop_kwargs = dict()          # type: Dict[str, Any]
        self.mode_devices = set()               # type: Set[ModeDevice]
        self.start_event_kwargs = None          # type: Dict[str, Any]
        self.stopping = False

        self.delay = DelayManager(self.machine.delayRegistry)
        '''DelayManager instance for delays in this mode. Note that all delays
        scheduled here will be automatically canceled when the mode stops.'''

        self.player = None                      # type: Player
        '''Reference to the current player object.'''

        self.configure_logging('Mode.' + name,
                               self.config['mode']['console_log'],
                               self.config['mode']['file_log'])

        self.configure_mode_settings(config.get('mode', dict()))

        self.auto_stop_on_ball_end = self.config['mode']['stop_on_ball_end']
        '''Controls whether this mode is stopped when the ball ends,
        regardless of its stop_events settings.
        '''

        self.restart_on_next_ball = self.config['mode']['restart_on_next_ball']
        '''Controls whether this mode will restart on the next ball. This only
Ejemplo n.º 27
0
class EventPlayer(FlatConfigPlayer):
    """Posts events based on config."""

    config_file_section = 'event_player'
    show_section = 'events'

    __slots__ = ["delay"]

    def __init__(self, machine):
        """Initialise EventPlayer."""
        super().__init__(machine)
        self.delay = DelayManager(self.machine.delayRegistry)

    def play(self, settings, context, calling_context, priority=0, **kwargs):
        """Post (delayed) events."""
        for event, s in settings.items():
            s = deepcopy(s)
            event_dict = self.machine.placeholder_manager.parse_conditional_template(
                event)

            if event_dict['condition'] and not event_dict[
                    'condition'].evaluate(kwargs):
                continue

            if event_dict['number']:
                delay = Util.string_to_ms(event_dict['number'])
                self.delay.add(callback=self._post_event,
                               ms=delay,
                               event=event_dict['name'],
                               s=s)
            else:
                self._post_event(event_dict['name'], s)

    def _post_event(self, event, s):
        event_name_placeholder = TextTemplate(
            self.machine,
            event.replace("(", "{").replace(")", "}"))
        self.machine.events.post(event_name_placeholder.evaluate({}), **s)

    def get_list_config(self, value):
        """Parse list."""
        result = {}
        for event in value:
            result[event] = {}
        return result

    def get_express_config(self, value):
        """Parse short config."""
        return self.get_list_config(Util.string_to_list(value))
Ejemplo n.º 28
0
    def __init__(self, machine):
        """Initialise ball controller."""
        self.machine = machine
        self.log = logging.getLogger("BallController")
        self.log.debug("Loading the BallController")
        self.delay = DelayManager(self.machine.delayRegistry)

        self.num_balls_known = -999

        # register for events
        self.machine.events.add_handler('request_to_start_game',
                                        self.request_to_start_game)
        self.machine.events.add_handler('machine_reset_phase_2',
                                        self._initialize)
        self.machine.events.add_handler('init_phase_2', self._init2)
Ejemplo n.º 29
0
    def __init__(self, machine: "MachineController", name: str) -> None:
        """Initialise ball save."""
        self.ball_locks = None
        self.unlimited_saves = None  # type: Optional[bool]
        self.source_playfield = None  # type: Optional[Playfield]
        super().__init__(machine, name)

        self.delay = DelayManager(machine)
        self.enabled = False
        self.timer_started = False
        self.saves_remaining = 0
        self.early_saved = 0
        self.state = 'disabled'
        self._scheduled_balls = 0
        self.active_time = 0
Ejemplo n.º 30
0
    def __init__(self, machine, name):
        """Initialise ball device."""
        super().__init__(machine, name)

        self.delay = DelayManager(machine)

        self.available_balls = 0
        """Number of balls that are available to be ejected. This differs from
        `balls` since it's possible that this device could have balls that are
        being used for some other eject, and thus not available."""

        self._target_on_unexpected_ball = None
        # Device will eject to this target when it captures an unexpected ball

        self._source_devices = list()
        # Ball devices that have this device listed among their eject targets

        self._ball_requests = deque()
        # deque of tuples that holds requests from target devices for balls
        # that this device could fulfil
        # each tuple is (target device, boolean player_controlled flag)

        self.ejector = None  # type: BallDeviceEjector
        self.ball_count_handler = None  # type: BallCountHandler
        self.incoming_balls_handler = None  # type: IncomingBallsHandler
        self.outgoing_balls_handler = None  # type: OutgoingBallsHandler

        # mirrored from ball_count_handler to make it obserable by the monitor
        self.counted_balls = 0
        self._state = "idle"