OPP autofire_coils configured as AUTO_CLR (0x02)

119 views
Skip to first unread message

Lukas Mutter

unread,
Dec 1, 2017, 7:54:55 AM12/1/17
to MPF Users

Hi guys,

I finally got my machine running but when I start MPF, my autofire coils stop working.
At boot the are working (configuration on the cards themselves).

I found a line in my log saying that the coil is being configured as 0x02 0x30 0x00.

Shouldn't autofire coils run with 0x01 0x30 0x00 instead?

(0x01 == USE_SWITCH
 0x02 == AUTO_CLR)

Thanks for your help,
Lukas

Lukas Mutter

unread,
Dec 1, 2017, 8:35:29 AM12/1/17
to MPF Users
In the /mpf/platforms/opp/opp.py folder I found the following functions wich produce this configuration:

    def _write_hw_rule(self, switch_obj, driver_obj, use_hold):
        if switch_obj.invert:
            raise AssertionError("Cannot handle inverted switches")

        self._verify_coil_and_switch_fit(switch_obj, driver_obj)

        self.log.debug("Setting HW Rule. Driver: %s, Driver settings: %s",
                       driver_obj
.hw_driver.number, driver_obj.config)

        driver_obj
.hw_driver.use_switch = True
        driver_obj
.hw_driver.switches.append(switch_obj.hw_switch.number)
        _
, _, switch_num = switch_obj.hw_switch.number.split("-")
        switch_num = int(switch_num)
        self._add_switch_coil_mapping(switch_num, driver_obj.hw_driver)

        # Technically not necessary unless the solenoid parameters are
        # changing.  MPF may not know when initial kick and hold values
        # are changed, so this might need to be called each time.
       
self.reconfigure_driver(driver_obj, use_hold)


and:

    def reconfigure_driver(self, driver, use_hold: bool):
       
"""Reconfigure a driver.
        Args:
            driver: Driver object.
            use_hold: Whether this driver stays enabled after a trigger or not.
       
"""
        # If hold is 0, set the auto clear bit
        if not use_hold:
            cmd = ord(OppRs232Intf.CFG_SOL_AUTO_CLR)
            driver.hw_driver.can_be_pulsed = True
            hold = 0
       
else:
            cmd = 0
            driver.hw_driver.can_be_pulsed = False
            hold = self.get_hold_value(driver)
            if not hold:
                raise AssertionError("Hold may not be 0")
            if hold >= 16:
                if self.minVersion >= 0x00020000:
                    # set flag for full power, hold is not used
                    cmd += ord(OppRs232Intf.CFG_SOL_ON_OFF)
                    hold = 0
                else:
                    hold = 15

        minimum_off
= self.get_minimum_off_time(driver)

       
# Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        if (self.minVersion < 0x00020000) and driver.hw_driver.use_switch:
            cmd
+= ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

        _, solenoid = driver.config['number'].split('-')
        pulse_len = self._get_pulse_ms_value(driver)

        msg
= bytearray()
        msg.append(driver.hw_driver.solCard.addr)
        msg
.extend(OppRs232Intf.CFG_IND_SOL_CMD)
        msg.append(int(solenoid))
        msg.append(cmd)
        msg
.append(pulse_len)
        msg
.append(hold + (minimum_off << 4))
        msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
        msg
.extend(OppRs232Intf.EOM_CMD)
        final_cmd = bytes(msg)

       
self.log.debug("Writing individual config: %s", "".join(" 0x%02x" % b for b in final_cmd))
        self.send_to_processor(driver.hw_driver.solCard.chain_serial, final_cmd)

jabdoa

unread,
Dec 1, 2017, 12:21:26 PM12/1/17
to MPF Users
This was changed by Hugh and I think it is correct how we handle it. How does your config look? Did you start a game? MPF will by default only enable flippers etc during the game.


Jan

Lukas Mutter

unread,
Dec 2, 2017, 4:49:39 AM12/2/17
to MPF Users
Hi Jan,

