ekfsm 0.13.0a183__py3-none-any.whl → 1.5.0__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/__init__.py +3 -14
- ekfsm/boards/oem/ekf/shu-shuttle.yaml +43 -0
- ekfsm/boards/oem/ekf/sq3-quartet.yaml +51 -37
- ekfsm/boards/oem/ekf/z1010.yaml +102 -0
- ekfsm/boards/oem/hitron/hdrc-300s.yaml +1 -1
- ekfsm/cli.py +32 -9
- ekfsm/config.py +14 -6
- ekfsm/core/__init__.py +13 -3
- ekfsm/core/components.py +7 -8
- ekfsm/core/connections.py +19 -0
- ekfsm/core/slots.py +6 -8
- ekfsm/core/sysfs.py +215 -25
- ekfsm/core/utils.py +128 -64
- ekfsm/devices/__init__.py +27 -7
- ekfsm/devices/buttons.py +251 -0
- ekfsm/devices/colorLed.py +110 -0
- ekfsm/devices/coretemp.py +35 -13
- ekfsm/devices/eeprom.py +73 -45
- ekfsm/devices/ekf_ccu_uc.py +76 -54
- ekfsm/devices/ekf_sur_led.py +6 -2
- ekfsm/devices/generic.py +200 -59
- ekfsm/devices/gpio.py +37 -27
- ekfsm/devices/iio.py +15 -31
- ekfsm/devices/iio_thermal_humidity.py +20 -13
- ekfsm/devices/imu.py +8 -4
- ekfsm/devices/io4edge.py +185 -0
- ekfsm/devices/ledArray.py +54 -0
- ekfsm/devices/mux.py +46 -8
- ekfsm/devices/pixelDisplay.py +141 -0
- ekfsm/devices/pmbus.py +74 -101
- ekfsm/devices/smbios.py +28 -8
- ekfsm/devices/smbus.py +1 -1
- ekfsm/devices/thermal_humidity.py +80 -0
- ekfsm/devices/toggles.py +90 -0
- ekfsm/devices/utils.py +52 -8
- ekfsm/devices/watchdog.py +79 -0
- ekfsm/exceptions.py +28 -7
- ekfsm/lock.py +48 -21
- ekfsm/simctrl.py +37 -83
- ekfsm/system.py +89 -73
- ekfsm/utils.py +44 -0
- {ekfsm-0.13.0a183.dist-info → ekfsm-1.5.0.dist-info}/METADATA +12 -6
- ekfsm-1.5.0.dist-info/RECORD +57 -0
- ekfsm-0.13.0a183.dist-info/RECORD +0 -45
- {ekfsm-0.13.0a183.dist-info → ekfsm-1.5.0.dist-info}/WHEEL +0 -0
- {ekfsm-0.13.0a183.dist-info → ekfsm-1.5.0.dist-info}/entry_points.txt +0 -0
ekfsm/core/sysfs.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
from collections.abc import MutableMapping
|
|
1
2
|
from pathlib import Path
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
from more_itertools import first_true
|
|
6
|
+
|
|
7
|
+
from ekfsm.exceptions import ConversionError, DriverError, SysFSError
|
|
2
8
|
|
|
3
9
|
SYSFS_ROOT = Path("/sys")
|
|
4
10
|
|
|
@@ -20,41 +26,41 @@ class SysFSAttribute:
|
|
|
20
26
|
"""
|
|
21
27
|
A SysFSAttribute is a singular sysfs attribute located somewhere in */sys*.
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
Parameters
|
|
24
30
|
----------
|
|
25
|
-
path
|
|
26
|
-
|
|
27
|
-
name : str
|
|
28
|
-
attribute name, or the last part of self.path
|
|
29
|
-
|
|
30
|
-
Methods
|
|
31
|
-
-------
|
|
32
|
-
read() -> Optional[str]
|
|
33
|
-
Reads the file attribute if it exists
|
|
34
|
-
write(data: Union[str, int]) -> None
|
|
35
|
-
Writes data to the file attribute
|
|
36
|
-
|
|
31
|
+
path: Path
|
|
32
|
+
Path to the underlying file for the SysFSAttribute instance.
|
|
37
33
|
"""
|
|
38
34
|
|
|
39
35
|
def __init__(self, path: Path):
|
|
40
|
-
self.path = path
|
|
41
36
|
if not path.exists() or not path.is_file():
|
|
42
37
|
raise FileNotFoundError("Invalid sysfs attribute path")
|
|
43
38
|
|
|
39
|
+
self.path = path
|
|
44
40
|
self.name: str = path.name
|
|
45
41
|
|
|
46
42
|
def read_utf8(self) -> str:
|
|
47
|
-
|
|
43
|
+
try:
|
|
44
|
+
return self.path.read_text()
|
|
45
|
+
except OSError as e:
|
|
46
|
+
raise SysFSError("Error accessing SysFS attribute") from e
|
|
48
47
|
|
|
49
48
|
def read_bytes(self) -> bytes:
|
|
50
|
-
|
|
49
|
+
try:
|
|
50
|
+
return self.path.read_bytes()
|
|
51
|
+
except OSError as e:
|
|
52
|
+
raise SysFSError("Error accessing SysFS attribute") from e
|
|
51
53
|
|
|
54
|
+
# FIXME: This cannot work due to sysfs attributes not supporting seek().
|
|
52
55
|
def write(self, data: str | bytes | None, offset: int = 0) -> None:
|
|
53
56
|
if self.is_sysfs_attr() and data is not None:
|
|
54
|
-
mode =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
mode = "r+" if isinstance(data, str) else "rb+"
|
|
58
|
+
try:
|
|
59
|
+
with open(self.path, mode) as f:
|
|
60
|
+
f.seek(offset)
|
|
61
|
+
f.write(data)
|
|
62
|
+
except OSError as e:
|
|
63
|
+
raise SysFSError("Error accessing SysFS attribute") from e
|
|
58
64
|
|
|
59
65
|
def is_sysfs_attr(self) -> bool:
|
|
60
66
|
return file_is_sysfs_attr(self.path)
|
|
@@ -70,10 +76,45 @@ def list_sysfs_attributes(path: Path) -> list[SysFSAttribute]:
|
|
|
70
76
|
return [SysFSAttribute(item) for item in path.iterdir() if file_is_sysfs_attr(item)]
|
|
71
77
|
|
|
72
78
|
|
|
73
|
-
class
|
|
74
|
-
def __init__(
|
|
79
|
+
class SysfsDevice(MutableMapping):
|
|
80
|
+
def __init__(
|
|
81
|
+
self, base_dir: Path, driver_required=True, find_driver: Callable | None = None
|
|
82
|
+
):
|
|
75
83
|
self.path: Path = base_dir
|
|
76
|
-
self.
|
|
84
|
+
self.driver_required = driver_required
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
self.driver = self.get_driver()
|
|
88
|
+
except Exception:
|
|
89
|
+
self.driver = None
|
|
90
|
+
|
|
91
|
+
if driver_required:
|
|
92
|
+
raise DriverError(f"No driver found for device at {base_dir}")
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
self.attributes: list[SysFSAttribute] = list_sysfs_attributes(self.path)
|
|
96
|
+
except FileNotFoundError as e:
|
|
97
|
+
raise SysFSError(f"SysFS entry for {base_dir} does not exist") from e
|
|
98
|
+
|
|
99
|
+
def __getitem__(self, key):
|
|
100
|
+
if (
|
|
101
|
+
attr := first_true(self.attributes, pred=lambda a: a.name == key)
|
|
102
|
+
) is not None:
|
|
103
|
+
return attr
|
|
104
|
+
|
|
105
|
+
raise KeyError(f"'{key}' is not a valid sysfs attribute in {self.path}")
|
|
106
|
+
|
|
107
|
+
def __setitem__(self, key, value):
|
|
108
|
+
self[key].write(value)
|
|
109
|
+
|
|
110
|
+
def __delitem__(self, key):
|
|
111
|
+
del self.attributes[key]
|
|
112
|
+
|
|
113
|
+
def __iter__(self):
|
|
114
|
+
return iter(self.attributes)
|
|
115
|
+
|
|
116
|
+
def __len__(self):
|
|
117
|
+
return len(self.attributes)
|
|
77
118
|
|
|
78
119
|
def pre(self) -> None:
|
|
79
120
|
pass
|
|
@@ -81,11 +122,160 @@ class SysFSDevice:
|
|
|
81
122
|
def post(self) -> None:
|
|
82
123
|
pass
|
|
83
124
|
|
|
84
|
-
def write_attr(self, attr: str, data: str | bytes
|
|
85
|
-
next(x for x in self.attributes if x.name == attr).write(data
|
|
125
|
+
def write_attr(self, attr: str, data: str | bytes) -> None:
|
|
126
|
+
next(x for x in self.attributes if x.name == attr).write(data)
|
|
127
|
+
|
|
128
|
+
def write_attr_bytes(self, attr: str, data: str) -> None:
|
|
129
|
+
# TODO: This
|
|
130
|
+
pass
|
|
86
131
|
|
|
87
132
|
def read_attr_utf8(self, attr: str) -> str:
|
|
88
133
|
return next(x for x in self.attributes if x.name == attr).read_utf8()
|
|
89
134
|
|
|
135
|
+
def read_float(self, attr: str) -> float:
|
|
136
|
+
"""
|
|
137
|
+
Read a sysfs attribute as a floating-point number
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
attr: str
|
|
142
|
+
The sysfs attribute to read
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
-------
|
|
146
|
+
The sysfs attribute as a floating-point number
|
|
147
|
+
|
|
148
|
+
Raises
|
|
149
|
+
------
|
|
150
|
+
SysFSError
|
|
151
|
+
If the sysfs attribute does not exist
|
|
152
|
+
ConversionError
|
|
153
|
+
If the sysfs attribute could not be converted to a floating-point number
|
|
154
|
+
"""
|
|
155
|
+
try:
|
|
156
|
+
value = self.read_attr_utf8(attr)
|
|
157
|
+
return float(value)
|
|
158
|
+
except StopIteration as e:
|
|
159
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
160
|
+
except SysFSError:
|
|
161
|
+
raise
|
|
162
|
+
except ValueError as e:
|
|
163
|
+
raise ConversionError(
|
|
164
|
+
"Failed to convert sysfs value to floating-point value"
|
|
165
|
+
) from e
|
|
166
|
+
|
|
167
|
+
def read_int(self, attr) -> int:
|
|
168
|
+
"""
|
|
169
|
+
Read a sysfs attribute stored as a string as an integer
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
attr: str
|
|
174
|
+
The sysfs attribute to read
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
The sysfs attribute as an integer
|
|
179
|
+
|
|
180
|
+
Raises
|
|
181
|
+
------
|
|
182
|
+
SysFSError
|
|
183
|
+
If the sysfs attribute does not exist
|
|
184
|
+
ConversionError
|
|
185
|
+
If the sysfs attribute could not be converted to an integer
|
|
186
|
+
"""
|
|
187
|
+
try:
|
|
188
|
+
value = self.read_attr_utf8(attr).strip()
|
|
189
|
+
return int(value)
|
|
190
|
+
except StopIteration as e:
|
|
191
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
192
|
+
except SysFSError:
|
|
193
|
+
raise
|
|
194
|
+
except ValueError as e:
|
|
195
|
+
raise ConversionError("Failed to convert sysfs value to int") from e
|
|
196
|
+
|
|
197
|
+
def read_hex(self, attr) -> int:
|
|
198
|
+
"""
|
|
199
|
+
Read a sysfs attribute stored as a hexadecimal integer as integer
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
attr: str
|
|
204
|
+
The sysfs attribute to read
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
The sysfs attribute as a hexadecimal integer
|
|
209
|
+
|
|
210
|
+
Raises
|
|
211
|
+
------
|
|
212
|
+
SysFSError
|
|
213
|
+
If the sysfs attribute does not exist
|
|
214
|
+
ConversionError
|
|
215
|
+
If the sysfs attribute could not be converted to a hexadecimal integer
|
|
216
|
+
"""
|
|
217
|
+
try:
|
|
218
|
+
value = self.read_attr_utf8(attr).strip()
|
|
219
|
+
return int(value, 16)
|
|
220
|
+
except StopIteration as e:
|
|
221
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
222
|
+
except SysFSError:
|
|
223
|
+
raise
|
|
224
|
+
except ValueError as e:
|
|
225
|
+
raise ConversionError("Failed to convert sysfs value to hex int") from e
|
|
226
|
+
|
|
227
|
+
def read_utf8(self, attr, strip=True) -> str:
|
|
228
|
+
"""
|
|
229
|
+
Read a sysfs attribute as a UTF-8 encoded string
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
attr: str
|
|
234
|
+
The sysfs attribute to read
|
|
235
|
+
strip: bool
|
|
236
|
+
Strip whitespace, defaults to true
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
The sysfs attribute as a UTF-8 encoded string
|
|
241
|
+
|
|
242
|
+
Raises
|
|
243
|
+
------
|
|
244
|
+
SysFSError
|
|
245
|
+
If the sysfs attribute does not exist
|
|
246
|
+
"""
|
|
247
|
+
try:
|
|
248
|
+
value = self.read_attr_utf8(attr)
|
|
249
|
+
if strip:
|
|
250
|
+
value = value.strip()
|
|
251
|
+
|
|
252
|
+
return value
|
|
253
|
+
except StopIteration as e:
|
|
254
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
255
|
+
except SysFSError:
|
|
256
|
+
raise
|
|
257
|
+
|
|
90
258
|
def read_attr_bytes(self, attr: str) -> bytes:
|
|
91
259
|
return next(x for x in self.attributes if x.name == attr).read_bytes()
|
|
260
|
+
|
|
261
|
+
def read_bytes(self, attr) -> bytes:
|
|
262
|
+
try:
|
|
263
|
+
value = self.read_attr_bytes(attr)
|
|
264
|
+
return value
|
|
265
|
+
except StopIteration as e:
|
|
266
|
+
raise SysFSError(f"'{attr}' sysfs attribute does not exist") from e
|
|
267
|
+
except SysFSError:
|
|
268
|
+
raise
|
|
269
|
+
|
|
270
|
+
def extend_attributes(self, attributes: list[SysFSAttribute]):
|
|
271
|
+
self.attributes.extend(attributes)
|
|
272
|
+
|
|
273
|
+
def get_driver(self) -> str | None:
|
|
274
|
+
path = self.path
|
|
275
|
+
|
|
276
|
+
if self.path.joinpath("device").exists():
|
|
277
|
+
path = self.path.joinpath("device")
|
|
278
|
+
elif not path.joinpath("driver").exists():
|
|
279
|
+
raise DriverError("Failed to retrieve driver info")
|
|
280
|
+
|
|
281
|
+
return path.joinpath("driver").readlink().name
|
ekfsm/core/utils.py
CHANGED
|
@@ -1,92 +1,156 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
import logging
|
|
3
|
-
from
|
|
4
|
-
from
|
|
4
|
+
from pprint import pformat
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from schema import Optional, Or, Schema, SchemaError, Use
|
|
8
|
+
from termcolor import colored
|
|
5
9
|
|
|
6
10
|
from ekfsm.devices import CLASS_MAP
|
|
7
11
|
from ekfsm.exceptions import ConfigError
|
|
8
12
|
|
|
9
13
|
if TYPE_CHECKING:
|
|
10
|
-
from .components import HwModule
|
|
11
14
|
from ekfsm.devices.generic import Device
|
|
12
15
|
|
|
16
|
+
from .components import HWModule
|
|
13
17
|
|
|
14
|
-
class BoardDictImporter:
|
|
15
|
-
|
|
16
|
-
def __init__(self, nodecls=AnyNode):
|
|
17
|
-
self.nodecls = nodecls
|
|
18
|
-
|
|
19
|
-
def import_(self, logger: logging.Logger, data, parent=None, abort: bool = False):
|
|
20
|
-
"""Import tree from `data`."""
|
|
21
|
-
return self.__import(logger, data, parent=parent, abort=abort)
|
|
22
|
-
|
|
23
|
-
def __import(self, logger: logging.Logger, data, parent=None, abort: bool = False):
|
|
24
|
-
from .components import HwModule
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if nodecls is None:
|
|
29
|
-
raise ConfigError(f"Unknown device type: {device_type}")
|
|
19
|
+
def import_board(logger: logging.Logger, data, parent=None, abort: bool = False):
|
|
20
|
+
from .components import HWModule
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
device_type = data.get("device_type")
|
|
23
|
+
nodecls = CLASS_MAP.get(device_type)
|
|
24
|
+
if nodecls is None:
|
|
25
|
+
raise ConfigError(f"Unknown device type: {device_type}")
|
|
35
26
|
|
|
36
|
-
|
|
27
|
+
children = data.pop("children", [])
|
|
28
|
+
if parent is not None and isinstance(parent, HWModule):
|
|
29
|
+
# ???
|
|
30
|
+
pass
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
logger.debug(f"Importing sub device {child}")
|
|
42
|
-
self.__import(logger, child, parent=node, abort=abort)
|
|
43
|
-
except Exception as e:
|
|
44
|
-
if abort:
|
|
45
|
-
logger.error(
|
|
46
|
-
f"Failed to import sub device {child}: {e}. aborting"
|
|
47
|
-
)
|
|
48
|
-
raise e
|
|
49
|
-
else:
|
|
50
|
-
logger.error(
|
|
51
|
-
f"Failed to import sub device {child}: {e}. continue anyway"
|
|
52
|
-
)
|
|
53
|
-
return node
|
|
32
|
+
if provides := data.get("provides"):
|
|
33
|
+
for p in provides:
|
|
34
|
+
interfaces = data["provides"][p]
|
|
54
35
|
|
|
36
|
+
for interface in interfaces:
|
|
37
|
+
if isinstance(interface, str):
|
|
38
|
+
if attr := getattr(nodecls, interface, None):
|
|
39
|
+
if not callable(attr) and not abort:
|
|
40
|
+
raise ConfigError("No such method")
|
|
41
|
+
elif isinstance(interface, dict):
|
|
42
|
+
for key, value in interface.items():
|
|
43
|
+
if attr := getattr(nodecls, value, None):
|
|
44
|
+
if not callable(attr) and not abort:
|
|
45
|
+
raise ConfigError("No such method")
|
|
46
|
+
else:
|
|
47
|
+
raise ConfigError("Error in board configuration")
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
logger: logging.Logger, data: dict, parent: "HwModule"
|
|
58
|
-
) -> tuple[str, str, str, list["Device"]]:
|
|
59
|
-
importer = BoardDictImporter()
|
|
60
|
-
abort = parent.abort
|
|
61
|
-
|
|
62
|
-
# better use schema extension for this
|
|
63
|
-
id = data.pop("id", None)
|
|
64
|
-
if id is None:
|
|
65
|
-
raise ConfigError("Board configuration must contain `id`")
|
|
66
|
-
name = data.pop("name", None)
|
|
67
|
-
if name is None:
|
|
68
|
-
raise ConfigError("Board configuration must contain `name`")
|
|
69
|
-
slot_type = data.pop("slot_type")
|
|
70
|
-
if slot_type is None:
|
|
71
|
-
raise ConfigError("Board configuration must contain `board_type`")
|
|
49
|
+
node = nodecls(parent=parent, abort=abort, **data)
|
|
72
50
|
|
|
73
|
-
children
|
|
74
|
-
devices = []
|
|
75
|
-
if children:
|
|
51
|
+
if children is not None:
|
|
76
52
|
for child in children:
|
|
77
53
|
try:
|
|
78
|
-
logger.debug(f"Importing
|
|
79
|
-
|
|
80
|
-
devices.append(node)
|
|
54
|
+
logger.debug(f"Importing sub device {pformat(child)}")
|
|
55
|
+
import_board(logger, data=child, parent=node, abort=abort)
|
|
81
56
|
except Exception as e:
|
|
82
57
|
if abort:
|
|
83
58
|
logger.error(
|
|
84
|
-
f"Failed to import
|
|
59
|
+
f"Failed to import sub device {pformat(child)}: {e}. Aborting."
|
|
85
60
|
)
|
|
86
61
|
raise e
|
|
87
62
|
else:
|
|
88
63
|
logger.error(
|
|
89
|
-
f"Failed to import
|
|
64
|
+
f"Failed to import sub device {pformat(child)}: {e}. Continuing anyway."
|
|
90
65
|
)
|
|
66
|
+
return node
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def provides_validator(x: Any) -> Any:
|
|
70
|
+
if isinstance(x, str):
|
|
71
|
+
return x
|
|
72
|
+
elif isinstance(x, dict) and len(x) == 1:
|
|
73
|
+
key, value = next(iter(x.items()))
|
|
74
|
+
if isinstance(key, str) and isinstance(value, str):
|
|
75
|
+
return x
|
|
76
|
+
raise SchemaError(
|
|
77
|
+
"Each provides item must be either a string or a dictionary with one string key/value pair"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
device_schema = Schema({})
|
|
82
|
+
|
|
83
|
+
_device_structure = Schema(
|
|
84
|
+
{
|
|
85
|
+
"device_type": str,
|
|
86
|
+
"name": str,
|
|
87
|
+
Optional("addr"): int,
|
|
88
|
+
Optional("slot_coding_mask"): int,
|
|
89
|
+
Optional("channel_id"): int,
|
|
90
|
+
Optional("service_suffix"): str,
|
|
91
|
+
Optional("keepaliveInterval"): int,
|
|
92
|
+
Optional("provides"): {
|
|
93
|
+
Optional(str): [Use(provides_validator)],
|
|
94
|
+
},
|
|
95
|
+
Optional("children"): Or(None, [device_schema]),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
device_schema._schema = _device_structure
|
|
100
|
+
|
|
101
|
+
module_schema = Schema(
|
|
102
|
+
{
|
|
103
|
+
"id": Or(int, str),
|
|
104
|
+
"name": str,
|
|
105
|
+
"slot_type": str,
|
|
106
|
+
Optional("children"): [device_schema],
|
|
107
|
+
Optional("bus_masters"): {
|
|
108
|
+
Optional("i2c"): dict,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def deserialize_module(logger: logging.Logger, data: dict) -> tuple[str, str, str]:
|
|
115
|
+
"""
|
|
116
|
+
docstring
|
|
117
|
+
"""
|
|
118
|
+
module_schema.validate(data)
|
|
119
|
+
|
|
120
|
+
id, name, slot_type = (data[key] for key in ["id", "name", "slot_type"])
|
|
121
|
+
logger.debug(colored(f"Importing top level module {pformat(name)}", "green"))
|
|
122
|
+
|
|
123
|
+
return id, name, slot_type
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def deserialize_hardware_tree(
|
|
127
|
+
logger: logging.Logger, data: dict, parent: "HWModule"
|
|
128
|
+
) -> list["Device"]:
|
|
129
|
+
abort = parent.abort
|
|
91
130
|
|
|
92
|
-
|
|
131
|
+
module_schema.validate(data)
|
|
132
|
+
|
|
133
|
+
children = data.pop("children", None)
|
|
134
|
+
if not children:
|
|
135
|
+
return []
|
|
136
|
+
|
|
137
|
+
devices = []
|
|
138
|
+
for child in children:
|
|
139
|
+
try:
|
|
140
|
+
logger.debug(
|
|
141
|
+
colored(f"Importing top level device {pformat(child)}", "green")
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
node = import_board(logger, child, parent=parent, abort=abort)
|
|
145
|
+
devices.append(node)
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logger.error(
|
|
148
|
+
colored(
|
|
149
|
+
f"Failed to import top-level device {pformat(child)}: {e}", "red"
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
logger.error(colored("Aborting." if abort else "Continuing anyway", "red"))
|
|
153
|
+
if abort:
|
|
154
|
+
raise
|
|
155
|
+
|
|
156
|
+
return devices
|
ekfsm/devices/__init__.py
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
from ekfsm.devices.generic import Device
|
|
2
1
|
from ekfsm.devices.coretemp import CoreTemp
|
|
2
|
+
from ekfsm.devices.generic import Device
|
|
3
3
|
from ekfsm.devices.smbios import SMBIOS
|
|
4
|
-
from .
|
|
5
|
-
|
|
6
|
-
from .
|
|
7
|
-
from .ekf_sur_led import EKFSurLed
|
|
4
|
+
from ekfsm.devices.thermal_humidity import ThermalHumidity
|
|
5
|
+
|
|
6
|
+
from .eeprom import EEPROM, EKF_CCU_EEPROM, EKF_EEPROM
|
|
8
7
|
from .ekf_ccu_uc import EKFCcuUc
|
|
8
|
+
from .ekf_sur_led import EKFSurLed
|
|
9
|
+
from .gpio import GPIO, EKFIdentificationIOExpander, GPIOExpander
|
|
9
10
|
from .iio_thermal_humidity import IIOThermalHumidity
|
|
10
11
|
from .mux import I2CMux, MuxChannel
|
|
12
|
+
from .pmbus import PMBus, PSUStatus
|
|
13
|
+
from .io4edge import IO4Edge, GPIOArray
|
|
14
|
+
from .pixelDisplay import PixelDisplay
|
|
15
|
+
from .buttons import ButtonArray
|
|
16
|
+
from .buttons import Button
|
|
17
|
+
from .colorLed import ColorLED
|
|
18
|
+
from .ledArray import LEDArray
|
|
19
|
+
from .watchdog import Watchdog
|
|
20
|
+
from .toggles import BinaryToggle
|
|
11
21
|
|
|
12
22
|
CLASS_MAP = {
|
|
13
23
|
"GenericDevice": Device,
|
|
@@ -20,10 +30,20 @@ CLASS_MAP = {
|
|
|
20
30
|
"EKF_EEPROM": EKF_EEPROM,
|
|
21
31
|
"EKF_CCU_EEPROM": EKF_CCU_EEPROM,
|
|
22
32
|
"EKFCcuUc": EKFCcuUc,
|
|
23
|
-
"
|
|
24
|
-
"
|
|
33
|
+
"PMBus": PMBus,
|
|
34
|
+
"PSUStatus": PSUStatus,
|
|
25
35
|
"SMBIOS": SMBIOS,
|
|
26
36
|
"HWMON": CoreTemp,
|
|
27
37
|
"EKFSurLed": EKFSurLed,
|
|
28
38
|
"IIOThermalHumidity": IIOThermalHumidity,
|
|
39
|
+
"ThermalHumidity": ThermalHumidity,
|
|
40
|
+
"IO4Edge": IO4Edge,
|
|
41
|
+
"PixelDisplay": PixelDisplay,
|
|
42
|
+
"ButtonArray": ButtonArray,
|
|
43
|
+
"Button": Button,
|
|
44
|
+
"ColorLED": ColorLED,
|
|
45
|
+
"LEDArray": LEDArray,
|
|
46
|
+
"Watchdog": Watchdog,
|
|
47
|
+
"GPIOArray": GPIOArray,
|
|
48
|
+
"BinaryToggle": BinaryToggle,
|
|
29
49
|
}
|