ekfsm 0.11.0b1.post3__py3-none-any.whl → 0.13.0a160.post4__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/ekf/ccu.yaml +2 -0
- ekfsm/boards/oem/ekf/se5-club.yaml +41 -0
- ekfsm/boards/oem/ekf/sn4-djembe.yaml +41 -0
- ekfsm/boards/oem/ekf/sq3-quartet.yaml +41 -0
- ekfsm/boards/oem/hitron/{hdrc-300.yaml → hdrc-300s.yaml} +6 -2
- ekfsm/cli.py +6 -1
- ekfsm/config.py +1 -0
- ekfsm/core/components.py +19 -7
- ekfsm/core/utils.py +26 -11
- ekfsm/devices/__init__.py +4 -3
- ekfsm/devices/{hwmon.py → coretemp.py} +8 -6
- ekfsm/devices/eeprom.py +41 -4
- ekfsm/devices/ekf_ccu_uc.py +68 -2
- ekfsm/devices/ekf_sur_led.py +2 -2
- ekfsm/devices/generic.py +20 -15
- ekfsm/devices/gpio.py +8 -7
- ekfsm/devices/iio_thermal_humidity.py +2 -2
- ekfsm/devices/imu.py +14 -0
- ekfsm/devices/mux.py +3 -3
- ekfsm/devices/pmbus.py +196 -14
- ekfsm/devices/smbus.py +24 -0
- ekfsm/simctrl.py +5 -27
- ekfsm/system.py +46 -19
- ekfsm-0.13.0a160.post4.dist-info/METADATA +174 -0
- ekfsm-0.13.0a160.post4.dist-info/RECORD +44 -0
- ekfsm-0.11.0b1.post3.dist-info/METADATA +0 -86
- ekfsm-0.11.0b1.post3.dist-info/RECORD +0 -39
- {ekfsm-0.11.0b1.post3.dist-info → ekfsm-0.13.0a160.post4.dist-info}/WHEEL +0 -0
- {ekfsm-0.11.0b1.post3.dist-info → ekfsm-0.13.0a160.post4.dist-info}/entry_points.txt +0 -0
ekfsm/boards/oem/ekf/ccu.yaml
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
id: 64
|
|
2
|
+
name: "EKF SE5-CLUB"
|
|
3
|
+
slot_type: CPCI_S0_PER
|
|
4
|
+
children:
|
|
5
|
+
- device_type: I2CMux
|
|
6
|
+
name: "MUX"
|
|
7
|
+
addr: 0x70
|
|
8
|
+
slot_coding_mask: 0x07
|
|
9
|
+
children:
|
|
10
|
+
- device_type: MuxChannel
|
|
11
|
+
name: "CH00"
|
|
12
|
+
channel_id: 0
|
|
13
|
+
children:
|
|
14
|
+
- device_type: EKFIdentificationIOExpander
|
|
15
|
+
name: "GPIO"
|
|
16
|
+
addr: 0x3D
|
|
17
|
+
provides:
|
|
18
|
+
inventory:
|
|
19
|
+
- revision
|
|
20
|
+
- device_type: EKF_EEPROM
|
|
21
|
+
name: "EEPROM"
|
|
22
|
+
addr: 0x55
|
|
23
|
+
provides:
|
|
24
|
+
inventory:
|
|
25
|
+
- vendor
|
|
26
|
+
- serial
|
|
27
|
+
- model
|
|
28
|
+
- repaired_at
|
|
29
|
+
- manufactured_at
|
|
30
|
+
- device_type: MuxChannel
|
|
31
|
+
name: "CH01"
|
|
32
|
+
channel_id: 1
|
|
33
|
+
children:
|
|
34
|
+
- device_type: MuxChannel
|
|
35
|
+
name: "CH02"
|
|
36
|
+
channel_id: 2
|
|
37
|
+
children:
|
|
38
|
+
- device_type: MuxChannel
|
|
39
|
+
name: "CH03"
|
|
40
|
+
channel_id: 3
|
|
41
|
+
children:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
id: 61
|
|
2
|
+
name: "EKF SN4-DJEMBE"
|
|
3
|
+
slot_type: CPCI_S0_PER
|
|
4
|
+
children:
|
|
5
|
+
- device_type: I2CMux
|
|
6
|
+
name: "MUX"
|
|
7
|
+
addr: 0x70
|
|
8
|
+
slot_coding_mask: 0x07
|
|
9
|
+
children:
|
|
10
|
+
- device_type: MuxChannel
|
|
11
|
+
name: "CH00"
|
|
12
|
+
channel_id: 0
|
|
13
|
+
children:
|
|
14
|
+
- device_type: EKFIdentificationIOExpander
|
|
15
|
+
name: "GPIO"
|
|
16
|
+
addr: 0x3D
|
|
17
|
+
provides:
|
|
18
|
+
inventory:
|
|
19
|
+
- revision
|
|
20
|
+
- device_type: EKF_EEPROM
|
|
21
|
+
name: "EEPROM"
|
|
22
|
+
addr: 0x55
|
|
23
|
+
provides:
|
|
24
|
+
inventory:
|
|
25
|
+
- vendor
|
|
26
|
+
- serial
|
|
27
|
+
- model
|
|
28
|
+
- repaired_at
|
|
29
|
+
- manufactured_at
|
|
30
|
+
- device_type: MuxChannel
|
|
31
|
+
name: "CH01"
|
|
32
|
+
channel_id: 1
|
|
33
|
+
children:
|
|
34
|
+
- device_type: MuxChannel
|
|
35
|
+
name: "CH02"
|
|
36
|
+
channel_id: 2
|
|
37
|
+
children:
|
|
38
|
+
- device_type: MuxChannel
|
|
39
|
+
name: "CH03"
|
|
40
|
+
channel_id: 3
|
|
41
|
+
children:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
id: 69
|
|
2
|
+
name: "EKF SQ3-QUARTET"
|
|
3
|
+
slot_type: CPCI_S0_PER
|
|
4
|
+
children:
|
|
5
|
+
- device_type: I2CMux
|
|
6
|
+
name: "MUX"
|
|
7
|
+
addr: 0x70
|
|
8
|
+
slot_coding_mask: 0x07
|
|
9
|
+
children:
|
|
10
|
+
- device_type: MuxChannel
|
|
11
|
+
name: "CH00"
|
|
12
|
+
channel_id: 0
|
|
13
|
+
children:
|
|
14
|
+
- device_type: EKFIdentificationIOExpander
|
|
15
|
+
name: "GPIO"
|
|
16
|
+
addr: 0x3D
|
|
17
|
+
provides:
|
|
18
|
+
inventory:
|
|
19
|
+
- revision
|
|
20
|
+
- device_type: EKF_EEPROM
|
|
21
|
+
name: "EEPROM"
|
|
22
|
+
addr: 0x55
|
|
23
|
+
provides:
|
|
24
|
+
inventory:
|
|
25
|
+
- vendor
|
|
26
|
+
- serial
|
|
27
|
+
- model
|
|
28
|
+
- repaired_at
|
|
29
|
+
- manufactured_at
|
|
30
|
+
- device_type: MuxChannel
|
|
31
|
+
name: "CH01"
|
|
32
|
+
channel_id: 1
|
|
33
|
+
children:
|
|
34
|
+
- device_type: MuxChannel
|
|
35
|
+
name: "CH02"
|
|
36
|
+
channel_id: 2
|
|
37
|
+
children:
|
|
38
|
+
- device_type: MuxChannel
|
|
39
|
+
name: "CH03"
|
|
40
|
+
channel_id: 3
|
|
41
|
+
children:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
id:
|
|
2
|
-
name: "
|
|
1
|
+
id: HDRC300S-110J-D120E(N)
|
|
2
|
+
name: "Hitron HDRC-300S"
|
|
3
3
|
slot_type: CPCI_S0_PSU
|
|
4
4
|
children:
|
|
5
5
|
- device_type: PmBus
|
|
@@ -15,6 +15,10 @@ children:
|
|
|
15
15
|
main:
|
|
16
16
|
- voltage: in1_input
|
|
17
17
|
- current: curr1_input
|
|
18
|
+
- status: status0_input
|
|
18
19
|
sby:
|
|
19
20
|
- voltage: in2_input
|
|
20
21
|
- current: curr2_input
|
|
22
|
+
- status: status1_input
|
|
23
|
+
th:
|
|
24
|
+
- temperature: temp1_input
|
ekfsm/cli.py
CHANGED
|
@@ -75,9 +75,12 @@ def cli(verbose, debug, sysfs, config):
|
|
|
75
75
|
@click.option("--revision", "-r", is_flag=False, help="Write chassis revision")
|
|
76
76
|
@click.option("--model", "-m", is_flag=False, help="Write chassis model")
|
|
77
77
|
@click.option("--custom", "-c", is_flag=False, help="Write chassis custom information")
|
|
78
|
-
|
|
78
|
+
@click.option("--version", "-v", is_flag=True, help="Write schema version")
|
|
79
|
+
def write(serial, unit, vendor, revision, model, custom, version):
|
|
79
80
|
"""Write data to the system"""
|
|
80
81
|
chassis = sm.ccu.chassis_inventory
|
|
82
|
+
eeprom = sm.ccu.mux.ch00.eeprom
|
|
83
|
+
|
|
81
84
|
if serial:
|
|
82
85
|
chassis.write_serial(serial)
|
|
83
86
|
if unit:
|
|
@@ -90,6 +93,8 @@ def write(serial, unit, vendor, revision, model, custom):
|
|
|
90
93
|
chassis.write_model(model)
|
|
91
94
|
if custom:
|
|
92
95
|
chassis.write_customer_area(custom)
|
|
96
|
+
if version:
|
|
97
|
+
eeprom.write_version(version)
|
|
93
98
|
|
|
94
99
|
|
|
95
100
|
@cli.command()
|
ekfsm/config.py
CHANGED
ekfsm/core/components.py
CHANGED
|
@@ -11,16 +11,17 @@ if TYPE_CHECKING:
|
|
|
11
11
|
from .slots import Slot
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class SysTree(NodeMixin):
|
|
15
15
|
"""
|
|
16
16
|
Base class for all system components including Hardware Modules and Devices.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
def __init__(self, name: str):
|
|
19
|
+
def __init__(self, name: str, abort: bool = False) -> None:
|
|
20
20
|
from ekfsm.log import ekfsm_logger
|
|
21
21
|
|
|
22
22
|
self.logger = ekfsm_logger(name)
|
|
23
23
|
self.name = name
|
|
24
|
+
self.abort = abort
|
|
24
25
|
|
|
25
26
|
def _render_tree(self) -> str:
|
|
26
27
|
output = ""
|
|
@@ -35,18 +36,26 @@ class SystemComponent(NodeMixin):
|
|
|
35
36
|
print(self)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
class HwModule(
|
|
39
|
+
class HwModule(SysTree):
|
|
39
40
|
"""
|
|
40
41
|
A HwModule represents an instantiation of a specifc hw board type,
|
|
41
42
|
for example an instance of an EKF SC9 board.
|
|
42
43
|
"""
|
|
43
44
|
|
|
44
|
-
def __init__(
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
instance_name: str,
|
|
48
|
+
config: dict,
|
|
49
|
+
slot: Slot,
|
|
50
|
+
abort: bool = False,
|
|
51
|
+
*args,
|
|
52
|
+
**kwargs,
|
|
53
|
+
) -> None:
|
|
45
54
|
from ekfsm.core.utils import deserialize_hardware_tree
|
|
46
55
|
|
|
47
56
|
from .slots import SlotType
|
|
48
57
|
|
|
49
|
-
super().__init__(instance_name)
|
|
58
|
+
super().__init__(instance_name, abort=abort)
|
|
50
59
|
self._slot: Slot = slot
|
|
51
60
|
self.config = config
|
|
52
61
|
|
|
@@ -90,8 +99,11 @@ class HwModule(SystemComponent):
|
|
|
90
99
|
|
|
91
100
|
nodes = findall(self, lambda node: isinstance(node, ProbeableDevice))
|
|
92
101
|
for node in nodes:
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
try:
|
|
103
|
+
if node.probe(*args, **kwargs):
|
|
104
|
+
return True
|
|
105
|
+
except Exception as e:
|
|
106
|
+
self.logger.error(f"Error probing {node}: {e}")
|
|
95
107
|
|
|
96
108
|
return False
|
|
97
109
|
|
ekfsm/core/utils.py
CHANGED
|
@@ -16,11 +16,11 @@ class BoardDictImporter:
|
|
|
16
16
|
def __init__(self, nodecls=AnyNode):
|
|
17
17
|
self.nodecls = nodecls
|
|
18
18
|
|
|
19
|
-
def import_(self, logger: logging.Logger, data, parent=None):
|
|
19
|
+
def import_(self, logger: logging.Logger, data, parent=None, abort: bool = False):
|
|
20
20
|
"""Import tree from `data`."""
|
|
21
|
-
return self.__import(logger, data, parent=parent)
|
|
21
|
+
return self.__import(logger, data, parent=parent, abort=abort)
|
|
22
22
|
|
|
23
|
-
def __import(self, logger: logging.Logger, data, parent=None):
|
|
23
|
+
def __import(self, logger: logging.Logger, data, parent=None, abort: bool = False):
|
|
24
24
|
from .components import HwModule
|
|
25
25
|
|
|
26
26
|
device_type = data.get("device_type")
|
|
@@ -30,6 +30,7 @@ class BoardDictImporter:
|
|
|
30
30
|
|
|
31
31
|
children = data.pop("children", [])
|
|
32
32
|
if parent is not None and isinstance(parent, HwModule):
|
|
33
|
+
# ???
|
|
33
34
|
pass
|
|
34
35
|
|
|
35
36
|
node = nodecls(parent=parent, **data)
|
|
@@ -38,11 +39,17 @@ class BoardDictImporter:
|
|
|
38
39
|
for child in children:
|
|
39
40
|
try:
|
|
40
41
|
logger.debug(f"Importing sub device {child}")
|
|
41
|
-
self.__import(logger, child, parent=node)
|
|
42
|
+
self.__import(logger, child, parent=node, abort=abort)
|
|
42
43
|
except Exception as e:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
+
)
|
|
46
53
|
return node
|
|
47
54
|
|
|
48
55
|
|
|
@@ -50,7 +57,9 @@ def deserialize_hardware_tree(
|
|
|
50
57
|
logger: logging.Logger, data: dict, parent: "HwModule"
|
|
51
58
|
) -> tuple[str, str, str, list["Device"]]:
|
|
52
59
|
importer = BoardDictImporter()
|
|
60
|
+
abort = parent.abort
|
|
53
61
|
|
|
62
|
+
# better use schema extension for this
|
|
54
63
|
id = data.pop("id", None)
|
|
55
64
|
if id is None:
|
|
56
65
|
raise ConfigError("Board configuration must contain `id`")
|
|
@@ -67,11 +76,17 @@ def deserialize_hardware_tree(
|
|
|
67
76
|
for child in children:
|
|
68
77
|
try:
|
|
69
78
|
logger.debug(f"Importing top level device {child}")
|
|
70
|
-
node = importer.import_(logger, child, parent=parent)
|
|
79
|
+
node = importer.import_(logger, child, parent=parent, abort=abort)
|
|
71
80
|
devices.append(node)
|
|
72
81
|
except Exception as e:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
if abort:
|
|
83
|
+
logger.error(
|
|
84
|
+
f"Failed to import top level device {child}: {e}. aborting"
|
|
85
|
+
)
|
|
86
|
+
raise e
|
|
87
|
+
else:
|
|
88
|
+
logger.error(
|
|
89
|
+
f"Failed to import top level device {child}: {e}. continue anyway"
|
|
90
|
+
)
|
|
76
91
|
|
|
77
92
|
return id, name, slot_type, devices
|
ekfsm/devices/__init__.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from ekfsm.devices.generic import Device
|
|
2
|
-
from ekfsm.devices.
|
|
2
|
+
from ekfsm.devices.coretemp import CoreTemp
|
|
3
3
|
from ekfsm.devices.smbios import SMBIOS
|
|
4
4
|
from .eeprom import EEPROM, EKF_EEPROM, EKF_CCU_EEPROM
|
|
5
|
-
from .pmbus import PmBus
|
|
5
|
+
from .pmbus import PmBus, PsuStatus
|
|
6
6
|
from .gpio import GPIO, EKFIdentificationIOExpander, GPIOExpander
|
|
7
7
|
from .ekf_sur_led import EKFSurLed
|
|
8
8
|
from .ekf_ccu_uc import EKFCcuUc
|
|
@@ -21,8 +21,9 @@ CLASS_MAP = {
|
|
|
21
21
|
"EKF_CCU_EEPROM": EKF_CCU_EEPROM,
|
|
22
22
|
"EKFCcuUc": EKFCcuUc,
|
|
23
23
|
"PmBus": PmBus,
|
|
24
|
+
"PsuStatus": PsuStatus,
|
|
24
25
|
"SMBIOS": SMBIOS,
|
|
25
|
-
"HWMON":
|
|
26
|
+
"HWMON": CoreTemp,
|
|
26
27
|
"EKFSurLed": EKFSurLed,
|
|
27
28
|
"IIOThermalHumidity": IIOThermalHumidity,
|
|
28
29
|
}
|
|
@@ -7,7 +7,7 @@ from ekfsm.core.sysfs import SYSFS_ROOT
|
|
|
7
7
|
from ekfsm.devices.generic import Device
|
|
8
8
|
|
|
9
9
|
# Path to the root of the HWMON sysfs filesystem
|
|
10
|
-
HWMON_ROOT = SYSFS_ROOT / Path(
|
|
10
|
+
HWMON_ROOT = SYSFS_ROOT / Path("class/hwmon")
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def find_core_temp_dir(hwmon_dir) -> Path:
|
|
@@ -24,19 +24,19 @@ def find_core_temp_dir(hwmon_dir) -> Path:
|
|
|
24
24
|
FileNotFoundError: If no coretemp directory is found
|
|
25
25
|
"""
|
|
26
26
|
# List all 'name' files in each subdirectory of hwmon_dir
|
|
27
|
-
name_files = glob.glob(os.path.join(hwmon_dir,
|
|
27
|
+
name_files = glob.glob(os.path.join(hwmon_dir, "*", "name"))
|
|
28
28
|
|
|
29
29
|
# Search for the file containing "coretemp"
|
|
30
30
|
for name_file in name_files:
|
|
31
|
-
with open(name_file,
|
|
32
|
-
if file.readline().strip() ==
|
|
31
|
+
with open(name_file, "r") as file:
|
|
32
|
+
if file.readline().strip() == "coretemp":
|
|
33
33
|
# Return the directory containing this file
|
|
34
34
|
return Path(os.path.dirname(name_file))
|
|
35
35
|
|
|
36
36
|
raise FileNotFoundError("No coretemp directory found")
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
class
|
|
39
|
+
class CoreTemp(Device):
|
|
40
40
|
"""
|
|
41
41
|
A class to represent the HWMON device.
|
|
42
42
|
|
|
@@ -55,7 +55,9 @@ class HWMON(Device):
|
|
|
55
55
|
):
|
|
56
56
|
from ekfsm.core.sysfs import SysFSDevice, SYSFS_ROOT
|
|
57
57
|
|
|
58
|
-
self.sysfs_device: SysFSDevice = SysFSDevice(
|
|
58
|
+
self.sysfs_device: SysFSDevice = SysFSDevice(
|
|
59
|
+
find_core_temp_dir(SYSFS_ROOT / Path("class/hwmon"))
|
|
60
|
+
)
|
|
59
61
|
|
|
60
62
|
super().__init__(name, parent, None, *args, **kwargs)
|
|
61
63
|
|
ekfsm/devices/eeprom.py
CHANGED
|
@@ -14,7 +14,7 @@ from datetime import date
|
|
|
14
14
|
from typing import Any, Callable, Literal, Sequence
|
|
15
15
|
from functools import wraps
|
|
16
16
|
|
|
17
|
-
from ekfsm.core.components import
|
|
17
|
+
from ekfsm.core.components import SysTree
|
|
18
18
|
from ekfsm.core.probe import ProbeableDevice
|
|
19
19
|
|
|
20
20
|
from .generic import Device
|
|
@@ -81,7 +81,7 @@ class EEPROM(Device):
|
|
|
81
81
|
def __init__(
|
|
82
82
|
self,
|
|
83
83
|
name: str,
|
|
84
|
-
parent:
|
|
84
|
+
parent: SysTree | None = None,
|
|
85
85
|
*args,
|
|
86
86
|
**kwargs,
|
|
87
87
|
):
|
|
@@ -740,7 +740,7 @@ class EKF_EEPROM(Validatable_EEPROM, ProbeableDevice):
|
|
|
740
740
|
return get_crc16_xmodem(self._data)
|
|
741
741
|
|
|
742
742
|
def probe(self, *args, **kwargs):
|
|
743
|
-
return self.
|
|
743
|
+
return self.hw_module.id == self.model()
|
|
744
744
|
|
|
745
745
|
|
|
746
746
|
class EKF_CCU_EEPROM(EKF_EEPROM):
|
|
@@ -764,7 +764,7 @@ class EKF_CCU_EEPROM(EKF_EEPROM):
|
|
|
764
764
|
_unit_length = 1
|
|
765
765
|
|
|
766
766
|
_customer_area_start = 190
|
|
767
|
-
_customer_area_length =
|
|
767
|
+
_customer_area_length = 63
|
|
768
768
|
|
|
769
769
|
def __init__(
|
|
770
770
|
self,
|
|
@@ -865,6 +865,7 @@ class EKF_CCU_EEPROM(EKF_EEPROM):
|
|
|
865
865
|
-------
|
|
866
866
|
The vendor of the chassis.
|
|
867
867
|
"""
|
|
868
|
+
|
|
868
869
|
return (
|
|
869
870
|
self._content[
|
|
870
871
|
self._cvendor_index_start : self._cvendor_index_start
|
|
@@ -1002,6 +1003,42 @@ class EKF_CCU_EEPROM(EKF_EEPROM):
|
|
|
1002
1003
|
unit = compute_int_from_bytes([area])
|
|
1003
1004
|
return unit
|
|
1004
1005
|
|
|
1006
|
+
@validated
|
|
1007
|
+
def version(self) -> int:
|
|
1008
|
+
"""
|
|
1009
|
+
Get the version of the EEPROM data scheme.
|
|
1010
|
+
|
|
1011
|
+
Note
|
|
1012
|
+
----
|
|
1013
|
+
If undefined, the version is set to 255 and then defaults to 0.
|
|
1014
|
+
|
|
1015
|
+
Returns
|
|
1016
|
+
-------
|
|
1017
|
+
The version of the EEPROM data scheme.
|
|
1018
|
+
"""
|
|
1019
|
+
version = self._content[self._ccrc_pos_start - 1]
|
|
1020
|
+
return version
|
|
1021
|
+
|
|
1022
|
+
def write_version(self, version: int) -> None:
|
|
1023
|
+
"""
|
|
1024
|
+
Write the version of the EEPROM data scheme.
|
|
1025
|
+
|
|
1026
|
+
Parameters
|
|
1027
|
+
----------
|
|
1028
|
+
version
|
|
1029
|
+
The version of the EEPROM data scheme.
|
|
1030
|
+
"""
|
|
1031
|
+
if version < 0 or version > 255:
|
|
1032
|
+
raise ValueError("Version must be between 0 and 255")
|
|
1033
|
+
|
|
1034
|
+
if version == 255:
|
|
1035
|
+
logger.warning("Version 255 is undefined, setting to 0")
|
|
1036
|
+
version = 0
|
|
1037
|
+
|
|
1038
|
+
version_bytes = version.to_bytes(1, byteorder="little")
|
|
1039
|
+
logger.info(f"Writing version {version}")
|
|
1040
|
+
self.write(version_bytes, self._ccrc_pos_start - 1)
|
|
1041
|
+
|
|
1005
1042
|
def write_unit(self, unit: int) -> None:
|
|
1006
1043
|
"""
|
|
1007
1044
|
Write the subsystem unit number.
|
ekfsm/devices/ekf_ccu_uc.py
CHANGED
|
@@ -2,8 +2,9 @@ from .generic import Device
|
|
|
2
2
|
from smbus2 import SMBus
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from typing import Tuple
|
|
5
|
-
from ekfsm.core.components import
|
|
5
|
+
from ekfsm.core.components import SysTree
|
|
6
6
|
from ..exceptions import AcquisitionError
|
|
7
|
+
from .imu import ImuSample
|
|
7
8
|
import struct
|
|
8
9
|
|
|
9
10
|
|
|
@@ -34,7 +35,7 @@ class EKFCcuUc(Device):
|
|
|
34
35
|
def __init__(
|
|
35
36
|
self,
|
|
36
37
|
name: str,
|
|
37
|
-
parent:
|
|
38
|
+
parent: SysTree | None,
|
|
38
39
|
*args,
|
|
39
40
|
**kwargs,
|
|
40
41
|
):
|
|
@@ -163,6 +164,68 @@ class EKFCcuUc(Device):
|
|
|
163
164
|
self._i2c_addr, CcuCommands.PUSH_TEMPERATURE.value, list(data)
|
|
164
165
|
)
|
|
165
166
|
|
|
167
|
+
def imu_sample(self) -> Tuple[ImuSample | None, bool]:
|
|
168
|
+
"""
|
|
169
|
+
Read the next IMU sample from the CCU's IMU sample FIFO.
|
|
170
|
+
|
|
171
|
+
If no sample is available, this method returns None.
|
|
172
|
+
The second return value indicates if more samples are available in the FIFO.
|
|
173
|
+
|
|
174
|
+
The CCU periodically samples the accelerometer and gyroscope data from the IMU and
|
|
175
|
+
places it into a FIFO of 256 entries.
|
|
176
|
+
Application must periodically read the samples from the FIFO to avoid overflow.
|
|
177
|
+
|
|
178
|
+
FIFO overflow is indicated in the sample by the `lost` attribute.
|
|
179
|
+
|
|
180
|
+
Note that the x, y, and z axes of the accelerometer and gyroscope
|
|
181
|
+
are aligned to the mounting of the IMU on the CCU board. Please correct the axes if necessary
|
|
182
|
+
to match the orientation of the IMU in your application.
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
Tuple[ImuSample | None, bool]
|
|
187
|
+
The IMU sample (or None) and a flag indicating if more samples are available in the FIFO.
|
|
188
|
+
"""
|
|
189
|
+
more_samples = False
|
|
190
|
+
_data = self._smbus.read_block_data(
|
|
191
|
+
self._i2c_addr, CcuCommands.IMU_SAMPLES.value
|
|
192
|
+
)
|
|
193
|
+
data = bytes(_data)
|
|
194
|
+
if len(data) < 14:
|
|
195
|
+
return None, False # No data available
|
|
196
|
+
diag, fsr, acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z = struct.unpack(
|
|
197
|
+
"<BBhhhhhh", data
|
|
198
|
+
)
|
|
199
|
+
imu_data = ImuSample(
|
|
200
|
+
[
|
|
201
|
+
self._scale_imu_accel(acc_x, fsr),
|
|
202
|
+
self._scale_imu_accel(acc_y, fsr),
|
|
203
|
+
self._scale_imu_accel(acc_z, fsr),
|
|
204
|
+
],
|
|
205
|
+
[
|
|
206
|
+
self._scale_imu_gyro(gyro_x, fsr),
|
|
207
|
+
self._scale_imu_gyro(gyro_y, fsr),
|
|
208
|
+
self._scale_imu_gyro(gyro_z, fsr),
|
|
209
|
+
],
|
|
210
|
+
True if diag & 1 else False,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
more_samples = True if (diag & 2 != 0) else False
|
|
214
|
+
|
|
215
|
+
return imu_data, more_samples
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def _scale_imu_accel(val: int, fsr: int) -> float:
|
|
219
|
+
fsr = fsr & 0xF
|
|
220
|
+
scale = 16 / (1 << fsr)
|
|
221
|
+
return val * (scale / 32768) * 9.80665 # convert to m/s^2
|
|
222
|
+
|
|
223
|
+
@staticmethod
|
|
224
|
+
def _scale_imu_gyro(val: int, fsr: int) -> float:
|
|
225
|
+
fsr = fsr >> 4 & 0xF
|
|
226
|
+
scale = 2000 / (1 << fsr)
|
|
227
|
+
return val * (scale / 32768)
|
|
228
|
+
|
|
166
229
|
def sw_shutdown(self) -> None:
|
|
167
230
|
"""
|
|
168
231
|
Tell CCU that the system is going to shutdown.
|
|
@@ -316,6 +379,9 @@ class EKFCcuUc(Device):
|
|
|
316
379
|
chunk = self._get_parameterset_chunk(begin)
|
|
317
380
|
if len(chunk) < 32:
|
|
318
381
|
break
|
|
382
|
+
# if chunk ends with zero byte, remove it (workaround for I2C slave bug)
|
|
383
|
+
if chunk[-1] == 0:
|
|
384
|
+
chunk = chunk[:-1]
|
|
319
385
|
json += chunk
|
|
320
386
|
begin = False
|
|
321
387
|
return json.decode("utf-8")
|
ekfsm/devices/ekf_sur_led.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .gpio import GPIOExpander
|
|
2
|
-
from ekfsm.core.components import
|
|
2
|
+
from ekfsm.core.components import SysTree
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class EKFSurLed(GPIOExpander):
|
|
@@ -10,7 +10,7 @@ class EKFSurLed(GPIOExpander):
|
|
|
10
10
|
def __init__(
|
|
11
11
|
self,
|
|
12
12
|
name: str,
|
|
13
|
-
parent:
|
|
13
|
+
parent: SysTree | None,
|
|
14
14
|
*args,
|
|
15
15
|
**kwargs,
|
|
16
16
|
):
|
ekfsm/devices/generic.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
from munch import Munch
|
|
3
|
-
from ekfsm.core.components import
|
|
3
|
+
from ekfsm.core.components import SysTree
|
|
4
4
|
from ekfsm.core.sysfs import SysFSDevice, sysfs_root
|
|
5
5
|
from ekfsm.exceptions import ConfigError
|
|
6
6
|
from pathlib import Path
|
|
@@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
|
|
9
9
|
from ekfsm.core.components import HwModule
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class Device(
|
|
12
|
+
class Device(SysTree):
|
|
13
13
|
"""
|
|
14
14
|
A generic device.
|
|
15
15
|
"""
|
|
@@ -17,12 +17,13 @@ class Device(SystemComponent):
|
|
|
17
17
|
def __init__(
|
|
18
18
|
self,
|
|
19
19
|
name: str,
|
|
20
|
-
parent:
|
|
20
|
+
parent: SysTree | None = None,
|
|
21
21
|
children: list["Device"] | None = None,
|
|
22
|
+
abort: bool = False,
|
|
22
23
|
*args,
|
|
23
|
-
**kwargs
|
|
24
|
+
**kwargs,
|
|
24
25
|
):
|
|
25
|
-
super().__init__(name)
|
|
26
|
+
super().__init__(name, abort=abort)
|
|
26
27
|
self.parent = parent
|
|
27
28
|
self.device_args = kwargs
|
|
28
29
|
self.logger.debug(f"Device: {name} {kwargs}")
|
|
@@ -30,21 +31,21 @@ class Device(SystemComponent):
|
|
|
30
31
|
if children:
|
|
31
32
|
self.children = children
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
# needs to be set during init because root will be changed after tree is complete
|
|
35
|
+
self.hw_module = self.root
|
|
36
|
+
|
|
37
|
+
# i2c initialization
|
|
38
|
+
if not hasattr(self, "sysfs_device") or self.sysfs_device is None:
|
|
34
39
|
self.sysfs_device: SysFSDevice | None = None
|
|
35
40
|
|
|
41
|
+
# post init
|
|
36
42
|
self._provides_attrs = kwargs.get("provides", {})
|
|
37
|
-
|
|
38
43
|
self.provides = self.__post_init__(Munch(self._provides_attrs))
|
|
39
44
|
|
|
40
45
|
def __post_init__(self, provides: Munch) -> Munch:
|
|
41
|
-
return self.__init_dynamic_attrs__(provides)
|
|
42
|
-
|
|
43
|
-
def __init_dynamic_attrs__(self, provides: Munch) -> Munch:
|
|
44
|
-
|
|
45
46
|
for key, fields in provides.items():
|
|
46
47
|
if isinstance(fields, dict):
|
|
47
|
-
provides[key] = self.
|
|
48
|
+
provides[key] = self.__post_init__(Munch(fields))
|
|
48
49
|
elif isinstance(fields, list | str):
|
|
49
50
|
provides[key] = Munch()
|
|
50
51
|
|
|
@@ -91,14 +92,18 @@ class Device(SystemComponent):
|
|
|
91
92
|
return None
|
|
92
93
|
|
|
93
94
|
@property
|
|
94
|
-
def hw_module(self) ->
|
|
95
|
+
def hw_module(self) -> "HwModule":
|
|
95
96
|
from ekfsm.core.components import HwModule
|
|
96
97
|
|
|
97
|
-
if isinstance(self.
|
|
98
|
-
return self.
|
|
98
|
+
if isinstance(self._hw_module, HwModule):
|
|
99
|
+
return self._hw_module
|
|
99
100
|
else:
|
|
100
101
|
raise RuntimeError("Device is not a child of HwModule")
|
|
101
102
|
|
|
103
|
+
@hw_module.setter
|
|
104
|
+
def hw_module(self, hw_module: "HwModule") -> None:
|
|
105
|
+
self._hw_module = hw_module
|
|
106
|
+
|
|
102
107
|
def get_i2c_chip_addr(self) -> int:
|
|
103
108
|
assert self.parent is not None
|
|
104
109
|
|