I tested it without starting a game and everything was working.

Then I started MPF and the configuration of my coils got overwritten with the rule specified in MPF.
In a game my flippers are working but everything specified as autofire_coil is not.

I ran MPF with debugging for bumper_1 and I even tried to change the enable_event. My log says the following for that coil: 
2017-12-01 13:35:10,317 : autofire.bumper_1 : Enabling
2017-12-01 13:35:10,317 : OPP : Setting HW Rule. Driver: COM4-4-8, Driver settings: {'debug': True, 'hold_power': None, 'recycle_factor': None, 'pulse_events': {}, 'console_log': 'full', 'tags': [], 'hold_power16': None, 'pulse_ms': 32, 'platform': None, 'label': '%', 'number': '4-8', 'enable_events': {}, 'file_log': 'full', 'disable_events': {}, 'recycle': True, 'allow_enable': False, 'pulse_power': None}
2017-12-01 13:35:10,317 : OPP : Mapping input 16 and coil 8
2017-12-01 13:35:10,318 : OPP : Writing individual config:  0x24 0x14 0x08 0x02 0x20 0x20 0xa5 0xff


hardware_test.yaml
setup_board_5.py
2017-12-01-13-34-58-mpf-Pinball-PC.log

OPP

unread,
Dec 3, 2017, 8:07:48 AM12/3/17
to MPF Users
Uh oh.  It looks like that bit does need to be set.  Basically I messed up.  Looking at the firmware, it seems that that bit should also be set in addition to the auto_clear bit.  (I was confusing auto_fire and auto_clear).

OPP

unread,
Dec 3, 2017, 8:42:07 AM12/3/17
to MPF Users
OK.  Finally figured out where I messed up.  During initialization, what I did would work.  During reconfigurations it doesn't work, and it looks at both the bits for auto_firing and auto_clearing the bit.  (I was trying to insure the auto_clear bit was set to make sure a second MPF command didn't need to be sent to clear the bit.)  I wrongly cleared the auto_fire bit thinking it was inferred by having the auto_clear set.

OPP

unread,
Dec 4, 2017, 10:31:22 AM12/4/17
to MPF Users
I'm going to have to take my previous two comments back.  The current MPF code looks right at this point.  I forgot that there is a second command that ends up being sent to set the input.  That is so that daffy flippers and switch matrices can be supported.

Do you happen to know what version of OPP firmware you are running.  I think that it is >= 0.02.00.00 but I just want to make certain.  If so, there should be a second command that configures the switch input that should be sent by MPF which sets the correct input (the configure command is only setting pulse parameters).  It should be sent by MPF when the _add_switch_coil_mapping is called.  The command would then be something like 0x24 0x17 0x10 0x08.  That command says that the first solenoid on the third wing board uses the direct input (which is input 16).  I took a look at the yaml file, and it looks correct.  I believe that the _add_switch_coil_mapping should occur once the game starts and hardware is configured.

I did notice in your yaml file that pulse_power is set.  I've never used that parameter, and it seems to be changing the minimum off parameter in the configuration.  In the log file I see:
OPP : Writing individual config:  0x24 0x14 0x08 0x02 0x20 0x20 0xa5 0xff.
I would normally expect that command to be 0x24 0x14 0x08 0x02 0x20 0x00 ?? 0xff.  One interesting thing to try would be to remove those pulse_power statements in the yaml for the autofire solenoids.

Lukas Mutter

unread,
Dec 4, 2017, 11:31:38 AM12/4/17
to MPF Users
Hi Hugh (?)

I'm using Firmware version 0.2.0.5
Board 1/5:
Received Version Response: 0x20 0x02 0x00 0x02 0x00 0x05 0x9d

I realized that in my log it says:
2017-12-01 13:34:59,723 : OPP : Config driver COM4-4-8, 32, None
2017-12-01 13:34:59,723 : OPP : Writing individual config: 0x24 0x14 0x08 0x02 0x20 0x00 0x45 0xff
2017-12-01 13:34:59,739 : autofire.bumper_1 : Platform Driver: None


