ekfsm 0.12.0.post1__py3-none-any.whl → 0.13.0a168.post1__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/devices/pmbus.py CHANGED
@@ -1,18 +1,100 @@
1
+ from enum import IntFlag
1
2
  from pathlib import Path
2
3
 
3
- from ekfsm.core.components import SystemComponent
4
+ from ekfsm.core.components import SysTree
4
5
 
5
- from ..core.sysfs import SysFSDevice
6
+ from ..core.sysfs import SysFSDevice, sysfs_root
6
7
 
7
8
  from .generic import Device
8
9
  from ..core.probe import ProbeableDevice
9
10
 
11
+ from time import sleep
12
+ from functools import wraps
13
+ from ekfsm.log import ekfsm_logger
14
+ from threading import Lock
15
+
16
+ __all__ = ["PsuStatus", "PmBus", "retry"]
17
+
18
+ logger = ekfsm_logger(__name__)
19
+
20
+
21
+ def retry(max_attempts=5, delay=0.5):
22
+ """
23
+ Retry decorator.
24
+
25
+ Decorator that retries a function a number of times before giving up.
26
+
27
+ This is useful for functions that may fail due to transient errors.
28
+
29
+ Note
30
+ ----
31
+ This is needed for certain PMBus commands that may fail due to transient errors
32
+ because page switching timing is not effectively handled by older kernel versions.
33
+
34
+ Important
35
+ ---------
36
+ This decorator is thread-safe, meaning a read attempt is atomic and cannot
37
+ be interupted by scheduler.
38
+
39
+ Parameters
40
+ ----------
41
+ max_attempts
42
+ The maximum number of attempts before giving up.
43
+ delay
44
+ The delay in seconds between attempts.
45
+ """
46
+
47
+ lock = Lock()
48
+
49
+ def decorator(func):
50
+ @wraps(func)
51
+ def wrapper(*args, **kwargs):
52
+ attempts = 0
53
+ while attempts < max_attempts:
54
+ with lock:
55
+ try:
56
+ return func(*args, **kwargs)
57
+ except Exception as e:
58
+ attempts += 1
59
+ if attempts == max_attempts:
60
+ logger.exception(
61
+ f"Failed to execute {func.__name__} after {max_attempts} attempts: {e}"
62
+ )
63
+ raise e
64
+ logger.info(
65
+ f"Retrying execution of {func.__name__} in {delay}s..."
66
+ )
67
+ sleep(delay)
68
+
69
+ return wrapper
70
+
71
+ return decorator
72
+
73
+
74
+ class PsuStatus(IntFlag):
75
+ """
76
+ Represents the status of a PSU according to STATUS_BYTE register.
77
+
78
+ See Also
79
+ --------
80
+ `PMBus Power System Management Protocol Specification - Part II - Revision 1.4, Fig. 60 <https://pmbus.org/>`_
81
+ """
82
+
83
+ OUTPUT_OVERVOLTAGE = 0x20
84
+ OUTPUT_OVERCURRENT = 0x10
85
+ INPUT_UNDERVOLTAGE = 0x08
86
+ TEMP_ANORMALY = 0x04
87
+ COMMUNICATION_ERROR = 0x02
88
+ ERROR = 0x01
89
+ OK = 0x00
90
+
10
91
 
11
92
  class PmBus(Device, ProbeableDevice):
