Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Improvements
now be called after performing signal acquisition.
- Invert channel and vtime functions implemented in the DSO driver.
- Fxconfig fixes for cmd2 4.0.0
- Jig switching fix to force sending the reset signal regardless of presumed jig state

*************
Version 0.6.4
Expand Down
9 changes: 6 additions & 3 deletions src/fixate/_switching.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,13 +619,13 @@ def _do_pending_updates(self) -> None:
time.sleep(collated.minimum_change_time)
self._dispatch_pin_state(collated.final)

def _dispatch_pin_state(self, new_state: PinSetState) -> None:
def _dispatch_pin_state(self, new_state: PinSetState, force: bool = False) -> None:
# check all pins actually have an address handler to send to
if unknown_pins := (new_state.on | new_state.off) - self._all_pins:
raise ValueError(f"Can't switch unknown pin(s) {', '.join(unknown_pins)}.")

new_active_pins = (self._active_pins | new_state.on) - new_state.off
if new_active_pins != self._active_pins:
if (new_active_pins != self._active_pins) or force:
self._active_pins = new_active_pins
for pin_set, handler in self._handler_pin_sets:
# Note that we might send an empty set here. We need to do that
Expand All @@ -645,7 +645,7 @@ def reset(self) -> None:
possible the state of each VirtualMux and its related pins will not
be in sync.
"""
self._dispatch_pin_state(PinSetState(off=self._all_pins))
self._dispatch_pin_state(PinSetState(off=self._all_pins), force=True)

def update_input(self) -> None:
"""
Expand Down Expand Up @@ -743,6 +743,9 @@ def reset(self) -> None:
"""
Reset all VirtualMux's to the default signal "" (all pins off)
"""
# first reset the virtual map of pins to a known default state
self.virtual_map.reset()
# now reset the muxes to ensure the virtual map and muxes are synced
self.mux.reset()

def _validate(self) -> None:
Expand Down
52 changes: 52 additions & 0 deletions test/test_switching.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from typing import Collection, Sequence

from fixate._switching import (
Pin,
_generate_bit_sets,
VirtualMux,
_bit_generator,
Expand Down Expand Up @@ -592,3 +595,52 @@ def test_pin_update_or():
2.0,
)
assert expected == a | b


def test_jig_driver_reset_when_desynced():
"""
test that reset forces the physical of the jig back to default
we do this by directly switching using the address handler to force a desync
between the virtual_map and the handler

cases where this could happen in a real test are after force quitting a script
where the physical state of pins would not be cleared
"""

class Handler(AddressHandler):
def __init__(self, pins: Sequence[Pin]) -> None:
self.physical_pin_states = {pin: False for pin in pins}
super().__init__(pins)

def set_pins(self, pins: Collection[Pin]) -> None:
old_pins = self.physical_pin_states
self.physical_pin_states = {pin: (pin in pins) for pin in old_pins}

handler = Handler(("x0", "x1", "x2"))

class Mux(VirtualMux):
pin_list = ("x0", "x1", "x2")
map_list = ("sig1", "x1", "x2")

class Group(MuxGroup):
def __init__(self):
self.mux = Mux()

jig = JigDriver(Group, [handler])
# directly switch some pins in the handler, the jig won't know about this
handler.set_pins(("x0", "x1"))
assert handler.physical_pin_states == {
"x0": True,
"x1": True,
"x2": False,
}
# the jig doesn't know about the state of the pins if not switching using the mux
assert not jig.active_pins()

# resetting the jig should clear the pins regardless about what it thinks the state of the pins are
jig.reset()
assert handler.physical_pin_states == {
"x0": False,
"x1": False,
"x2": False,
}
Loading