ekfsm 1.2.0a7__py3-none-any.whl → 1.3.0a26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ekfsm might be problematic. Click here for more details.
- ekfsm/boards/oem/hitron/hdrc-300s.yaml +1 -1
- ekfsm/cli.py +6 -8
- ekfsm/config.py +14 -6
- ekfsm/core/__init__.py +5 -5
- ekfsm/core/components.py +4 -4
- ekfsm/core/slots.py +6 -13
- ekfsm/core/sysfs.py +183 -13
- ekfsm/core/utils.py +104 -64
- ekfsm/devices/__init__.py +8 -7
- ekfsm/devices/coretemp.py +11 -10
- ekfsm/devices/eeprom.py +52 -39
- ekfsm/devices/ekf_ccu_uc.py +37 -46
- ekfsm/devices/ekf_sur_led.py +6 -2
- ekfsm/devices/generic.py +141 -88
- ekfsm/devices/gpio.py +33 -25
- ekfsm/devices/iio.py +15 -31
- ekfsm/devices/iio_thermal_humidity.py +12 -13
- ekfsm/devices/mux.py +11 -6
- ekfsm/devices/pmbus.py +60 -67
- ekfsm/devices/smbios.py +10 -8
- ekfsm/devices/smbus.py +1 -1
- ekfsm/devices/utils.py +0 -9
- ekfsm/exceptions.py +28 -7
- ekfsm/lock.py +1 -1
- ekfsm/simctrl.py +37 -83
- ekfsm/system.py +44 -70
- ekfsm/utils.py +9 -6
- {ekfsm-1.2.0a7.dist-info → ekfsm-1.3.0a26.dist-info}/METADATA +8 -5
- ekfsm-1.3.0a26.dist-info/RECORD +46 -0
- ekfsm-1.2.0a7.dist-info/RECORD +0 -46
- {ekfsm-1.2.0a7.dist-info → ekfsm-1.3.0a26.dist-info}/WHEEL +0 -0
- {ekfsm-1.2.0a7.dist-info → ekfsm-1.3.0a26.dist-info}/entry_points.txt +0 -0
ekfsm/devices/mux.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from ekfsm.core.components import SysTree
|
|
2
|
+
from ekfsm.log import ekfsm_logger
|
|
2
3
|
|
|
3
|
-
from ..core.sysfs import
|
|
4
|
+
from ..core.sysfs import SysfsDevice
|
|
4
5
|
from .generic import Device
|
|
5
6
|
|
|
7
|
+
logger = ekfsm_logger(__name__)
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class MuxChannel(Device):
|
|
8
11
|
"""
|
|
@@ -25,20 +28,21 @@ class MuxChannel(Device):
|
|
|
25
28
|
def __init__(
|
|
26
29
|
self,
|
|
27
30
|
name: str,
|
|
28
|
-
channel_id: int,
|
|
29
31
|
parent: "I2CMux",
|
|
30
32
|
children: list[Device] | None = None,
|
|
33
|
+
abort=False,
|
|
34
|
+
channel_id: int | None = None,
|
|
31
35
|
*args,
|
|
32
36
|
**kwargs,
|
|
33
37
|
) -> None:
|
|
34
|
-
super().__init__(name
|
|
38
|
+
super().__init__(name, parent, children, abort, *args, **kwargs)
|
|
35
39
|
self.channel_id = channel_id
|
|
36
40
|
|
|
37
41
|
assert parent.sysfs_device is not None
|
|
38
42
|
assert isinstance(self.parent, I2CMux)
|
|
39
43
|
|
|
40
44
|
path = parent.sysfs_device.path / f"channel-{self.channel_id}"
|
|
41
|
-
self.sysfs_device =
|
|
45
|
+
self.sysfs_device = SysfsDevice(path, False)
|
|
42
46
|
|
|
43
47
|
|
|
44
48
|
class I2CMux(Device):
|
|
@@ -59,11 +63,12 @@ class I2CMux(Device):
|
|
|
59
63
|
self,
|
|
60
64
|
name: str,
|
|
61
65
|
parent: SysTree | None = None,
|
|
62
|
-
children: list[
|
|
66
|
+
children: list[Device] | None = None,
|
|
67
|
+
abort=False,
|
|
63
68
|
*args,
|
|
64
69
|
**kwargs,
|
|
65
70
|
):
|
|
66
|
-
super().__init__(name, parent, children, **kwargs)
|
|
71
|
+
super().__init__(name, parent, children, abort, *args, **kwargs)
|
|
67
72
|
|
|
68
73
|
self.addr = self.get_i2c_chip_addr()
|
|
69
74
|
self.sysfs_device = self.get_i2c_sysfs_device(self.addr)
|
ekfsm/devices/pmbus.py
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from enum import IntFlag
|
|
2
|
-
from
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from time import sleep
|
|
3
5
|
|
|
4
6
|
from ekfsm.core.components import SysTree
|
|
7
|
+
from ekfsm.exceptions import HWMonError
|
|
8
|
+
from ekfsm.log import ekfsm_logger
|
|
5
9
|
|
|
6
|
-
from ..core.sysfs import SysFSDevice, sysfs_root
|
|
7
|
-
|
|
8
|
-
from .generic import Device
|
|
9
10
|
from ..core.probe import ProbeableDevice
|
|
11
|
+
from ..core.sysfs import list_sysfs_attributes, sysfs_root
|
|
12
|
+
from .generic import Device
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
from functools import wraps
|
|
13
|
-
from ekfsm.log import ekfsm_logger
|
|
14
|
-
from threading import Lock
|
|
15
|
-
import re
|
|
16
|
-
|
|
17
|
-
__all__ = ["PsuStatus", "PmBus", "retry"]
|
|
14
|
+
__all__ = ["PSUStatus", "PMBus", "retry"]
|
|
18
15
|
|
|
19
16
|
logger = ekfsm_logger(__name__)
|
|
20
17
|
|
|
@@ -34,8 +31,8 @@ def retry(max_attempts=5, delay=0.5):
|
|
|
34
31
|
|
|
35
32
|
Important
|
|
36
33
|
---------
|
|
37
|
-
This decorator is thread-safe
|
|
38
|
-
|
|
34
|
+
This decorator is _not_ thread-safe across multiple ekfsm processes. Unfortunately,
|
|
35
|
+
we cannot use fcntl or flock syscalls with files on virtual filesystems like sysfs.
|
|
39
36
|
|
|
40
37
|
Parameters
|
|
41
38
|
----------
|
|
@@ -45,26 +42,19 @@ def retry(max_attempts=5, delay=0.5):
|
|
|
45
42
|
The delay in seconds between attempts.
|
|
46
43
|
"""
|
|
47
44
|
|
|
48
|
-
lock = Lock()
|
|
49
|
-
|
|
50
45
|
def decorator(func):
|
|
51
46
|
@wraps(func)
|
|
52
47
|
def wrapper(*args, **kwargs):
|
|
53
48
|
attempts = 0
|
|
54
49
|
while attempts < max_attempts:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
raise e
|
|
65
|
-
logger.info(
|
|
66
|
-
f"Retrying execution of {func.__name__} in {delay}s..."
|
|
67
|
-
)
|
|
50
|
+
try:
|
|
51
|
+
return func(*args, **kwargs)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
attempts += 1
|
|
54
|
+
if attempts == max_attempts:
|
|
55
|
+
logger.exception(f"Failed to execute {func.__name__} after {max_attempts} attempts: {e}")
|
|
56
|
+
raise e
|
|
57
|
+
logger.info(f"Retrying execution of {func.__name__} in {delay}s...")
|
|
68
58
|
sleep(delay)
|
|
69
59
|
|
|
70
60
|
return wrapper
|
|
@@ -72,7 +62,7 @@ def retry(max_attempts=5, delay=0.5):
|
|
|
72
62
|
return decorator
|
|
73
63
|
|
|
74
64
|
|
|
75
|
-
class
|
|
65
|
+
class PSUStatus(IntFlag):
|
|
76
66
|
"""
|
|
77
67
|
Represents the status of a PSU according to STATUS_BYTE register.
|
|
78
68
|
|
|
@@ -108,44 +98,47 @@ class PsuStatus(IntFlag):
|
|
|
108
98
|
OK = 0x00
|
|
109
99
|
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
This class represents a PMBus device (e.g. a PSU).
|
|
114
|
-
"""
|
|
101
|
+
logger = ekfsm_logger(__name__)
|
|
102
|
+
|
|
115
103
|
|
|
104
|
+
class PMBus(Device, ProbeableDevice):
|
|
116
105
|
def __init__(
|
|
117
106
|
self,
|
|
118
107
|
name: str,
|
|
119
108
|
parent: SysTree | None = None,
|
|
120
109
|
children: list[Device] | None = None,
|
|
110
|
+
abort: bool = False,
|
|
121
111
|
*args,
|
|
122
112
|
**kwargs,
|
|
123
113
|
):
|
|
124
|
-
super().__init__(name, parent, children, *args, **kwargs)
|
|
114
|
+
super().__init__(name, parent, children, abort, *args, **kwargs)
|
|
125
115
|
self.addr = self.get_i2c_chip_addr()
|
|
126
|
-
self.sysfs_device = self.get_i2c_sysfs_device(self.addr)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
self.sysfs_device = self.get_i2c_sysfs_device(self.addr, driver_required=True)
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
for entry in self.sysfs_device.path.glob("hwmon/hwmon*"):
|
|
120
|
+
if entry.is_dir():
|
|
121
|
+
attrs = list_sysfs_attributes(entry)
|
|
122
|
+
self.sysfs_device.extend_attributes(attrs)
|
|
123
|
+
|
|
124
|
+
debug_attrs_path = sysfs_root().joinpath(f"kernel/debug/pmbus/{entry.name}")
|
|
125
|
+
debug_attrs = list_sysfs_attributes(debug_attrs_path)
|
|
126
|
+
self.sysfs_device.extend_attributes(debug_attrs)
|
|
127
|
+
except FileNotFoundError:
|
|
128
|
+
logger.debug("Expected sysfs attribute not found")
|
|
129
|
+
except StopIteration:
|
|
130
|
+
raise HWMonError("Device is not managed by hwmon subsystem")
|
|
138
131
|
|
|
139
132
|
def probe(self, *args, **kwargs) -> bool:
|
|
140
|
-
from ekfsm.core import
|
|
133
|
+
from ekfsm.core import HWModule
|
|
141
134
|
|
|
142
|
-
assert isinstance(self.hw_module,
|
|
135
|
+
assert isinstance(self.hw_module, HWModule)
|
|
143
136
|
# compare the regexp from the board yaml file with the model
|
|
144
137
|
return re.match(self.hw_module.id, self.model()) is not None
|
|
145
138
|
|
|
146
139
|
# Voltage and Current Interfaces
|
|
147
|
-
def
|
|
148
|
-
return
|
|
140
|
+
def __convert_and_scale(self, attr: str) -> float:
|
|
141
|
+
return self.sysfs.read_float(attr) / 1000.0
|
|
149
142
|
|
|
150
143
|
@retry()
|
|
151
144
|
def in1_input(self) -> float:
|
|
@@ -156,7 +149,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
156
149
|
-------
|
|
157
150
|
Input voltage in volts
|
|
158
151
|
"""
|
|
159
|
-
return self.
|
|
152
|
+
return self.__convert_and_scale("in1_input")
|
|
160
153
|
|
|
161
154
|
@retry()
|
|
162
155
|
def in2_input(self) -> float:
|
|
@@ -167,7 +160,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
167
160
|
-------
|
|
168
161
|
Input voltage in volts
|
|
169
162
|
"""
|
|
170
|
-
return self.
|
|
163
|
+
return self.__convert_and_scale("in2_input")
|
|
171
164
|
|
|
172
165
|
@retry()
|
|
173
166
|
def curr1_input(self) -> float:
|
|
@@ -178,7 +171,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
178
171
|
-------
|
|
179
172
|
Input current in amperes
|
|
180
173
|
"""
|
|
181
|
-
return self.
|
|
174
|
+
return self.__convert_and_scale("curr1_input")
|
|
182
175
|
|
|
183
176
|
@retry()
|
|
184
177
|
def curr2_input(self) -> float:
|
|
@@ -189,32 +182,32 @@ class PmBus(Device, ProbeableDevice):
|
|
|
189
182
|
-------
|
|
190
183
|
Input current in amperes
|
|
191
184
|
"""
|
|
192
|
-
return self.
|
|
185
|
+
return self.__convert_and_scale("curr2_input")
|
|
193
186
|
|
|
194
187
|
# Status Interface
|
|
195
188
|
@retry()
|
|
196
|
-
def status0_input(self) ->
|
|
189
|
+
def status0_input(self) -> PSUStatus:
|
|
197
190
|
"""
|
|
198
191
|
Get the status of PSU page 1.
|
|
199
192
|
|
|
200
193
|
Returns
|
|
201
194
|
-------
|
|
202
|
-
PSU status as defined in
|
|
195
|
+
PSU status as defined in PSUStatus
|
|
203
196
|
"""
|
|
204
|
-
status =
|
|
205
|
-
return
|
|
197
|
+
status = self.sysfs.read_int("status0_input")
|
|
198
|
+
return PSUStatus(status)
|
|
206
199
|
|
|
207
200
|
@retry()
|
|
208
|
-
def status1_input(self) ->
|
|
201
|
+
def status1_input(self) -> PSUStatus:
|
|
209
202
|
"""
|
|
210
203
|
Get the status of PSU page 2.
|
|
211
204
|
|
|
212
205
|
Returns
|
|
213
206
|
-------
|
|
214
|
-
PSU status as defined in
|
|
207
|
+
PSU status as defined in PSUStatus
|
|
215
208
|
"""
|
|
216
|
-
status =
|
|
217
|
-
return
|
|
209
|
+
status = self.sysfs.read_int("status1_input")
|
|
210
|
+
return PSUStatus(status)
|
|
218
211
|
|
|
219
212
|
# Temperature Interface
|
|
220
213
|
@retry()
|
|
@@ -226,7 +219,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
226
219
|
-------
|
|
227
220
|
PSU temperature in degrees celsius
|
|
228
221
|
"""
|
|
229
|
-
return self.
|
|
222
|
+
return self.__convert_and_scale("temp1_input")
|
|
230
223
|
|
|
231
224
|
# Inventory Interface
|
|
232
225
|
def vendor(self) -> str:
|
|
@@ -237,7 +230,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
237
230
|
-------
|
|
238
231
|
PSU vendor
|
|
239
232
|
"""
|
|
240
|
-
return self.
|
|
233
|
+
return self.sysfs.read_utf8("vendor")
|
|
241
234
|
|
|
242
235
|
def model(self) -> str:
|
|
243
236
|
"""
|
|
@@ -247,7 +240,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
247
240
|
-------
|
|
248
241
|
PSU model
|
|
249
242
|
"""
|
|
250
|
-
return self.
|
|
243
|
+
return self.sysfs.read_utf8("model")
|
|
251
244
|
|
|
252
245
|
def serial(self) -> str:
|
|
253
246
|
"""
|
|
@@ -257,7 +250,7 @@ class PmBus(Device, ProbeableDevice):
|
|
|
257
250
|
-------
|
|
258
251
|
PSU serial number
|
|
259
252
|
"""
|
|
260
|
-
return self.
|
|
253
|
+
return self.sysfs.read_utf8("serial")
|
|
261
254
|
|
|
262
255
|
def revision(self) -> str:
|
|
263
256
|
"""
|
|
@@ -267,4 +260,4 @@ class PmBus(Device, ProbeableDevice):
|
|
|
267
260
|
-------
|
|
268
261
|
PSU revision
|
|
269
262
|
"""
|
|
270
|
-
return self.
|
|
263
|
+
return self.sysfs.read_utf8("revision")
|
ekfsm/devices/smbios.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
from ekfsm.core.
|
|
2
|
+
|
|
3
|
+
from ekfsm.core.components import HWModule
|
|
4
|
+
from ekfsm.core.sysfs import SysfsDevice, sysfs_root
|
|
5
|
+
|
|
4
6
|
from .generic import Device
|
|
5
7
|
|
|
6
8
|
|
|
@@ -18,15 +20,15 @@ class SMBIOS(Device):
|
|
|
18
20
|
def __init__(
|
|
19
21
|
self,
|
|
20
22
|
name: str,
|
|
21
|
-
parent:
|
|
23
|
+
parent: HWModule | None = None,
|
|
24
|
+
children: list["Device"] | None = None,
|
|
25
|
+
abort: bool = False,
|
|
22
26
|
*args,
|
|
23
27
|
**kwargs,
|
|
24
28
|
):
|
|
25
|
-
self.sysfs_device:
|
|
26
|
-
sysfs_root() / Path("devices/virtual/dmi/id")
|
|
27
|
-
)
|
|
29
|
+
self.sysfs_device: SysfsDevice | None = SysfsDevice(sysfs_root() / Path("devices/virtual/dmi/id"), False)
|
|
28
30
|
|
|
29
|
-
super().__init__(name, parent, None, *args, **kwargs)
|
|
31
|
+
super().__init__(name, parent, None, abort, *args, **kwargs)
|
|
30
32
|
|
|
31
33
|
def revision(self) -> str:
|
|
32
34
|
"""
|
|
@@ -37,4 +39,4 @@ class SMBIOS(Device):
|
|
|
37
39
|
str
|
|
38
40
|
The board revision.
|
|
39
41
|
"""
|
|
40
|
-
return self.
|
|
42
|
+
return self.sysfs.read_utf8("board_version")
|
ekfsm/devices/smbus.py
CHANGED
ekfsm/devices/utils.py
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
from crcmod.predefined import Crc
|
|
2
|
-
from typing import Sequence
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def compute_int_from_bytes(data: Sequence[int]) -> int:
|
|
6
|
-
# Combine the bytes into a single integer
|
|
7
|
-
result = 0
|
|
8
|
-
for num in data:
|
|
9
|
-
result = (result << 8) | num
|
|
10
|
-
return result
|
|
11
2
|
|
|
12
3
|
|
|
13
4
|
def get_crc16_xmodem(data: bytes) -> int:
|
ekfsm/exceptions.py
CHANGED
|
@@ -3,6 +3,7 @@ from enum import Enum
|
|
|
3
3
|
|
|
4
4
|
class EkfSmException(Exception):
|
|
5
5
|
"""Base class for all exceptions in the EKFSM Library"""
|
|
6
|
+
|
|
6
7
|
pass
|
|
7
8
|
|
|
8
9
|
|
|
@@ -12,7 +13,7 @@ class ConfigError(EkfSmException):
|
|
|
12
13
|
pass
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class
|
|
16
|
+
class SysFSError(EkfSmException):
|
|
16
17
|
"""Error while handling sysfs pseudo file system"""
|
|
17
18
|
|
|
18
19
|
pass
|
|
@@ -31,9 +32,31 @@ class GPIOError(EkfSmException):
|
|
|
31
32
|
def __init__(self, error_type: ErrorType, details: str | None = None):
|
|
32
33
|
self.error_type = error_type
|
|
33
34
|
self.details = details
|
|
34
|
-
super().__init__(
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
super().__init__(f"{error_type.value}: {details}" if details else error_type.value)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DriverError(EkfSmException):
|
|
39
|
+
"""No driver found for device"""
|
|
40
|
+
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class HWMonError(EkfSmException):
|
|
45
|
+
"""No HwMon entry found for device"""
|
|
46
|
+
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ConversionError(EkfSmException):
|
|
51
|
+
"""Failed to convert"""
|
|
52
|
+
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class UnsupportedModeError(EkfSmException):
|
|
57
|
+
"""Format not supported"""
|
|
58
|
+
|
|
59
|
+
pass
|
|
37
60
|
|
|
38
61
|
|
|
39
62
|
class FirmwareNodeError(EkfSmException):
|
|
@@ -47,9 +70,7 @@ class DataCorruptionError(EkfSmException):
|
|
|
47
70
|
|
|
48
71
|
def __init__(self, details: str | None = None):
|
|
49
72
|
self.details = details
|
|
50
|
-
super().__init__(
|
|
51
|
-
f"Data corruption: {details}" if details else "Data corruption"
|
|
52
|
-
)
|
|
73
|
+
super().__init__(f"Data corruption: {details}" if details else "Data corruption")
|
|
53
74
|
|
|
54
75
|
|
|
55
76
|
class AcquisitionError(EkfSmException):
|
ekfsm/lock.py
CHANGED
ekfsm/simctrl.py
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import socket
|
|
2
2
|
import struct
|
|
3
|
-
from unittest.mock import patch
|
|
4
3
|
from pathlib import Path
|
|
4
|
+
from typing import List
|
|
5
|
+
from unittest.mock import patch
|
|
5
6
|
|
|
6
|
-
from
|
|
7
|
-
from ekfsm.devices.gpio import EKFIdSimGpio
|
|
8
|
-
from ekfsm.devices.gpio import SimGpio
|
|
9
|
-
from .core.sysfs import set_sysfs_root
|
|
10
|
-
from .core.components import SysTree
|
|
7
|
+
from smbus2 import SMBus
|
|
11
8
|
|
|
9
|
+
from ekfsm.devices.gpio import EKFIdSimGpio, SimGpio
|
|
10
|
+
from ekfsm.devices.smbus import SimSMBus
|
|
11
|
+
|
|
12
|
+
from .core.components import SysTree
|
|
13
|
+
from .core.sysfs import set_sysfs_root
|
|
12
14
|
from .devices import GPIO
|
|
13
|
-
from typing import List
|
|
14
|
-
from smbus2 import SMBus
|
|
15
15
|
|
|
16
16
|
GPIO_SIM_MAPPING: dict[str, SimGpio] = {}
|
|
17
|
-
SMBUS_SIM_MAPPING: dict[str,
|
|
17
|
+
SMBUS_SIM_MAPPING: dict[str, SimSMBus] = {}
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def register_gpio_sim(major: int, minor: int, sim_gpio: SimGpio) -> None:
|
|
@@ -31,14 +31,14 @@ def find_gpio_dev_with_major_minor(major: int, minor: int) -> SimGpio:
|
|
|
31
31
|
return GPIO_SIM_MAPPING[name]
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def register_smbus_sim(bus_num: int, i2c_addr: int, sim_smbus:
|
|
34
|
+
def register_smbus_sim(bus_num: int, i2c_addr: int, sim_smbus: SimSMBus) -> None:
|
|
35
35
|
name = f"{bus_num}:{i2c_addr}"
|
|
36
36
|
if name in SMBUS_SIM_MAPPING:
|
|
37
37
|
raise ValueError(f"SMBUS_SIM_MAPPING already contains {name}")
|
|
38
38
|
SMBUS_SIM_MAPPING[name] = sim_smbus
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
def find_smbus_dev(bus_num: int, i2c_addr: int) ->
|
|
41
|
+
def find_smbus_dev(bus_num: int, i2c_addr: int) -> SimSMBus:
|
|
42
42
|
name = f"{bus_num}:{i2c_addr}"
|
|
43
43
|
|
|
44
44
|
if name not in SMBUS_SIM_MAPPING:
|
|
@@ -46,7 +46,7 @@ def find_smbus_dev(bus_num: int, i2c_addr: int) -> SimSmbus:
|
|
|
46
46
|
return SMBUS_SIM_MAPPING[name]
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class
|
|
49
|
+
class GPIOSimulator(GPIO):
|
|
50
50
|
def __init__(
|
|
51
51
|
self,
|
|
52
52
|
name: str,
|
|
@@ -80,7 +80,7 @@ class GpioSimulator(GPIO):
|
|
|
80
80
|
return f"GPIO_SIM({self.name})"
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
class
|
|
83
|
+
class SMBusSimulator:
|
|
84
84
|
def __init__(self, bus_num: int):
|
|
85
85
|
self.bus_num = bus_num
|
|
86
86
|
|
|
@@ -100,73 +100,12 @@ class SmbusSimulator:
|
|
|
100
100
|
find_smbus_dev(self.bus_num, i2c_addr).write_word_data(cmd, data)
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
patched_methods.append(
|
|
110
|
-
patch.object(GPIO, "num_lines", new_callable=lambda: GpioSimulator.num_lines)
|
|
111
|
-
)
|
|
112
|
-
patched_methods.append(
|
|
113
|
-
patch.object(GPIO, "set_pin", new_callable=lambda: GpioSimulator.set_pin)
|
|
114
|
-
)
|
|
115
|
-
patched_methods.append(
|
|
116
|
-
patch.object(GPIO, "get_pin", new_callable=lambda: GpioSimulator.get_pin)
|
|
117
|
-
)
|
|
118
|
-
patched_methods.append(
|
|
119
|
-
patch.object(
|
|
120
|
-
GPIO, "set_direction", new_callable=lambda: GpioSimulator.set_direction
|
|
121
|
-
)
|
|
122
|
-
)
|
|
123
|
-
patched_methods.append(
|
|
124
|
-
patch.object(GPIO, "__str__", new_callable=lambda: GpioSimulator.__str__)
|
|
125
|
-
)
|
|
126
|
-
for pm in patched_methods:
|
|
127
|
-
pm.start()
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def enable_smbus_simulation():
|
|
131
|
-
patched_methods = []
|
|
132
|
-
|
|
133
|
-
patched_methods.append(
|
|
134
|
-
patch.object(SMBus, "__init__", new_callable=lambda: SmbusSimulator.__init__)
|
|
135
|
-
)
|
|
136
|
-
patched_methods.append(
|
|
137
|
-
patch.object(
|
|
138
|
-
SMBus, "read_word_data", new_callable=lambda: SmbusSimulator.read_word_data
|
|
139
|
-
)
|
|
140
|
-
)
|
|
141
|
-
patched_methods.append(
|
|
142
|
-
patch.object(
|
|
143
|
-
SMBus,
|
|
144
|
-
"read_block_data",
|
|
145
|
-
new_callable=lambda: SmbusSimulator.read_block_data,
|
|
146
|
-
)
|
|
147
|
-
)
|
|
148
|
-
patched_methods.append(
|
|
149
|
-
patch.object(
|
|
150
|
-
SMBus,
|
|
151
|
-
"write_block_data",
|
|
152
|
-
new_callable=lambda: SmbusSimulator.write_block_data,
|
|
153
|
-
)
|
|
154
|
-
)
|
|
155
|
-
patched_methods.append(
|
|
156
|
-
patch.object(
|
|
157
|
-
SMBus, "write_byte", new_callable=lambda: SmbusSimulator.write_byte
|
|
158
|
-
)
|
|
159
|
-
)
|
|
160
|
-
patched_methods.append(
|
|
161
|
-
patch.object(
|
|
162
|
-
SMBus,
|
|
163
|
-
"write_word_data",
|
|
164
|
-
new_callable=lambda: SmbusSimulator.write_word_data,
|
|
165
|
-
)
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
for pm in patched_methods:
|
|
169
|
-
pm.start()
|
|
103
|
+
def patch_methods(cls, simulator, methods):
|
|
104
|
+
patched = []
|
|
105
|
+
for i, method in enumerate(methods):
|
|
106
|
+
if hasattr(cls, method) and hasattr(simulator, method):
|
|
107
|
+
patched.append(patch.object(cls, method, new_callable=lambda: getattr(simulator, method)))
|
|
108
|
+
patched[i].start()
|
|
170
109
|
|
|
171
110
|
|
|
172
111
|
def enable_simulation(sysfs_path: Path | str) -> None:
|
|
@@ -180,8 +119,23 @@ def enable_simulation(sysfs_path: Path | str) -> None:
|
|
|
180
119
|
sysfs_path = Path(sysfs_path)
|
|
181
120
|
|
|
182
121
|
set_sysfs_root(sysfs_path)
|
|
183
|
-
|
|
184
|
-
|
|
122
|
+
patch_methods(
|
|
123
|
+
GPIO,
|
|
124
|
+
GPIOSimulator,
|
|
125
|
+
["__init__", "num_lines", "set_pin", "get_pin", "set_direction", "__str__"],
|
|
126
|
+
)
|
|
127
|
+
patch_methods(
|
|
128
|
+
SMBus,
|
|
129
|
+
SMBusSimulator,
|
|
130
|
+
[
|
|
131
|
+
"__init__",
|
|
132
|
+
"read_word_data",
|
|
133
|
+
"read_block_data",
|
|
134
|
+
"write_block_data",
|
|
135
|
+
"write_byte",
|
|
136
|
+
"write_word_data",
|
|
137
|
+
],
|
|
138
|
+
)
|
|
185
139
|
|
|
186
140
|
|
|
187
141
|
def register_gpio_simulations():
|
|
@@ -189,7 +143,7 @@ def register_gpio_simulations():
|
|
|
189
143
|
register_gpio_sim(233, 2, EKFIdSimGpio(0x34, 0xA, 0x0, 0x1)) # CCU Rev 0
|
|
190
144
|
|
|
191
145
|
|
|
192
|
-
class SocketSmbus(
|
|
146
|
+
class SocketSmbus(SimSMBus):
|
|
193
147
|
def __init__(self, host: str, port: int) -> None:
|
|
194
148
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
195
149
|
self.sock.connect((host, port))
|