and later it says:
2017-12-01 13:35:10,317 : autofire.bumper_1 : Enabling
2017-12-01 13:35:10,317 : OPP : Setting HW Rule. Driver: COM4-4-8, Driver settings: {'debug': True, 'hold_power': None, 'recycle_factor': None,
 
'pulse_events': {}, 'console_log': 'full', 'tags': [], 'hold_power16': None, 'pulse_ms': 32, 'platform': None, 'label': '%', 'number': '4-8',
 
'enable_events': {}, 'file_log': 'full', 'disable_events': {}, 'recycle': True, 'allow_enable': False, 'pulse_power': None}
2017-12-01 13:35:10,317 : OPP : Mapping input 16 and coil 8
2017-12-01 13:35:10,318 : OPP : Writing individual config: 0x24 0x14 0x08 0x02 0x20 0x20 0xa5 0xff


Somehow the command gets changed as you mentioned above instead of actually "mapping input 16 and coil 8".
 
The pulse_power statement doesn't change anything and has been added for testing(in the log above it was not included)
And do you know what the line:
autofire.bumper_1 : Platform Driver: None

means?

jabdoa

unread,
Dec 4, 2017, 12:49:36 PM12/4/17
to MPF Users
That 0x20 is only the setting for recycle time and should be fine. Pulse_power is not implemented in OPP and pulse_power 8 means full power anyway.


Jan

OPP

unread,
Dec 4, 2017, 3:53:25 PM12/4/17
to MPF Users
I don't see the following in your yaml file:
autofire.bumper_1 : Platform Driver: None
I guess that I don't understand that question.

I see Mapping input 16 and coil 8 in the log file which should generate that command.  The problem might be that immediately after that command I see the 0x24 0x14 0x08 0x02 0x20 0x20 0xa5 0xff to reconfigure the coil.  That would immediately disable the default switch input.

One way to test if that is the issue is to change the switch input for the pop bumper to a different input.  In the yaml file, try:
    bumper_1:
        coil: c_bumper_1
        switch: s_bumper_2

That changes pop bumper 1 from the default configuration to use the switch for pop bumper 2.  That will would not be cleared with the resending of the config command for pop bumper 1 solenoid.  If that works, it is the fact that it does a reconfiguration, that it immediately overwrites the switch configuration.
-Hugh

jabdoa

unread,
Dec 4, 2017, 5:37:03 PM12/4/17
to MPF Users
Will it clear the default switch every time we reconfigure it?


Jan

OPP

unread,
Dec 4, 2017, 7:25:44 PM12/4/17
to MPF Users
Yes it will.  I did that on purpose to make sure that it cleared out the default switch configuration on startup.  I was worried about starting the pinball machine and not clearing those default hardware switch inputs.  If that happens, you get the strange situation when the machine first starts and the default switches are active because the disable switches commands aren't sent until the first game is over.

Is there a way to hold off the reconfiguration command if none of the parameters are changing?  If simply changing the switch input, or even enable/disabling a solenoid switch, there is no reason with the OPP hardware to send the config command.  (Disabling a solenoid can be done by removing the switch input).  Configurations should only be sent at initialization, or when trying to change the strength of the flippers/slings/bumpers during a game.  (i.e. in SS3 I change the strength of the bumpers during certain modes to simulate a bar fight and to really kick the ball around a lot.)

Lukas Mutter

unread,
Dec 5, 2017, 3:34:29 AM12/5/17
to MPF Users
Changing the switch input for the autofire_coil works. But now a different bumper is firing.
Is there a workaround to solve this via software or should I simply switch the wires for all autofire coils. That way should work.

Thank you so much for your help guys

OPP

