Uh oh!
There was an error while loading. Please reload this page.
Possible driver manager concept - #182
Conversation
At the moment, we sometimes create dm=JigDriverManager()
classDriverManager:
def__init__(self):
pub.subscribe(self.test_exception, "Test_Exception")
logging.debug("Driver Manager Init")
self._dmm=Noneself._pps=Noneself._relay_matrix=Noneself._jig_J513=NoneclassFTDIAddressHandlerJ513(AddressHandler):
pin_list= (
"1K1",
...
"3K16",
)
defupdate_output(self, value):
dm.relay_matrix.serial_shift_bit_bang(value)Note the reference to the global Happy to be proven wrong on that :) |
clint-lawrence
commented
May 31, 2024
Starting to chip away at that problem over here master...clint-lawrence:Fixate:jig-mux-refactor |
John2202W
commented
Jul 16, 2024
Another aspect that would be helpful to tie into a rework of the driver manager is a way to decouple or delay the execution of opening drivers until they are used. I.e. for IPM3 we are testing a bunch of comms channels and using a mux to switch in either serial uart or RS485 converters. Would be ideal to have a simple test list such as: With a generic test class: With each of the serial ports being a property of the Driver Manager: Since at import time the serial ports are trying to be accessed, if the device is not connected an exception will be raised before the sequencer and UI are up and running. |
Hey, I know I'm very out of the loop with current practices. Written on phone so excuse code mistakes. But is is better to do something like dependency injection and do away with the driver manager altogether as a global accessor. But rather just use as a context manager and to inject from it to the methods. Would give you the delayed initialisation. And makes type checking easier and local to the the test function. classSerialCommTest(TestClass):
def__init__(
self, mux: str, PortA: serial.Serial, PortB: serial.Serial, *args, **kwargs
):
super().__init__(*args, **kwargs)
self.mux=muxself.port_a=PortAself.port_b=PortBdefsetup(self, jig_j511: JigJ511):
jig_j511.mux(self.mux)
deftest(self, port_a: serial.Serial, port_b: serial.Serial):
port_a.write(self.Message)
message1=port_b.readline()
chk_true(message1==self.Message, f"Comms channel: {self.mux}")
message_return=self.Message+"-reverse".encode("utf-8")
port_b.write(message_return)
message2=port_b.readline()
chk_true(
message2==message_return, f"Comms channel: {self.mux} return"
) |
fromcontextlibimportcontextmanagerclassDriverManager:
stack: ExitStack
...
defregister(name:str, driver:Generator):
self.drivers[name] =contextmanager(driver)
def__enter__():
self.stack=ExitStack()
returnself
...
defenter_context(name:str):
self.active[name] =self.stack.enter_context(self.drivers[name])
returnself.active[name]
# properties for backwards compatibility @propertydefrs422_A(self) ->serial.Serial:
"""RS422 converters for serial comms"""returnself.active.get("rs422_A", self.enter_context("rs422_A")) |
Although, I guess the enter_context and stack should live on the test list, or sequencer not the driver manager. So that you could have set up and teardown of drivers at the same level required by the test lists. Or the sequencer could inject it into the test list etc. Either way, I think this approach simplifies specifying type annotations, at the cost of a "little bit of magic" with using the inspect module to find the appropriate driver for each test list / test by looking at the function signature and matching it by name. The driver manager also becomes generic instead of a per test script implementation. Not relying on dataclass field default factories, allows lazy loading. And provides actual clear definitions on when to clean up the driver. Eg. defdmm_factory():
dmm=DMM.open()
yielddmmdmm.close()
defserial_factory(description:str, baud:int):
@wrapsdeftmp():
device=serial.Serial(
findftdi.by_description(description),
baudrate=baud,
timeout=0.1,
)
yielddevicedevice.close()
returntmpdm=DriverManager()
dm.register("dmm", dmm_factory)
dm.register("rs422_A", serial_factory("J511-RS422-A",57600))
dm.register("rs422_B", serial_factory("J511-RS422-B",57600))You could specify in the top level list if you need the dmm for all tests, or you could get down to specifying only a single mux for a test instead of jig drivers.mux Forgive me if I'm way off base, haven't really looked at it the past 5 years |
This is pretty scrappy, but mostly trying to test out the big picture idea.
Have a look at
test-script.py. Here is the general concept:The doesn't work 100% yet, the example with the "dummy" driver works. obviously we will also need to think about backwards compatibility.