93
+
12
94
  def __init__(
13
95
  self,
14
96
  name: str,
15
- parent: SystemComponent | None = None,
97
+ parent: SysTree | None = None,
16
98
  children: list[Device] | None = None,
17
99
  *args,
18
100
  **kwargs,
@@ -23,43 +105,143 @@ class PmBus(Device, ProbeableDevice):
23
105
 
24
106
  files = list(Path(self.sysfs_device.path).rglob("hwmon/*/in1_input"))
25
107
  if len(files) == 0:
26
- raise FileNotFoundError("No HWMON entries found")
108
+ raise FileNotFoundError("No HWMON entries found in sysfs")
27
109
  self.hwmon_sysfs = SysFSDevice(files[0].parent)
28
110
 
111
+ self.debugfs_root = sysfs_root() / "kernel/debug/pmbus"
112
+ files = list(self.debugfs_root.rglob("hwmon*/status*_input"))
113
+ if len(files) == 0:
114
+ raise FileNotFoundError("No HWMON entries found in debugfs")
115
+ self.hwmon_debugfs = SysFSDevice(files[0].parent)
116
+
29
117
  def probe(self, *args, **kwargs) -> bool:
30
118
  from ekfsm.core import HwModule
31
119
 
32
- assert isinstance(self.root, HwModule)
33
- return self.root.id == self.model()
120
+ assert isinstance(self.hw_module, HwModule)
121
+ return self.hw_module.id == self.model()
34
122
 
35
123
  # Voltage and Current Interfaces
36
- def _in_conversion(self, in_file: str) -> float:
37
- return float(self.hwmon_sysfs.read_attr_utf8(in_file)) / 1000.0
38
-
39
- def _current_conversion(self, in_file: str) -> float:
124
+ def _conversion(self, in_file: str) -> float:
40
125
  return float(self.hwmon_sysfs.read_attr_utf8(in_file)) / 1000.0
41
126
 
127
+ @retry()
42
128
  def in1_input(self) -> float:
43
- return self._in_conversion("in1_input")
129
+ """
130
+ Get input voltage of PSU page 1.
44
131
 
132
+ Returns
133
+ -------
134
+ Input voltage in volts
135
+ """
136
+ return self._conversion("in1_input")
137
+
138
+ @retry()
45
139
  def in2_input(self) -> float:
46
- return self._in_conversion("in2_input")
140
+ """
141
+ Get input voltage of PSU page 2.
142
+
143
+ Returns
144
+ -------
145
+ Input voltage in volts
146
+ """
147
+ return self._conversion("in2_input")
47
148
 
149
+ @retry()
48
150
  def curr1_input(self) -> float:
49
- return self._current_conversion("curr1_input")
151
+ """
152
+ Get input current of PSU page 1.
50
153
 
154
+ Returns
155
+ -------
156
+ Input current in amperes
157
+ """
158
+ return self._conversion("curr1_input")
159
+
160
+ @retry()
51
161
  def curr2_input(self) -> float:
52
- return self._current_conversion("curr2_input")
162
+ """
163
+ Get input current of PSU page 2.
164
+
165
+ Returns
166
+ -------
167
+ Input current in amperes
168
+ """
169
+ return self._conversion("curr2_input")
170
+
171
+ # Status Interface
172
+ @retry()
173
+ def status0_input(self) -> PsuStatus:
174
+ """
175
+ Get the status of PSU page 1.
176
+
177
+ Returns
178
+ -------
179
+ PSU status as defined in PsuStatus
180
+ """
181
+ status = int(self.hwmon_debugfs.read_attr_utf8("status0_input").strip(), 16)
182
+ return PsuStatus(status)
183
+
184
+ @retry()
185
+ def status1_input(self) -> PsuStatus:
186
+ """
187
+ Get the status of PSU page 2.
188
+
189
+ Returns
190
+ -------
191
+ PSU status as defined in PsuStatus
192
+ """
193
+ status = int(self.hwmon_debugfs.read_attr_utf8("status1_input").strip(), 16)
194
+ return PsuStatus(status)
195
+
196
+ # Temperature Interface
197
+ @retry()
198
+ def temp1_input(self) -> float:
199
+ """
200
+ Get the PSU temperature.
201
+
202
+ Returns
203
+ -------
204
+ PSU temperature in degrees celsius
205
+ """
206
+ return self._conversion("temp1_input")
53
207
 
54
208
  # Inventory Interface
55
209
  def vendor(self) -> str:
210
+ """
211
+ Get the vendor of the PSU.
212
+
213
+ Returns
214
+ -------
215
+ PSU vendor
216
+ """
56
217
  return self.hwmon_sysfs.read_attr_utf8("vendor").strip()
57
218
 
58
219
  def model(self) -> str:
220
+ """
221
+ Get the model of the PSU.
222
+
223
+ Returns
224
+ -------
225
+ PSU model
226
+ """
59
227
  return self.hwmon_sysfs.read_attr_utf8("model").strip()
60
228
 
61
229
  def serial(self) -> str:
230
+ """
231
+ Get the serial number of the PSU.
232
+
233
+ Returns
234
+ -------
235
+ PSU serial number
236
+ """
62
237
  return self.hwmon_sysfs.read_attr_utf8("serial").strip()
63
238
 
64
239
  def revision(self) -> str:
240
+ """
241
+ Get the revision of the PSU.
242
+
243
+ Returns
244
+ -------
245
+ PSU revision
246
+ """
65
247
  return self.hwmon_sysfs.read_attr_utf8("revision").strip()
ekfsm/devices/smbios.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
  from ekfsm.core.components import HwModule
3
- from ekfsm.core.sysfs import SysFSDevice, SYSFS_ROOT
3
+ from ekfsm.core.sysfs import SysFSDevice, sysfs_root
4
4
  from .generic import Device
5
5
 
6
6
 
@@ -22,7 +22,9 @@ class SMBIOS(Device):
22
22
  *args,
23
23
  **kwargs,
24
24
  ):
