Exemplo n.º 1
0
Arquivo: p3_roc.py Projeto: jherrm/mpf
    def write_hw_rule(
        self,
        sw,
        sw_activity,
        coil_action_ms,  # 0 = disable, -1 = hold forever
        coil=None,
        pulse_ms=0,
        pwm_on=0,
        pwm_off=0,
        delay=0,
        recycle_time=0,
        debounced=True,
        drive_now=False,
    ):

        """Used to write (or update) a hardware rule to the P3-ROC.

        *Hardware Rules* are used to configure the P3-ROC to automatically
        change driver states based on switch changes. These rules are
        completely handled by the P3-ROC hardware (i.e. with no interaction from
        the Python game code). They're used for things that you want to happen
        fast, like firing coils when flipper buttons are pushed, slingshots,
        pop bumpers, etc.

        You can overwrite existing hardware rules at any time to change or
        remove them.

        Args:
            sw : switch object
                Which switch you're creating this rule for. The parameter is a
                reference to the switch object itsef.
            sw_activity : int
                Do you want this coil to fire when the switch becomes active
                (1) or inactive (0)
            coil_action_ms : int
                The total time (in ms) that this coil action should take place.
                A value of -1 means it's forever.
            coil : coil object
                Which coil is this rule controlling
            pulse_ms : int
                How long should the coil be pulsed (ms)
            pwm_on : int
                If the coil should be held on at less than 100% duty cycle,
                this is the "on" time (in ms).
            pwm_off : int
                If the coil should be held on at less than 100% duty cycle,
                this is the "off" time (in ms).
            delay : int
                Not currently implemented for the P3-ROC hardware
            recycle_time : int
                How long (in ms) should this switch rule wait before firing
                again. Put another way, what's the "fastest" this rule can
                fire? This is used to prevent "machine gunning" of slingshots
                and pop bumpers. Do not use it with flippers. Note the P3-ROC
                has a non-configurable delay time of 125ms. (So it's either
                125ms or 0.) So if you set this delay to anything other than
                0, it will be 125ms.
            debounced : bool
                Should the P3-ROC fire this coil after the switch has been
                debounced? Typically no.
            drive_now : bool
                Should the P3-ROC check the state of the switches when this
                rule is firts applied, and fire the coils if they should be?
                Typically this is True, especially with flippers because you
                want them to fire if the player is holding in the buttons when
                the machine enables the flippers (which is done via several
                calls to this method.)

        """

        self.log.debug(
            "Setting HW Rule. Switch:%s, Action ms:%s, Coil:%s, "
            "Pulse:%s, pwm_on:%s, pwm_off:%s, Delay:%s, Recycle:%s,"
            "Debounced:%s, Now:%s",
            sw.name,
            coil_action_ms,
            coil.name,
            pulse_ms,
            pwm_on,
            pwm_off,
            delay,
            recycle_time,
            debounced,
            drive_now,
        )

        if sw_activity == 0 and debounced:
            event_type = "open_debounced"
        elif sw_activity == 0 and not debounced:
            event_type = "open_nondebounced"
        elif sw_activity == 1 and debounced:
            event_type = "closed_debounced"
        else:  # if sw_activity == 1 and not debounced:
            event_type = "closed_nondebounced"

        # Note the P3-ROC uses a 125ms non-configurable recycle time. So any
        # non-zero value passed here will enable the 125ms recycle.

        reload_active = False
        if recycle_time:
            reload_active = True

        # We only want to notify_host for debounced switch events. We use non-
        # debounced for hw_rules since they're faster, but we don't want to
        # notify the host on them since the host would then get two events
        # one for the nondebounced followed by one for the debounced.

        notify_host = False
        if debounced:
            notify_host = True

        rule = {"notifyHost": notify_host, "reloadActive": reload_active}

        # Now let's figure out what type of P3-ROC action we need to take.
        # We're going to 'brtue force' this here because it's the easiest to
        # understand. (Which makes it the most pythonic, right? :)

        proc_action = "disable"

        patter = False  # makes it easier to understand later...
        if pwm_on and pwm_off:
            patter = True

        if coil_action_ms == -1:  # hold coil forever
            if patter:
                proc_action = "patter"
            else:
                proc_action = "enable"
        elif coil_action_ms > 0:  # timed action of some sort
            if coil_action_ms <= pulse_ms:
                proc_action = "pulse"
                pulse_ms = coil_action_ms
            elif patter:
                if pulse_ms:
                    pass
                    # todo error, P3-ROC can't do timed patter with pulse
                else:  # no initial pulse
                    proc_action = "pulsed_patter"

        this_driver = []
        final_driver = []

        # The P3-ROC ties hardware rules to switches, with a list of linked
        # drivers that should change state based on a switch activity.
        # Since our framework applies the rules one-at-a-time, we have to read
        # the existing linked drivers from the hardware for that switch, add
        # our new driver to the list, then re-update the rule on the hardware.

        if proc_action == "pulse":
            this_driver = [pinproc.driver_state_pulse(coil.hw_driver.state(), pulse_ms)]

        elif proc_action == "patter":
            this_driver = [pinproc.driver_state_patter(coil.hw_driver.state(), pwm_on, pwm_off, pulse_ms, True)]
            # todo above param True should not be there. Change to now?

        elif proc_action == "enable":
            this_driver = [pinproc.driver_state_pulse(coil.hw_driver.state(), 0)]

        elif proc_action == "disable":
            this_driver = [pinproc.driver_state_disable(coil.hw_driver.state())]

        elif proc_action == "pulsed_patter":
            this_driver = [pinproc.driver_state_pulsed_patter(coil.hw_driver.state(), pwm_on, pwm_off, coil_action_ms)]

        # merge in any previously-configured driver rules for this switch

        final_driver = list(this_driver)  # need to make an actual copy
        sw_rule_string = str(sw.name) + str(event_type)
        if sw_rule_string in self.hw_switch_rules:
            for driver in self.hw_switch_rules[sw_rule_string]:
                final_driver.append(driver)
            self.hw_switch_rules[sw_rule_string].extend(this_driver)
        else:
            self.hw_switch_rules[sw_rule_string] = this_driver

        self.log.debug(
            "Writing HW rule for switch: %s, event_type: %s," "rule: %s, final_driver: %s, drive now: %s",
            sw.number,
            event_type,
            rule,
            final_driver,
            drive_now,
        )
        self.proc.switch_update_rule(sw.number, event_type, rule, final_driver, drive_now)