-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
System11 AC Relay Improvements #1628
System11 AC Relay Improvements #1628
Conversation
Kudos, SonarCloud Quality Gate passed!
|
@@ -44,6 +45,7 @@ def __init__(self, machine: MachineController) -> None: | |||
|
|||
self.a_side_done_time = 0 | |||
self.c_side_done_time = 0 | |||
self.debounce_secs = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A number of other values are always pulled by lookup (e.g. self.system11_config['ac_relay_delay_ms']
), but the debounce time is used every tick during a switchover and I thought it'd be nice to spare all those lookups with a stored value.
"""Return if A side cannot be switches off right away.""" | ||
return self.drivers_holding_a_side or self.a_side_done_time > self.machine.clock.get_time() or self.a_side_queue | ||
"""Return if A side cannot be switched off right away.""" | ||
return self.a_side_active or self.a_side_queue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block (and the C side) originally duplicated the check in both a_side_active
and a_side_busy
, so I cleaned the latter up to just check the former.
@@ -310,9 +332,6 @@ def _enable_a_side(self): | |||
if self.c_side_active: | |||
self._disable_all_c_side_drivers() | |||
self._disable_ac_relay() | |||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This delay call seems redundant to me, because self._disable_ac_relay()
also creates a delay for ac_relay_delay_ms
that uses self._a_side_enabled
as a callback.
This block here uses the same delay to call self._enable_a_side
, which would also call self._a_side_enabled
. I've noticed no issues removing the redundant call, but please let me know if I'm overlooking something.
@@ -510,4 +536,4 @@ def disable(self): | |||
|
|||
def timed_enable(self, pulse_settings: PulseSettings, hold_settings: HoldSettings): | |||
"""Pulse and enable the coil for an explicit duration.""" | |||
self.overlay.driver_action(self.platform.driver, pulse_settings, hold_settings, self.side) | |||
self.overlay.driver_action(self.platform_driver, pulse_settings, hold_settings, self.side, True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This self.platform.driver
instead of self.platform_driver
is a mistake on my part from the last PR!
@@ -52,10 +52,10 @@ def test_ac_switch_and_pulse(self): | |||
c_ac_relay.enable = MagicMock() | |||
c_ac_relay.disable = MagicMock() | |||
|
|||
driver_11.pulse = MagicMock() | |||
driver_11.pulse = MagicMock(return_value=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that the code path uses the wait_ms
response from pulse()
to calculate switchover delays, need to ensure that a value is returned.
This PR adds some improvements and fixes some logical gaps in the System11 AC Relay behavior.
New Features
New config option
ac_relay_debounce_ms
The AC Relay configuration already has an option
ac_relay_delay_ms
, which is the desired delay between changing the relay state and pulsing the coils. However there is no option for the inverse: a desired delay after the coils are pulsed before the relay changes back.The new
ac_relay_debounce_ms
config option is a time duration that is added to the calculated coil completion time, which provides a safety buffer to ensure that the relay is not switched over while a coil still has power.New config option
ac_relay_switch
Later System11 machines include a switch that reflects the real-time state of the AC relay. Using this switch provides a much more accurate assessment of when it is safe to fire relayed coils. The existing method, using
ac_relay_delay_ms
, is vulnerable to queue and serial bus delays because the delay is calculated from when the relay coil is scheduled, which may be some time before the actual command is sent.With a long platform queue, such as during a ball start, it's even possible for the AC relay switch over, coil fire, and switch back events to be sent to the platform within 5-10ms of each other if the queue is longer than the
ac_relay_delay_ms
.This new config option updates the System11 platform to use a switch instead of a delay, if the
ac_relay_switch
value is provided. Instead of a delay timeout, the platform will listen to switch state changes and trigger the appropriate A/C side behavior.New config option
queue_c_side_while_preferred
Most of the bugs and logic improvements (listed below) are caused by competing coil events on both the A and C sides. Even with the below fixes, certain game designs may still drive excessive relay back-and-forth if the preferred C side (flashers) is trying to fire repeatedly while the A side (coils) has a series of coils to fire.
This new configuration option
queue_c_side_while_preferred
is for games where the designer does not care about queueing C side events during gameplay. Because the C side is typically used for flashers and is typically "preferred" during gameplay, this option ignores all C-side triggers while the A side is active. The result is immediate firing of A side coils—even multiple in a row—and no lagging flashes after.Logic Improvements and Bug Fixes
Prioritize switched side queue over preferred
A bug exists in the System11 logic where during relay switches from the preferred side to the other side, any triggers sent to the preferred side will immediately be serviced, causing a switch back to the preferred side and never getting around to firing what the relay originally switched over to fire.
This PR adds a safety check to check for the relay being in transition before attempting to service a trigger, therefore allowing the switchover to complete and the non-preferred side to fire before restoring the preferred side.
Include hold/timed_enable duration in coil timing calculation
A bug exists where the time calculation for how long to hold the relay on a non-preferred side are based exclusively on the pulse time, which can lead to the relay switching over while a coil is still powered for a hold or timed_enable.
This PR updates the time calculation to include both
pulse_settings.duration
andhold_settings.duration
, to help prevent relay switches while switched coils are hot.Explicit
timed_enable
argument for pulse actionsA bug exists with the recent timed_enable implementation based on how System11 platforms determine their behavior. A simple boolean check for
hold_settings
triggered eitherpulse()
(if no hold settings) orenable()
(if yes hold settings). This bug could lead to unintended enabling of coils intended for a timed enable.This PR updates adds an explicit
timed_enable
argument that takes priority over the true/false presence ofhold_settings
, allowing a timed enable to be performed instead of a hold.