unread,
Dec 5, 2017, 7:20:19 AM12/5/17
to MPF Users
No, that was just me trying to guess the root cause without being able to see your machine.  The issue lays in the fact that I made some assumptions about how MPF works, and they are not 100% true.  So for the short term, the following might work for you...  In the the MPF code in mpf/mpf/platforms/opp/opp.py, you will see the following lines:


        # Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        if (self.minVersion < 0x00020000) and driver.hw_driver.use_switch:
            cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

Change those lines to:


        # Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        if driver.hw_driver.use_switch:
            cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

Basically remove the test for the minVersion < 0x00020000.  That will once again set the USE_SWITCH bit during the configuration.  The reason that the change can't be the final change is that it would not allow daffy flippers to work.  (With daffy flippers the left flipper button activates the right flipper and vice-versa).  I'm hoping to try and figure out the correct fix with Jan so that there are no restrictions.

Oh yeah, don't forget to change the yaml code back to the original file.
-Hugh

jabdoa

unread,
Dec 5, 2017, 9:07:27 AM12/5/17
to MPF Users
I quickly looked over the code this morning. I guess that this will work in 0.50/dev but more coincidently. In 0.50 we first reconfigure and then add the mapping. In 0.33 it is the other way around (hence the issue).

So just to recap for me:
- When we reconfigure a coil without OppRs232Intf.CFG_SOL_USE_SWITCH it will remove the default mapping. Question: Only the default mapping or all mappings?
If yes (default mapping removed every time): I propose we set OppRs232Intf.CFG_SOL_USE_SWITCH in case we want to map the default switch (and not add any mapping)
If no (all mappings removed every time): I propose that we readd the mappings after each reconfigure. 

Jan

OPP

unread,
Dec 5, 2017, 10:51:03 AM12/5/17
to MPF Users
Yes, only the default mapping is removed.  All other switch inputs for the solenoid are untouched.

Could the fix be as simple as the following (original code):

    def _write_hw_rule(self, switch_obj, driver_obj, use_hold):
        if switch_obj.invert:
            raise AssertionError("Cannot handle inverted switches")

        self._verify_coil_and_switch_fit(switch_obj, driver_obj)

        self.log.debug("Setting HW Rule. Driver: %s, Driver settings: %s",
                       driver_obj.hw_driver.number, driver_obj.config)

        driver_obj.hw_driver.use_switch = True
        driver_obj.hw_driver.switches.append(switch_obj.hw_switch.number)
        _, _, switch_num = switch_obj.hw_switch.number.split("-")
        switch_num = int(switch_num)
        self._add_switch_coil_mapping(switch_num, driver_obj.hw_driver)

        # Technically not necessary unless the solenoid parameters are
        # changing.  MPF may not know when initial kick and hold values
        # are changed, so this might need to be called each time.
        self.reconfigure_driver(driver_obj, use_hold)


New code:

    def _write_hw_rule(self, switch_obj, driver_obj, use_hold):
        if switch_obj.invert:
            raise AssertionError("Cannot handle inverted switches")

        self._verify_coil_and_switch_fit(switch_obj, driver_obj)

        self.log.debug("Setting HW Rule. Driver: %s, Driver settings: %s",
                       driver_obj.hw_driver.number, driver_obj.config)

        # Technically not necessary unless the solenoid parameters are
        # changing.  MPF may not know when initial kick and hold values
        # are changed, so this might need to be called each time.
        self.reconfigure_driver(driver_obj, use_hold)

        driver_obj.hw_driver.use_switch = True
        driver_obj.hw_driver.switches.append(switch_obj.hw_switch.number)
        _, _, switch_num = switch_obj.hw_switch.number.split("-")
        switch_num = int(switch_num)
        self._add_switch_coil_mapping(switch_num, driver_obj.hw_driver)

The reconfigure_driver is moved before the _add_switch_coil_mapping.  That should order the commands properly.  At some point, it would be nice to not send the extra reconfig command since 99.99% of the time the configuration of a solenoid is not changing, so the call to reconfigure_driver is actually unnecessary.  Other change that I would toss in is change the following code:

    def get_minimum_off_time(cls, coil):
        """Return minimum off factor.

        The hardware applies this factor to pulse_ms to prevent the coil from burning.
        """
        if not coil.config['recycle']:
            return 0
        elif coil.config['recycle_factor']:
            if coil.config['recycle_factor'] > 7:
                raise AssertionError("Maximum recycle_factor allowed is 7")
            return coil.config['recycle_factor']
        else:
            # default to two times pulse_ms
            return 2