25
- self.sysfs_device: SysFSDevice = SysFSDevice(SYSFS_ROOT / Path("devices/virtual/dmi/id"))
25
+ self.sysfs_device: SysFSDevice = SysFSDevice(
26
+ sysfs_root() / Path("devices/virtual/dmi/id")
27
+ )
26
28
 
27
29
  super().__init__(name, parent, None, *args, **kwargs)
28
30
 
ekfsm/devices/smbus.py ADDED
@@ -0,0 +1,24 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import List
3
+
4
+
5
+ class SimSmbus(ABC):
6
+ @abstractmethod
7
+ def read_word_data(self, cmd: int) -> int:
8
+ pass
9
+
10
+ @abstractmethod
11
+ def read_block_data(self, cmd: int) -> List[int]:
12
+ pass
13
+
14
+ @abstractmethod
15
+ def write_block_data(self, cmd: int, data: List[int]):
16
+ pass
17
+
18
+ @abstractmethod
19
+ def write_byte(self, cmd: int):
20
+ pass
21
+
22
+ @abstractmethod
23
+ def write_word_data(self, cmd: int, data: int):
24
+ pass
ekfsm/simctrl.py CHANGED
@@ -1,42 +1,20 @@
1
- from abc import ABC, abstractmethod
2
1
  import socket
3
2
  import struct
4
3
  from unittest.mock import patch
5
4
  from pathlib import Path
6
5
 
6
+ from ekfsm.devices.smbus import SimSmbus
7
7
  from ekfsm.devices.gpio import EKFIdSimGpio
8
8
  from ekfsm.devices.gpio import SimGpio
9
9
  from .core.sysfs import set_sysfs_root
10
- from .core.components import SystemComponent
10
+ from .core.components import SysTree
11
11
 
12
12
  from .devices import GPIO
13
13
  from typing import List
14
14
  from smbus2 import SMBus
15
15
 
16
- GPIO_SIM_MAPPING = {}
17
- SMBUS_SIM_MAPPING = {}
18
-
19
-
20
- class SimSmbus(ABC):
21
- @abstractmethod
22
- def read_word_data(self, cmd: int) -> int:
23
- pass
24
-
25
- @abstractmethod
26
- def read_block_data(self, cmd: int) -> List[int]:
27
- pass
28
-
29
- @abstractmethod
30
- def write_block_data(self, cmd: int, data: List[int]):
31
- pass
32
-
33
- @abstractmethod
34
- def write_byte(self, cmd: int):
35
- pass
36
-
37
- @abstractmethod
38
- def write_word_data(self, cmd: int, data: int):
39
- pass
16
+ GPIO_SIM_MAPPING: dict[str, SimGpio] = {}
17
+ SMBUS_SIM_MAPPING: dict[str, SimSmbus] = {}
40
18
 
