ekfsm 0.13.0a168.post1__py3-none-any.whl → 0.13.0a183.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/__init__.py CHANGED
@@ -3,6 +3,7 @@ from .system import System
3
3
  from .core import HwModule
4
4
  from .core.slots import SlotType
5
5
  from .exceptions import ConfigError
6
+ from .lock import locking_cleanup, locking_configure
6
7
 
7
8
  __all__ = (
8
9
  "System",
@@ -10,4 +11,6 @@ __all__ = (
10
11
  "HwModule",
11
12
  "Slot",
12
13
  "SlotType",
14
+ "locking_cleanup",
15
+ "locking_configure",
13
16
  )
@@ -1,4 +1,4 @@
1
- id: HDRC300S-110J-D120E(N)
1
+ id: HDRC300S.*
2
2
  name: "Hitron HDRC-300S"
3
3
  slot_type: CPCI_S0_PSU
4
4
  children:
@@ -4,6 +4,7 @@ from enum import Enum
4
4
  from typing import Tuple
5
5
  from ekfsm.core.components import SysTree
6
6
  from ..exceptions import AcquisitionError
7
+ from ..lock import Locker
7
8
  from .imu import ImuSample
8
9
  import struct
9
10
 
@@ -292,21 +293,18 @@ class EKFCcuUc(Device):
292
293
  progress_callback
293
294
  A callback function that is called with the current progress in bytes.
294
295
 
295
- Warning
296
- ---------
297
- Do not call this method at the same time from multiple threads or processes.
298
-
299
296
  """
300
- offset = 0
301
- max_chunk_len = 28
302
- while len(firmware) > 0:
303
- chunk, firmware = firmware[:max_chunk_len], firmware[max_chunk_len:]
304
- self._load_firmware_chunk(offset, len(firmware) == 0, chunk)
305
- offset += len(chunk)
306
- if len(firmware) != 0:
307
- self._nop()
308
- if progress_callback is not None:
309
- progress_callback(offset)
297
+ with Locker(self.name + "-load_firmware").lock():
298
+ offset = 0
299
+ max_chunk_len = 28
300
+ while len(firmware) > 0:
301
+ chunk, firmware = firmware[:max_chunk_len], firmware[max_chunk_len:]
302
+ self._load_firmware_chunk(offset, len(firmware) == 0, chunk)
303
+ offset += len(chunk)
304
+ if len(firmware) != 0:
305
+ self._nop()
306
+ if progress_callback is not None:
307
+ progress_callback(offset)
310
308
 
311
309
  def _load_firmware_chunk(self, offset: int, is_last: bool, data: bytes) -> None:
312
310
  if is_last:
@@ -369,22 +367,20 @@ class EKFCcuUc(Device):
369
367
  str
370
368
  The parameterset in JSON format.
371
369
 
372
- Warning
373
- ---------
374
- Do not call this method at the same time from multiple threads or processes.
375
370
  """
376
- json = b""
377
- begin = True
378
- while True:
379
- chunk = self._get_parameterset_chunk(begin)
380
- if len(chunk) < 32:
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]
385
- json += chunk
386
- begin = False
387
- return json.decode("utf-8")
371
+ with Locker(self.name + "-parameterset").lock():
372
+ json = b""
373
+ begin = True
374
+ while True:
375
+ chunk = self._get_parameterset_chunk(begin)
376
+ if len(chunk) < 32:
377
+ break
378
+ # if chunk ends with zero byte, remove it (workaround for I2C slave bug)
379
+ if chunk[-1] == 0:
380
+ chunk = chunk[:-1]
381
+ json += chunk
382
+ begin = False
383
+ return json.decode("utf-8")
388
384
 
389
385
  def _get_parameterset_chunk(self, begin: bool) -> bytes:
390
386
  data = self._smbus.read_block_data(
@@ -423,19 +419,16 @@ class EKFCcuUc(Device):
423
419
  _cfg
424
420
  The parameterset in JSON format.
425
421
 
426
- Warning
427
- ---------
428
- Do not call this method at the same time from multiple threads or processes.
429
-
430
422
  """
431
- cfg = _cfg.encode("utf-8")
432
- offset = 0
433
- max_chunk_len = 28
434
- while len(cfg) > 0:
435
- chunk, cfg = cfg[:max_chunk_len], cfg[max_chunk_len:]
436
- self._load_parameterset_chunk(offset, len(cfg) == 0, chunk)
437
- offset += len(chunk)
438
- self._nop()
423
+ with Locker(self.name + "-parameterset").lock():
424
+ cfg = _cfg.encode("utf-8")
425
+ offset = 0
426
+ max_chunk_len = 28
427
+ while len(cfg) > 0:
428
+ chunk, cfg = cfg[:max_chunk_len], cfg[max_chunk_len:]
429
+ self._load_parameterset_chunk(offset, len(cfg) == 0, chunk)
430
+ offset += len(chunk)
431
+ self._nop()
439
432
 
440
433
  def _load_parameterset_chunk(self, offset: int, is_last: bool, data: bytes) -> None:
441
434
  if is_last:
ekfsm/devices/pmbus.py CHANGED
@@ -12,6 +12,7 @@ from time import sleep
12
12
  from functools import wraps
13
13
  from ekfsm.log import ekfsm_logger
14
14
  from threading import Lock
15
+ import re
15
16
 
16
17
  __all__ = ["PsuStatus", "PmBus", "retry"]
17
18
 
@@ -118,7 +119,8 @@ class PmBus(Device, ProbeableDevice):
118
119
  from ekfsm.core import HwModule
119
120
 
120
121
  assert isinstance(self.hw_module, HwModule)
121
- return self.hw_module.id == self.model()
122
+ # compare the regexp from the board yaml file with the model
123
+ return re.match(self.hw_module.id, self.model()) is not None
122
124
 
123
125
  # Voltage and Current Interfaces
124
126
  def _conversion(self, in_file: str) -> float:
ekfsm/lock.py ADDED
@@ -0,0 +1,94 @@
1
+ import fcntl
2
+ import os
3
+ from pathlib import Path
4
+ from contextlib import contextmanager
5
+
6
+ #
7
+ # Some devices or device functions don't allow concurrent access.
8
+ # The locking mechanism is used to ensure that only one process/thread can
9
+ # access the device (function) at a time.
10
+ #
11
+ # Locking granularity is defined by the device.
12
+ # It may be at the device level or function level.
13
+ #
14
+ # Application can choose to use the locking mechanism or not.
15
+ # By default, the locking mechanism is enabled and uses the default
16
+ # lockfile root directory /var/lock/ekfsm.
17
+ #
18
+ # Use locking_configure() to enable or disable the locking mechanism or to change
19
+ # the lockfile root directory.
20
+
21
+ USE_LOCK = True
22
+ LOCKFILE_ROOT = "/var/lock/ekfsm"
23
+ ALL_LOCKERS: list["Locker"] = [] # List of all locker instances
24
+
25
+
26
+ def locking_configure(enable: bool, lockfile_root: str = LOCKFILE_ROOT):
27
+ """
28
+ Configures the locking mechanism.
29
+
30
+ :param enable: Whether to enable or disable locking.
31
+ :param lockfile_root: The root directory for lockfiles. (default: /var/lock/ekfsm)
32
+ """
33
+ global USE_LOCK, LOCKFILE_ROOT
34
+ USE_LOCK = enable
35
+ LOCKFILE_ROOT = lockfile_root
36
+
37
+
38
+ def locking_cleanup():
39
+ """
40
+ Cleans up all lockfiles and closes all lock file descriptors.
41
+ Should be called at the end of the program to ensure all locks are released.
42
+ """
43
+ for locker in ALL_LOCKERS:
44
+ locker.cleanup()
45
+
46
+
47
+ class Locker:
48
+ """
49
+ A class that implements a locking mechanism using file locks.
50
+
51
+ Parameters
52
+ ----------
53
+ module
54
+ The name of the module or resource to lock. This will be used to create a unique lock file.
55
+
56
+ Example
57
+ -------
58
+ with Locker("mysharedresourcename").lock():
59
+ # Access the shared resource here
60
+ pass
61
+ """
62
+
63
+ def __init__(self, module: str):
64
+ if not USE_LOCK:
65
+ return
66
+
67
+ self.lockfile_path = Path(LOCKFILE_ROOT) / module
68
+ self.lock_fd = None
69
+ # Ensure lockfile exists
70
+ os.makedirs(LOCKFILE_ROOT, exist_ok=True)
71
+ open(self.lockfile_path, "a").close()
72
+ ALL_LOCKERS.append(self)
73
+
74
+ def cleanup(self):
75
+ if not USE_LOCK:
76
+ return
77
+ if self.lock_fd is not None:
78
+ try:
79
+ fcntl.flock(self.lock_fd, fcntl.LOCK_UN)
80
+ os.close(self.lock_fd)
81
+ self.lock_fd = None
82
+ except (OSError, AttributeError):
83
+ pass
84
+
85
+ @contextmanager
86
+ def lock(self):
87
+ if not USE_LOCK:
88
+ yield
89
+ self.lock_fd = os.open(self.lockfile_path, os.O_RDWR)
90
+ try:
91
+ fcntl.flock(self.lock_fd, fcntl.LOCK_EX)
92
+ yield
93
+ finally:
94
+ self.cleanup()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ekfsm
3
- Version: 0.13.0a168.post1
3
+ Version: 0.13.0a183.post1
4
4
  Summary: The EKF System Management Library (ekfsm) is a sensor monitoring suite for Compact PCI Serial devices.
5
5
  Author-email: Klaus Popp <klaus.popp@ci4rail.com>, Jan Jansen <jan@ekf.de>, Felix Päßler <fp@ekf.de>
6
6
  Requires-Python: >=3.10
@@ -1,7 +1,8 @@
1
- ekfsm/__init__.py,sha256=RF5mSVhkFWVsbJgYk-qMKb9eVHAcQ7WbJCunGBim4Ig,244
1
+ ekfsm/__init__.py,sha256=UQljpq-to0fUnfzSlYJ-jdfv8CCc6ZQKBXoTnss67i8,345
2
2
  ekfsm/cli.py,sha256=ElaIx49lujDM-XCE0R29pv1AsqqnMcNCPZ1-S5XOpSw,2931
3
3
  ekfsm/config.py,sha256=FTk47f3qA05Zv6Cy_L_5XlGmmbC9z_kPdQJKpVoHkWs,924
4
4
  ekfsm/exceptions.py,sha256=25P677GxfBTdBWHRngPce0bmhcLg7MFeTtuAvguxd90,1310
5
+ ekfsm/lock.py,sha256=qmWkW6OA-NLiDrtSsQn-K10tZJ19t-h4iFB5zyL97Vw,2682
5
6
  ekfsm/log.py,sha256=_GC8Y7a4fFV4_DNicbwQ-5rRzNQU6WSotXd2etXSrZk,866
6
7
  ekfsm/py.typed,sha256=1gNRtmxvYcVqDDEyAzBLnD8dAOweUfYxW2ZPdJzN1fg,102
7
8
  ekfsm/simctrl.py,sha256=NkmjvqOym9Wruh0f14Od6gHfEgPMAkxUzMQ-nvzcM3Q,6681
@@ -16,7 +17,7 @@ ekfsm/boards/oem/ekf/sq1-track.yaml,sha256=YU83BQjGu-4ejirwnGxd38sJme859kdRovkZy
16
17
  ekfsm/boards/oem/ekf/sq3-quartet.yaml,sha256=pBB7Tv0IWLkFUYBs3tFvZriA-uqPuPIgzjaN0aHT4e4,1052
17
18
  ekfsm/boards/oem/ekf/srf-fan.yaml,sha256=Mcu1Q8B1Ih10hoc_hbkGlppBmbOFcufsVUR42iW4Rwc,1368
18
19
  ekfsm/boards/oem/ekf/sur-uart.yaml,sha256=VaNP2BSlNTi1lDco16Ma9smPEAMaVKvx-ZNDcm3QptM,1890
19
- ekfsm/boards/oem/hitron/hdrc-300s.yaml,sha256=Cji2ZmYsEUvHQ0m04iKkPlzDNRwJgqj8y2lzQzkAWd4,560
20
+ ekfsm/boards/oem/hitron/hdrc-300s.yaml,sha256=E567QsRPvyAEXpXOeF1OvX2AoQK8BTxI0C7QVBFlT_k,548
20
21
  ekfsm/core/__init__.py,sha256=nv3Rs-E953M9PBFV9ryejRY-KM6xG1NMlQTWwzCEQwo,212
21
22
  ekfsm/core/components.py,sha256=dh71jM_OJ8QhTzou-5L6RaF3abXgE470KJfxQRqq1CY,3836
22
23
  ekfsm/core/probe.py,sha256=DgJvkvMjVk09n0Rzn13ybRvidrmFn_D2PD56XS-KgxU,262
@@ -26,7 +27,7 @@ ekfsm/core/utils.py,sha256=EoPOuRmLlvHvGneDcKjP7Qbjfsc4XlMbLeaSFRObt_E,3145
26
27
  ekfsm/devices/__init__.py,sha256=UtFLCtAdpDJ3OaY7fedk13bx90NMsfxhyVAHV13t2U4,936
27
28
  ekfsm/devices/coretemp.py,sha256=s0qUoVR90hr9O7Yp7AecXc_LAfrd0LUIJSm2Wh7AJZY,2012
28
29
  ekfsm/devices/eeprom.py,sha256=8z0eWs4ljRtoLoS3rLbMiGcSxWmNmXeJ8zB6hRGZXis,32042
29
- ekfsm/devices/ekf_ccu_uc.py,sha256=Jmy2HiXPG39MHmD9JGtIR5U9UoeyIQnIbiz9VPZteEk,15252
30
+ ekfsm/devices/ekf_ccu_uc.py,sha256=a1vztQQfRVNVikJ-jBNTV9lgtm_i8056J6UMi6qiDcg,15211
30
31
  ekfsm/devices/ekf_sur_led.py,sha256=dY2EIqUx4-LV7ipCEIg8DfXWlGxpspRmEtEhVfHY6LI,1871
31
32
  ekfsm/devices/generic.py,sha256=Xii1fkV8R2kRvWCe9Pg-uOVDWXa-Ow5AM6CbUYKcxSI,9494
32
33
  ekfsm/devices/gpio.py,sha256=hlJ3yJ8jSGUIkPpjymani0EcxYJX2iEybGbnV8N0O5E,9552
@@ -34,11 +35,11 @@ ekfsm/devices/iio.py,sha256=gMOJGdg2PvFbAvlBpLfDTIc_-9i1Z3OLpuabTke6N3I,1480
34
35
  ekfsm/devices/iio_thermal_humidity.py,sha256=4Qod31hhnUIHP6ojv_cf2JLld8OCN1McFOPTJL-Ue-A,1196
35
36
  ekfsm/devices/imu.py,sha256=bnSaTjGSLV90FyUbkK9oTon0dmF7N_JQ4uGmBPFA5Co,414
36
37
  ekfsm/devices/mux.py,sha256=CV5ECUiEvaxXNoozMFchsuLD4FpYD_7uFp62DNWVFJ0,1026
37
- ekfsm/devices/pmbus.py,sha256=Tgve-a_-9SvlaPUGZw87Ulh3Z5wIBxBPLap3zzsgr2Q,6383
38
+ ekfsm/devices/pmbus.py,sha256=rdhVvwuV0pQs7DvQgluoKLVPHBRa13HpJiU6oVwkLRg,6482
38
39
  ekfsm/devices/smbios.py,sha256=gDDYtfCd7njzqxJBKJxIR2BMCK6-uZxUVxC9y0hnz4g,1009
39
40
  ekfsm/devices/smbus.py,sha256=zD9b6PehipMw-xoaOMC-oorDVxBoo30hc98gyFxFLs0,500
40
41
  ekfsm/devices/utils.py,sha256=4-0Kmvy4ou8R71afNj6RqdBTjLW4SMWPHqVrzB2RUZw,397
41
- ekfsm-0.13.0a168.post1.dist-info/METADATA,sha256=dd-yEslD64NYfCMidSe2G61CMwVaCwDlaaSLu1jvdA8,6552
42
- ekfsm-0.13.0a168.post1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- ekfsm-0.13.0a168.post1.dist-info/entry_points.txt,sha256=WhUR4FzuxPoGrbTOKLsNJO7NAnk2qd4T30fqzN1yLw8,45
44
- ekfsm-0.13.0a168.post1.dist-info/RECORD,,
42
+ ekfsm-0.13.0a183.post1.dist-info/METADATA,sha256=yqILFbdhxfGAZHHpNwDa7rT2SRYJME8GpJMNsmy89YA,6552
43
+ ekfsm-0.13.0a183.post1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
+ ekfsm-0.13.0a183.post1.dist-info/entry_points.txt,sha256=WhUR4FzuxPoGrbTOKLsNJO7NAnk2qd4T30fqzN1yLw8,45
45
+ ekfsm-0.13.0a183.post1.dist-info/RECORD,,