To this:
    def get_minimum_off_time(cls, coil):
        """Return minimum off factor.

        The hardware applies this factor to pulse_ms to prevent the coil from burning.
        """
        if not coil.config['recycle']:
            return 0
        elif coil.config['recycle_factor']:
            if coil.config['recycle_factor'] > 7:
                raise AssertionError("Maximum recycle_factor allowed is 7")
            return coil.config['recycle_factor']
        else:
            # default to 0
            return 0

I always default the minimum off times to zero.  If the user has an issue, they could set recycle_factor to change it from the default.  The OPP hardware makes sure that a switch off state is seen before it will refire the solenoid.  That insures that a switch that is always closed will not cause shot gunning of the solenoid.
-Hugh

jabdoa

unread,
Dec 5, 2017, 11:03:31 AM12/5/17
to MPF Users
MPF only reconfigures if a parameter changes (e.g. recycle factor in this case). The change above is not enough because MPF might also reconfigure the coil for other reasons (such as pulsing or enabling the coil). Recycle factor of 2 is the default in case you set recycle to true (which afaik is the default for pop bumpers and slings).


Jan

OPP

unread,
Dec 5, 2017, 12:26:01 PM12/5/17
to MPF Users
So another option which is a little more difficult to implement would be to test if the switch is set as the default switch and if that is the case set the CFG_SOL_USE_SWITCH flag.

In reconfigure_driver, starting at the long comment:

Original code:

        # Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        if (self.minVersion < 0x00020000) and driver.hw_driver.use_switch:
            cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

        _, solenoid = driver.config['number'].split('-')
        pulse_len = self._get_pulse_ms_value(driver)

New version of code:

        # Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        # after the reconfig. 
        _, solenoid = driver.config['number'].split('-')
        if (self.minVersion < 0x00020000) and driver.hw_driver.use_switch:
            cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)
        elif (self.minVersion >= 0x00020000):
            # If driver is using matching switch set CFG_SOL_USE_SWITCH
            # in case config happens after set switch command
            matching_sw = ((int(solenoid) & 0x0c) << 1) | (int(solenoid) & 0x03)
            if matching_sw in driver_obj.hw_driver.switches:
                cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

        pulse_len = self._get_pulse_ms_value(driver)

Basically I'm checking if the matching hardware switch is set, and if so, set the cmd bit.  The should fix any issue with ordering of the commands to the OPP hardware.

jabdoa

unread,
Dec 6, 2017, 6:11:11 AM12/6/17
to MPF Users
Yeah I like that. Will add that tonight.

Jan

jabdoa

unread,
Dec 6, 2017, 2:54:24 PM12/6/17
to MPF Users
Please give 0.33.43 a try. It includes the fix from Hugh. Thanks Hugh!


Jan

Lukas Mutter

unread,
Dec 8, 2017, 5:12:04 AM12/8/17
to MPF Users
Thank you for your help guys

Unfortunately this is not working for me.
I now just changed my switch wires to allow MPF to fully reconfigure and remap all the settings.
This way on boot the switch of my left sling enables the right sling...
When I run MPF everything gets reconfigured and works as expected
At least I can play now.

Lukas

Lukas Mutter

unread,
Dec 8, 2017, 5:13:57 AM12/8/17
to MPF Users
If you want I can switch back for further testing 

jabdoa

unread,
Dec 8, 2017, 7:42:29 AM12/8/17
to MPF Users
Hi Lukas,

I just tested this. The previous fix did not work properly. It is now tested and should work as expected. Released in 0.33.45.


Jan
Reply all
Reply to author
Forward
0 new messages