41
19
 
42
20
  def register_gpio_sim(major: int, minor: int, sim_gpio: SimGpio) -> None:
@@ -72,7 +50,7 @@ class GpioSimulator(GPIO):
72
50
  def __init__(
73
51
  self,
74
52
  name: str,
75
- parent: SystemComponent | None = None,
53
+ parent: SysTree | None = None,
76
54
  *args,
77
55
  **kwargs,
78
56
  ):
@@ -191,13 +169,16 @@ def enable_smbus_simulation():
191
169
  pm.start()
192
170
 
193
171
 
194
- def enable_simulation(sysfs_path: Path):
172
+ def enable_simulation(sysfs_path: Path | str) -> None:
195
173
  global GPIO_SIM_MAPPING
196
174
  GPIO_SIM_MAPPING = {}
197
175
 
198
176
  global SMBUS_SIM_MAPPING
199
177
  SMBUS_SIM_MAPPING = {}
200
178
 
179
+ if isinstance(sysfs_path, str):
180
+ sysfs_path = Path(sysfs_path)
181
+
201
182
  set_sysfs_root(sysfs_path)
202
183
  enable_gpio_simulation()
203
184
  enable_smbus_simulation()
ekfsm/system.py CHANGED
@@ -2,6 +2,7 @@ from typing import Tuple, Any, Generator
2
2
  from pathlib import Path
3
3
  from munch import Munch, munchify
4
4
 
5
+ from ekfsm.core.components import SysTree
5
6
  import yaml
6
7
 
7
8
  from .core.slots import Slot, SlotType
@@ -46,7 +47,7 @@ def all_board_cfg_files() -> Generator[Path, None, None]:
46
47
  yield item
47
48
 
48
49
 
49
- class System:
50
+ class System(SysTree):
50
51
  """
51
52
  A System represents a CPCI system.
52
53
 
@@ -94,21 +95,26 @@ class System:
94
95
  >>> print(b.name + b.slot.name) # Print the name of the board and the slot it is in
95
96
  """
96
97
 
97
- def __init__(self, config: Path) -> None:
98
+ def __init__(self, config: Path, abort: bool = False) -> None:
98
99
  """
99
100
  Parameters
100
101
  ----------
101
102
  config
102
103
  Path to the config that specifies the system and how the slots are filled.
103
104
  """
105
+ self.config_path = config
106
+ self.config = load_config(str(self.config_path))
107
+ self.name = self.config.system_config.name
108
+
109
+ super().__init__(self.name, abort=abort)
110
+
104
111
  self.logger = ekfsm_logger(__name__)
105
112
  self._init_system(config)
106
113
  self._init_slot_attrs()
114
+ self._aggregate_provider_functions()
115
+ self.children = self.boards
107
116
 
108
117
  def _init_system(self, config: Path):
109
- self.config_path = config
110
- self.config = load_config(str(self.config_path))
111
- self.name = self.config.system_config.name
112
118
  self.slots: Slots = Slots()
113
119
  self.boards: list[HwModule] = []
114
120
 
@@ -136,6 +142,18 @@ class System:
136
142
  for board in self.boards:
137
143
  setattr(self, board.instance_name.lower(), board)
138
144
 
145
+ def _aggregate_provider_functions(self):
146
+ if hasattr(self.config.system_config, "aggregates"):
147
+ agg = self.config.system_config.aggregates
148
+ if agg is not None:
149
+ for key, value in agg.items():
150
+ prv = Munch()
151
+ for board in self.boards:
152
+ if hasattr(board, key):
153
+ prv.update({value: getattr(board, key)})
154
+ if value in prv.keys():
155
+ setattr(self, value, prv[value])
156
+
139
157
  def reload(self):
