-
Notifications
You must be signed in to change notification settings - Fork 143
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
Changes from all commits
d94840e
3217db7
d6a6a8e
77a9c09
cf21e53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,9 +23,10 @@ class System11OverlayPlatform(DriverPlatform, SwitchPlatform): | |
|
||
"""Overlay platform to drive system11 machines using a WPC controller.""" | ||
|
||
__slots__ = ["delay", "platform", "system11_config", "a_side_queue", "c_side_queue", | ||
__slots__ = ["delay", "platform", "system11_config", "a_side_queue", "c_side_queue", "debounce_secs", | ||
"a_side_done_time", "c_side_done_time", "drivers_holding_a_side", "drivers_holding_c_side", | ||
"a_side_enabled", "c_side_enabled", "ac_relay_in_transition", "prefer_a_side", "drivers"] | ||
"a_side_enabled", "c_side_enabled", "ac_relay_in_transition", "prefer_a_side", "drivers", | ||
"relay_switch"] | ||
|
||
def __init__(self, machine: MachineController) -> None: | ||
"""Initialise the board.""" | ||
|
@@ -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 | ||
self.drivers_holding_a_side = set() # type: Set[DriverPlatformInterface] | ||
self.drivers_holding_c_side = set() # type: Set[DriverPlatformInterface] | ||
self.a_side_enabled = True | ||
|
@@ -60,25 +62,26 @@ def __init__(self, machine: MachineController) -> None: | |
def stop(self): | ||
"""Stop the overlay. Nothing to do here because stop is also called on parent platform.""" | ||
|
||
@property | ||
def a_side_active(self): | ||
"""Return if A side cannot be switched off right away.""" | ||
return self.drivers_holding_a_side or self.a_side_done_time + self.debounce_secs > self.machine.clock.get_time() | ||
|
||
@property | ||
def a_side_busy(self): | ||
"""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 commentThe reason will be displayed to describe this comment to others. Learn more. This block (and the C side) originally duplicated the check in both |
||
|
||
@property | ||
def c_side_active(self): | ||
"""Return if C side cannot be switches off right away.""" | ||
return self.drivers_holding_c_side or self.c_side_done_time > self.machine.clock.get_time() | ||
"""Return if C side cannot be switched off right away.""" | ||
return self.drivers_holding_c_side or self.c_side_done_time + self.debounce_secs > self.machine.clock.get_time() | ||
|
||
@property | ||
def c_side_busy(self): | ||
"""Return if C side cannot be switches off right away.""" | ||
return self.drivers_holding_c_side or self.c_side_done_time > self.machine.clock.get_time() or self.c_side_queue | ||
"""Return if C side cannot be switched off right away.""" | ||
return self.c_side_active or self.c_side_queue | ||
|
||
@property | ||
def a_side_active(self): | ||
"""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() | ||
|
||
async def initialize(self): | ||
"""Automatically called by the Platform class after all the core modules are loaded.""" | ||
|
@@ -101,8 +104,15 @@ def _initialize(self, **kwargs): | |
|
||
self.system11_config['ac_relay_driver'].get_and_verify_hold_power(1.0) | ||
|
||
self.log.debug("Configuring A/C Select Relay transition delay for " | ||
"%sms", self.system11_config['ac_relay_delay_ms']) | ||
if self.system11_config['ac_relay_switch']: | ||
self.log.debug("Configuring A/C Select Relay switch %s", self.system11_config['ac_relay_switch']) | ||
self.system11_config['ac_relay_switch'].add_handler(state=0, callback=self._a_side_enabled) | ||
self.system11_config['ac_relay_switch'].add_handler(state=1, callback=self._c_side_enabled) | ||
|
||
self.debounce_secs = self.system11_config['ac_relay_debounce_ms'] / 1000.0 | ||
self.log.debug("Configuring A/C Select Relay transition delay for %sms and debounce for %s", | ||
self.system11_config['ac_relay_delay_ms'], | ||
self.system11_config['ac_relay_debounce_ms']) | ||
|
||
self.machine.events.add_handler(self.system11_config['prefer_a_side_event'], self._prefer_a_side) | ||
self.log.info("Configuring System11 driver to prefer A side on event %s", | ||
|
@@ -250,7 +260,7 @@ def clear_hw_rule(self, switch, coil): | |
self.platform.clear_hw_rule(switch, coil) | ||
|
||
def driver_action(self, driver, pulse_settings: Optional[PulseSettings], hold_settings: Optional[HoldSettings], | ||
side: str): | ||
side: str, timed_enable: bool = False): | ||
"""Add a driver action for a switched driver to the queue (for either the A-side or C-side queue). | ||
|
||
Args: | ||
|
@@ -264,20 +274,26 @@ def driver_action(self, driver, pulse_settings: Optional[PulseSettings], hold_se | |
""" | ||
if self.prefer_a_side: | ||
if side == "A": | ||
self.a_side_queue.add((driver, pulse_settings, hold_settings)) | ||
self._service_a_side() | ||
self.a_side_queue.add((driver, pulse_settings, hold_settings, timed_enable)) | ||
if not self.ac_relay_in_transition: | ||
self._service_a_side() | ||
elif side == "C": | ||
self.c_side_queue.add((driver, pulse_settings, hold_settings)) | ||
self.c_side_queue.add((driver, pulse_settings, hold_settings, timed_enable)) | ||
if not self.ac_relay_in_transition and not self.a_side_busy: | ||
self._service_c_side() | ||
else: | ||
raise AssertionError("Invalid side {}".format(side)) | ||
else: | ||
if side == "C": | ||
self.c_side_queue.add((driver, pulse_settings, hold_settings)) | ||
self._service_c_side() | ||
# Sometimes it doesn't make sense to queue the C side (flashers) and play them after | ||
# switching to the A side (coils) and back. In which case, just ignore this driver action. | ||
if not self.c_side_enabled and not self.system11_config['queue_c_side_while_preferred']: | ||
return | ||
self.c_side_queue.add((driver, pulse_settings, hold_settings, timed_enable)) | ||
if not self.ac_relay_in_transition: | ||
self._service_c_side() | ||
elif side == "A": | ||
self.a_side_queue.add((driver, pulse_settings, hold_settings)) | ||
self.a_side_queue.add((driver, pulse_settings, hold_settings, timed_enable)) | ||
if not self.ac_relay_in_transition and not self.c_side_busy: | ||
self._service_a_side() | ||
else: | ||
|
@@ -288,18 +304,24 @@ def _enable_ac_relay(self): | |
self.ac_relay_in_transition = True | ||
self.a_side_enabled = False | ||
self.c_side_enabled = False | ||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], | ||
callback=self._c_side_enabled, | ||
name='enable_ac_relay') | ||
# Without a relay switch, use a delay to wait for the relay to enable | ||
if not self.system11_config['ac_relay_switch']: | ||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], | ||
callback=self._c_side_enabled, | ||
name='enable_ac_relay') | ||
|
||
def _disable_ac_relay(self): | ||
self.system11_config['ac_relay_driver'].disable() | ||
self.ac_relay_in_transition = True | ||
self.a_side_enabled = False | ||
self.c_side_enabled = False | ||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], | ||
callback=self._a_side_enabled, | ||
name='disable_ac_relay') | ||
# Clear out the C side queue if we don't want to hold onto it for later | ||
if not self.system11_config['queue_c_side_while_preferred']: | ||
self.c_side_queue.clear() | ||
if not self.system11_config['ac_relay_switch']: | ||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], | ||
callback=self._a_side_enabled, | ||
name='disable_ac_relay') | ||
|
||
# -------------------------------- A SIDE --------------------------------- | ||
|
||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. This delay call seems redundant to me, because This block here uses the same delay to call |
||
callback=self._enable_a_side, | ||
name='enable_a_side') | ||
return | ||
|
||
if self.c_side_enabled: | ||
|
@@ -354,12 +373,17 @@ def _service_a_side(self): | |
return | ||
|
||
while self.a_side_queue: | ||
driver, pulse_settings, hold_settings = self.a_side_queue.pop() | ||
driver, pulse_settings, hold_settings, timed_enable = self.a_side_queue.pop() | ||
|
||
if hold_settings is None and pulse_settings: | ||
driver.pulse(pulse_settings) | ||
self.a_side_done_time = max(self.a_side_done_time, | ||
self.machine.clock.get_time() + (pulse_settings.duration / 1000.0)) | ||
if timed_enable: | ||
wait_ms = driver.timed_enable(pulse_settings, hold_settings) or 0 | ||
wait_secs = (pulse_settings.duration + hold_settings.duration + wait_ms) / 1000.0 | ||
self.a_side_done_time = max(self.a_side_done_time, self.machine.clock.get_time() + wait_secs) | ||
|
||
elif hold_settings is None and pulse_settings: | ||
wait_ms = driver.pulse(pulse_settings) or 0 | ||
wait_secs = (pulse_settings.duration + wait_ms) / 1000.0 | ||
self.a_side_done_time = max(self.a_side_done_time, self.machine.clock.get_time() + wait_secs) | ||
|
||
elif hold_settings and pulse_settings: | ||
driver.enable(pulse_settings, hold_settings) | ||
|
@@ -381,9 +405,6 @@ def _enable_c_side(self): | |
if self.a_side_active: | ||
self._disable_all_a_side_drivers() | ||
self._enable_ac_relay() | ||
self.delay.add(ms=self.system11_config['ac_relay_delay_ms'], | ||
callback=self._enable_c_side, | ||
name='enable_c_side') | ||
return | ||
|
||
if self.a_side_enabled: | ||
|
@@ -429,9 +450,14 @@ def _service_c_side(self): | |
return | ||
|
||
while self.c_side_queue: | ||
driver, pulse_settings, hold_settings = self.c_side_queue.pop() | ||
driver, pulse_settings, hold_settings, timed_enable = self.c_side_queue.pop() | ||
|
||
if timed_enable: | ||
driver.timed_enable(pulse_settings, hold_settings) | ||
self.c_side_done_time = max(self.c_side_done_time, | ||
self.machine.clock.get_time() + (pulse_settings.duration / 1000.0)) | ||
|
||
if hold_settings is None and pulse_settings: | ||
elif hold_settings is None and pulse_settings: | ||
driver.pulse(pulse_settings) | ||
self.c_side_done_time = max(self.c_side_done_time, | ||
self.machine.clock.get_time() + (pulse_settings.duration / 1000.0)) | ||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. This |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. Now that the code path uses the |
||
driver_11.enable = MagicMock() | ||
driver_11.disable = MagicMock() | ||
driver_12.pulse = MagicMock() | ||
driver_12.pulse = MagicMock(return_value=0) | ||
driver_12.enable = MagicMock() | ||
driver_12.disable = MagicMock() | ||
|
||
|
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.