1111- Turn digital output on and off
1212"""
1313
14+ import errno
15+ from contextlib import contextmanager
16+ from time import monotonic , sleep
17+
1418import usb .core
1519import usb .util
1620
@@ -26,18 +30,35 @@ def __init__(self, **args):
2630 raise ValueError ("Device not found" )
2731
2832 if self ._dev .idVendor == 0x16C0 :
29- self .set_output = self .set_output_dcttech
30- self .get_output = self .get_output_dcttech
33+ self ._set_output = self ._set_output_dcttech
34+ self ._get_output = self ._get_output_dcttech
3135 elif self ._dev .idVendor == 0x5131 :
32- self .set_output = self .set_output_lcus
33- self .get_output = self .get_output_lcus
36+ self ._set_output = self ._set_output_lcus
37+ self ._get_output = self ._get_output_lcus
3438 else :
3539 raise ValueError (f"Unknown vendor/protocol for VID { self ._dev .idVendor :x} " )
3640
3741 if self ._dev .is_kernel_driver_active (0 ):
3842 self ._dev .detach_kernel_driver (0 )
3943
40- def set_output_dcttech (self , number , status ):
44+ @contextmanager
45+ def _claimed (self ):
46+ timeout = monotonic () + 1.0
47+ while True :
48+ try :
49+ usb .util .claim_interface (self ._dev , 0 )
50+ break
51+ except usb .core .USBError as e :
52+ if monotonic () > timeout :
53+ raise e
54+ if e .errno == errno .EBUSY :
55+ sleep (0.01 )
56+ else :
57+ raise e
58+ yield
59+ usb .util .release_interface (self ._dev , 0 )
60+
61+ def _set_output_dcttech (self , number , status ):
4162 assert 1 <= number <= 8
4263 req = [0xFF if status else 0xFD , number ]
4364 self ._dev .ctrl_transfer (
@@ -48,7 +69,7 @@ def set_output_dcttech(self, number, status):
4869 req , # payload
4970 )
5071
51- def get_output_dcttech (self , number ):
72+ def _get_output_dcttech (self , number ):
5273 assert 1 <= number <= 8
5374 resp = self ._dev .ctrl_transfer (
5475 usb .util .CTRL_TYPE_CLASS | usb .util .CTRL_RECIPIENT_DEVICE | usb .util .ENDPOINT_IN ,
@@ -59,7 +80,7 @@ def get_output_dcttech(self, number):
5980 )
6081 return bool (resp [7 ] & (1 << (number - 1 )))
6182
62- def set_output_lcus (self , number , status ):
83+ def _set_output_lcus (self , number , status ):
6384 assert 1 <= number <= 8
6485 ep_in = self ._dev [0 ][(0 , 0 )][0 ]
6586 ep_out = self ._dev [0 ][(0 , 0 )][1 ]
@@ -68,13 +89,18 @@ def set_output_lcus(self, number, status):
6889 ep_out .write (req )
6990 ep_in .read (64 )
7091
71- def get_output_lcus (self , number ):
92+ def _get_output_lcus (self , number ):
7293 assert 1 <= number <= 8
7394 # we have no information on how to read the current value
7495 return False
7596
76- def __del__ (self ):
77- usb .util .release_interface (self ._dev , 0 )
97+ def set_output (self , number , status ):
98+ with self ._claimed ():
99+ self ._set_output (number , status )
100+
101+ def get_output (self , number ):
102+ with self ._claimed ():
103+ self ._get_output (number )
78104
79105
80106_relays = {}
0 commit comments