140
158
  """
141
159
  Reload the current system configuration.
@@ -144,7 +162,7 @@ class System:
144
162
  ---------
145
163
  This will rebuild all system objects and reinitialize the system tree.
146
164
  """
147
- self._init_system(self.config_path)
165
+ self.__init__(self.config_path)
148
166
 
149
167
  def _create_master(self) -> Tuple[HwModule | None, int]:
150
168
  for i, slot in enumerate(self.config.system_config.slots):
@@ -190,10 +208,16 @@ class System:
190
208
  hwmod = self._create_hwmodule_from_cfg_file(slot, board_name, path)
191
209
 
192
210
  except Exception as e:
193
- self.logger.error(
194
- f"failed to create desired hwmodule {board_type} (as {board_name}): {e}. Leaving slot empty!"
195
- )
196
- return None, slot
211
+ if self.abort:
212
+ self.logger.error(
213
+ f"failed to create desired hwmodule {board_type} (as {board_name}): {e}. Aborting!"
214
+ )
215
+ raise e
216
+ else:
217
+ self.logger.error(
218
+ f"failed to create desired hwmodule {board_type} (as {board_name}): {e}. Leaving slot empty!"
219
+ )
220
+ return None, slot
197
221
 
198
222
  # try to probe desired board type
199
223
  if hwmod.probe():
@@ -211,6 +235,7 @@ class System:
211
235
  hwmod = self._create_hwmodule_from_cfg_file(slot, board_name, path)
212
236
  except ConfigError:
213
237
  # slot type not matching, ignore
238
+ # ??? should we log this?
214
239
  continue
215
240
  except Exception as e:
216
241
  self.logger.debug(
@@ -274,7 +299,15 @@ class System:
274
299
  f"Slot type mismatch for slot {slot.name}: {cfg.slot_type} != {slot.slot_type}"
275
300
  )
276
301
 
277
- return HwModule(instance_name=board_name, config=yaml_data, slot=slot)
302
+ hwmod = HwModule(
303
+ instance_name=board_name,
304
+ config=yaml_data,
305
+ slot=slot,
306
+ abort=self.abort,
307
+ parent=self,
308
+ )
309
+
310
+ return hwmod
278
311
 
279
312
  def get_module_in_slot(self, idx: int) -> HwModule | None:
280
313
  return next(
@@ -316,11 +349,5 @@ class System:
316
349
  f"'{type(self).__name__}' object has no board with name '{name}'"
317
350
  )
318
351
 
319
- def __str__(self) -> str:
320
- output = ""
321
- for b in self.boards:
322
- output += b._render_tree()
323
- return output
324
-
325
- def print(self) -> None:
326
- print(self)
352
+ def __repr__(self):
353
+ return f"System (name={self.name})"
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.4
2
+ Name: ekfsm
3
+ Version: 0.13.0a168.post1
4
+ Summary: The EKF System Management Library (ekfsm) is a sensor monitoring suite for Compact PCI Serial devices.
5
+ Author-email: Klaus Popp <klaus.popp@ci4rail.com>, Jan Jansen <jan@ekf.de>, Felix Päßler <fp@ekf.de>
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: anytree
8
+ Requires-Dist: click>=8.0.1
9
+ Requires-Dist: crcmod
10
+ Requires-Dist: gpiod>=2.1.0
11
+ Requires-Dist: hexdump
12
+ Requires-Dist: more-itertools
13
+ Requires-Dist: munch
14
+ Requires-Dist: smbus2
15
+ Requires-Dist: types-pyyaml>=6.0.12.20241230
16
+ Requires-Dist: yamale
17
+ Description-Content-Type: text/markdown
18
+
19
+ # ekfsm - EKF system management library
20
+
21
+ Provides a python library framework for access to system management functions on Linux based modular hardware systems,
22
+ such as CompactPCI-Serial systems.
23
+
24
+ ## Features
25
+
26
+ - System configuration via YAML configuration file
27
+ - Obtain inventory information of the system and its components
28
+ - Obtain sensor information, such as temperature, humidity, voltage, current, accelerometer, gyroscope, etc.
29
+ - Write and read EEPROM contents
30
+ - Access to system level functions, such as system LEDs, system fan, system power supply, etc.
31
+ - Supports simulation mode for development and testing
32
+ - Probing of desired boards in configured slots
33
+
34
+ ## Requirements
35
+
36
+ Prior to the use of I2C, PMBus or GPIO devices using the API, those devices have to be initialised by ACPI or manual device setup.
37
+
38
+ ### Example
39
+
40
+ In order to initialize an EEPROM of type AT24 behind a Mux channel 0, manualy add the device:
41
+
42
+ ```bash
43
+ cd /sys/bus/i2c/devices/0-0074/channel-0/
44
+ echo 24c02 0x55 >new_device
45
+ ```
46
+
47
+ Now we can access the EEPROM contents:
48
+
49
+ ```bash
50
+ hd 8-0055/eeprom
51
+ 00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
52
+ *
53
+ 00000100
54
+ ```
55
+
56
+
57
+ ## Installation
58
+
59
+ To install the package via pip, you have to use a virtual environment to ensure full operabilty.
60
+ *Note: CLI entrypoint script won't work if installed in the system store!*
61
+
62
+ ### Prepare virtual environment
63
+
64
+ First, name, create and activate your virtual environment (here `myvenv`):
65
+
66
+ ```bash
67
+ $ python -m venv myvenv
68
+ $ source myvenv/bin/activate
69
+ ```
70
+
71
+ ### Package install
72
+
73
+ Now install the ekfsm package and all dependencies from the [project pypi registry](https://gitlab.ekf.com/libs/apis/ekfsm/-/packages):
74
+
75
+ ```bash
76
+ (myvenv) $ pip install ekfsm --index-url https://gitlab.ekf.com/api/v4/projects/407/packages/pypi/simple
77
+ Looking in indexes: https://gitlab.ekf.com/api/v4/projects/407/packages/pypi/simple
78
+ Collecting ekfsm
79
+ Downloading https://gitlab.ekf.com/api/v4/projects/407/packages/pypi/files/e400ee46de9346c086ce708675977cc6ab080c8c016d360970c82d1c436f7c89/ekfsm-0.12.0-py3-none-any.whl (43 kB)
80
+ Collecting anytree (from ekfsm)
81
+ Using cached anytree-2.12.1-py3-none-any.whl.metadata (8.1 kB)
82
+ Collecting click>=8.0.1 (from ekfsm)
83
+ Using cached click-8.1.8-py3-none-any.whl.metadata (2.3 kB)
84
+ Collecting crcmod (from ekfsm)
85
+ Using cached crcmod-1.7-cp312-cp312-linux_x86_64.whl
86
+ Collecting gpiod>=2.1.0 (from ekfsm)
87
+ Using cached gpiod-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.1 kB)
88
+ Collecting hexdump (from ekfsm)
89
+ Using cached hexdump-3.3-py3-none-any.whl
90
+ Collecting more-itertools (from ekfsm)
91
+ Using cached more_itertools-10.6.0-py3-none-any.whl.metadata (37 kB)
92
+ Collecting munch (from ekfsm)
93
+ Using cached munch-4.0.0-py2.py3-none-any.whl.metadata (5.9 kB)
94
+ Collecting smbus2 (from ekfsm)
95
+ Using cached smbus2-0.5.0-py2.py3-none-any.whl.metadata (6.9 kB)
96
+ Collecting types-pyyaml>=6.0.12.20241230 (from ekfsm)
97
+ Using cached types_PyYAML-6.0.12.20241230-py3-none-any.whl.metadata (1.8 kB)
98
+ Collecting yamale (from ekfsm)
99
+ Using cached yamale-6.0.0-py3-none-any.whl.metadata (22 kB)
100
+ Collecting six (from anytree->ekfsm)
101
+ Using cached six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB)
102
+ Collecting pyyaml (from yamale->ekfsm)
103
+ Using cached PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)
104
+ Using cached click-8.1.8-py3-none-any.whl (98 kB)
105
+ Using cached gpiod-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (103 kB)
106
+ Using cached types_PyYAML-6.0.12.20241230-py3-none-any.whl (20 kB)
107
+ Using cached anytree-2.12.1-py3-none-any.whl (44 kB)
108
+ Using cached more_itertools-10.6.0-py3-none-any.whl (63 kB)
109
+ Using cached munch-4.0.0-py2.py3-none-any.whl (9.9 kB)
110
+ Using cached smbus2-0.5.0-py2.py3-none-any.whl (11 kB)
111
+ Using cached yamale-6.0.0-py3-none-any.whl (57 kB)
112
+ Using cached PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (767 kB)
113
+ Using cached six-1.17.0-py2.py3-none-any.whl (11 kB)
114
+ Installing collected packages: smbus2, hexdump, crcmod, types-pyyaml, six, pyyaml, munch, more-itertools, gpiod, click, yamale, anytree, ekfsm
115
+ Successfully installed anytree-2.12.1 click-8.1.8 crcmod-1.7 ekfsm-0.12.0 gpiod-2.3.0 hexdump-3.3 more-itertools-10.6.0 munch-4.0.0 pyyaml-6.0.2 six-1.17.0 smbus2-0.5.0 types-pyyaml-6.0.12.20241230 yamale-6.0.0
116
+ ```
117
+
118
+ ## Example Usage Scenario
119
+
120
+ To use the library for a desired system, it must be configured in a system config yaml file:
121
+
122
+ ```yaml
123
+ # Example config
124
+ system_config:
125
+ name: "Simple System"
126
+ slots:
127
+ - name: SYSTEM_SLOT
128
+ slot_type: CPCI_S0_SYS
129
+ desired_hwmodule_type: EKF SC9-Toccata
130
+ desired_hwmodule_name: CPU
131
+ attributes:
132
+ is_master: true
133
+ - name: SLOT1
134
+ slot_type: CPCI_S0_PER
135
+ desired_hwmodule_type: EKF SRF-SUR
136
+ desired_hwmodule_name: SER
137
+ attributes:
138
+ slot_coding: 0x1
139
+ ```
140
+
141
+ ### API
142
+
143
+ If you want to access the LEDs on the EKF SUR-UART, you can do the following:
144
+ ```python
145
+ import ekfsm
146
+
147
+ system = ekfsm.System("system.yaml")
148
+
149
+ # alternative ways to get the SUR HwModule
150
+ sur = system["SER"] # by using the hwmodule name as key
151
+ sur = system.ser # by using the hwmodule name as attribute
152
+ sur = system.slots["SLOT1"].hwmodule # by using the slot name as key
153
+ sur = system.slots.slot1.hwmodule # by using the slot name as attribute
154
+
155
+ # accessing the LED device
156
+ sur.led_a.set(0,"purple") # set the color of the LED to purple
157
+ ```
158
+
159
+ For further infos on all API aspects, please see the [API Reference](https://ekfsm.readthedocs.io/en/main/reference/index.html).
160
+
161
+ ### CLI
162
+
163
+ Upon activation of a venv provided with the ekfsm library, an entry point script `ekfsm-cli` is exported in the current shell.
164
+
165
+ See `ekfsm-cli -h` for a help on the usage.
166
+
167
+
168
+ ## Resources
169
+
170
+ [Documentation](https://ekfsm.readthedocs.io/en/main/)
171
+
172
+ [Source Code](https://gitlab.ekf.com/libs/apis/ekfsm)
173
+
174
+ [Developer Wiki](https://gitlab.ekf.com/libs/apis/ekfsm/-/wikis/home)