shepherd-core 2025.6.1__tar.gz → 2025.6.2__tar.gz
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.
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/PKG-INFO +1 -1
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/eenv_generator.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/uart_decode_waveform.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/__init__.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/__init__.py +1 -1
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/shepherd.py +28 -11
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/firmware.py +4 -4
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/virtual_harvester.py +3 -3
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/virtual_source.py +5 -5
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/experiment/observer_features.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/__init__.py +8 -4
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/emulation.py +14 -5
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/firmware_mod.py +14 -5
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/harvest.py +5 -0
- shepherd_core-2025.6.2/shepherd_core/data_models/task/helper_paths.py +15 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/observer_tasks.py +16 -15
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/programming.py +8 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/testbed_tasks.py +12 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/decoder_waveform/uart.py +7 -7
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/fw_tools/patcher.py +6 -6
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/fw_tools/validation.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/inventory/system.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/logger.py +3 -3
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/fixtures.py +5 -5
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/version.py +1 -1
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/virtual_harvester_model.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/virtual_source_simulation.py +2 -2
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/PKG-INFO +1 -1
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/SOURCES.txt +1 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/README.md +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/experiment_from_yaml.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/experiment_generic_var1.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/experiment_generic_var2.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/experiment_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/firmware_model.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/firmware_modification.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/inventory.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/simulate_vharvester.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/simulate_vsource.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/uart_raw2.csv +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/examples/vsource_debug_sim.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/pyproject.toml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/setup.cfg +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/calibration_hw_def.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/commons.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/config.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/cal_measurement.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/calibration.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/content.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/timezone.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/wrapper.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/energy_environment.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/virtual_source_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/experiment/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/experiment/experiment.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/experiment/target_config.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/readme.md +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/cape.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/gpio.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/mcu.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/observer.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/target.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/target_fixture.old1 +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/testbed.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/fw_tools/converter.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/fw_tools/converter_elf.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/inventory/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/inventory/python.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/inventory/target.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/reader.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/cache_path.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/client_abc_fix.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/client_web.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/testbed_client/user_model.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/target_model.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/virtual_converter_model.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/virtual_harvester_simulation.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/vsource/virtual_source_model.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/writer.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/dependency_links.txt +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/requires.txt +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/top_level.txt +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core.egg-info/zip-safe +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/conftest.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/conftest.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_cal_data.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_cal_data_faulty.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_cal_meas.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_emulator.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_experiment.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_harvester.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_testbed.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/example_config_virtsource.yaml +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_base_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_content_fixtures.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_content_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_examples.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_experiment_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_task_generation.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_task_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_testbed_fixtures.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/data_models/test_testbed_models.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/decoder_waveform/test_decoder.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/build_msp.elf +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/build_nrf.elf +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/conftest.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/test_converter.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/test_patcher.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/fw_tools/test_validation.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/inventory/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/inventory/test_inventory.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/test_cal_hw.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/test_examples.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/test_logger.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/test_reader.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/test_writer.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/vsource/__init__.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/vsource/conftest.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/vsource/test_converter.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/vsource/test_harvester.py +0 -0
- {shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/tests/vsource/test_z.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_core
|
|
3
|
-
Version: 2025.6.
|
|
3
|
+
Version: 2025.6.2
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -8,7 +8,7 @@ from tqdm import trange
|
|
|
8
8
|
|
|
9
9
|
from shepherd_core import Reader as ShpReader
|
|
10
10
|
from shepherd_core import Writer as ShpWriter
|
|
11
|
-
from shepherd_core import
|
|
11
|
+
from shepherd_core.logger import log
|
|
12
12
|
|
|
13
13
|
# Config
|
|
14
14
|
voltages_V = [4.0, 2.0]
|
|
@@ -26,7 +26,7 @@ for _v, _c in product(voltages_V, currents_A):
|
|
|
26
26
|
file_path = path_here / f"{name}.h5"
|
|
27
27
|
|
|
28
28
|
if file_path.exists():
|
|
29
|
-
|
|
29
|
+
log.info("File exists, will skip: %s", file_path.name)
|
|
30
30
|
else:
|
|
31
31
|
with ShpWriter(file_path) as file:
|
|
32
32
|
file.store_hostname("artificial")
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from timeit import timeit
|
|
5
5
|
|
|
6
|
-
from shepherd_core import logger
|
|
7
6
|
from shepherd_core.decoder_waveform import Uart
|
|
7
|
+
from shepherd_core.logger import log
|
|
8
8
|
|
|
9
9
|
# file captured with logic analyzer, 15.5k events (2700 symbols, 61 lines)
|
|
10
10
|
trace = Path(__file__).parent / "uart_raw2.csv"
|
|
@@ -13,7 +13,7 @@ uwd = Uart(trace)
|
|
|
13
13
|
sym = uwd.get_symbols()
|
|
14
14
|
lne = uwd.get_lines()
|
|
15
15
|
txt = uwd.get_text()
|
|
16
|
-
|
|
16
|
+
log.info(txt)
|
|
17
17
|
|
|
18
18
|
do_analysis = False
|
|
19
19
|
if do_analysis:
|
|
@@ -17,7 +17,7 @@ from .data_models.task.emulation import Compression
|
|
|
17
17
|
from .inventory import Inventory
|
|
18
18
|
from .logger import get_verbose_level
|
|
19
19
|
from .logger import increase_verbose_level
|
|
20
|
-
from .logger import
|
|
20
|
+
from .logger import log
|
|
21
21
|
from .reader import Reader
|
|
22
22
|
from .testbed_client.client_web import WebClient
|
|
23
23
|
from .version import version
|
|
@@ -41,5 +41,5 @@ __all__ = [
|
|
|
41
41
|
"increase_verbose_level",
|
|
42
42
|
"local_now",
|
|
43
43
|
"local_tz",
|
|
44
|
-
"
|
|
44
|
+
"log",
|
|
45
45
|
]
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/base/shepherd.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
4
|
import pathlib
|
|
5
|
+
import pickle
|
|
5
6
|
from collections.abc import Generator
|
|
6
7
|
from datetime import timedelta
|
|
7
8
|
from ipaddress import IPv4Address
|
|
@@ -126,10 +127,12 @@ class ShpModel(BaseModel):
|
|
|
126
127
|
comment: Optional[str] = None,
|
|
127
128
|
*,
|
|
128
129
|
minimal: bool = True,
|
|
130
|
+
use_pickle: bool = False,
|
|
129
131
|
) -> Path:
|
|
130
132
|
"""Store data to yaml in a wrapper.
|
|
131
133
|
|
|
132
134
|
minimal: stores minimal set (filters out unset & default parameters)
|
|
135
|
+
pickle: uses pickle to serialize data, on BBB >100x faster for large files
|
|
133
136
|
comment: documentation.
|
|
134
137
|
"""
|
|
135
138
|
model_dict = self.model_dump(exclude_unset=minimal)
|
|
@@ -139,25 +142,39 @@ class ShpModel(BaseModel):
|
|
|
139
142
|
created=local_now(),
|
|
140
143
|
parameters=model_dict,
|
|
141
144
|
)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
if use_pickle:
|
|
146
|
+
model_serial = pickle.dumps(model_dict, fix_imports=True)
|
|
147
|
+
model_path = Path(path).resolve().with_suffix(".pickle")
|
|
148
|
+
else:
|
|
149
|
+
# TODO: x64 windows supports CSafeLoader/dumper,
|
|
150
|
+
# there are examples that replace load if avail
|
|
151
|
+
model_serial = yaml.safe_dump(
|
|
152
|
+
model_wrap.model_dump(exclude_unset=minimal, exclude_defaults=minimal),
|
|
153
|
+
default_flow_style=False,
|
|
154
|
+
sort_keys=False,
|
|
155
|
+
)
|
|
156
|
+
model_path = Path(path).resolve().with_suffix(".yaml")
|
|
147
157
|
# TODO: handle directory
|
|
148
|
-
|
|
158
|
+
|
|
149
159
|
if not model_path.parent.exists():
|
|
150
160
|
model_path.parent.mkdir(parents=True)
|
|
151
161
|
with model_path.open("w") as f:
|
|
152
|
-
f.write(
|
|
162
|
+
f.write(model_serial)
|
|
153
163
|
return model_path
|
|
154
164
|
|
|
155
165
|
@classmethod
|
|
156
166
|
def from_file(cls, path: Union[str, Path]) -> Self:
|
|
157
|
-
"""Load from
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
"""Load from YAML or pickle file."""
|
|
168
|
+
path: Path = Path(path)
|
|
169
|
+
if not Path(path).exists():
|
|
170
|
+
raise FileNotFoundError
|
|
171
|
+
if path.suffix.lower() == ".pickle":
|
|
172
|
+
with Path(path).open("rb") as shp_file:
|
|
173
|
+
shp_wrap = pickle.load(shp_file, fix_imports=True) # noqa: S301
|
|
174
|
+
else:
|
|
175
|
+
with Path(path).open() as shp_file:
|
|
176
|
+
shp_dict = yaml.safe_load(shp_file)
|
|
177
|
+
shp_wrap = Wrapper(**shp_dict)
|
|
161
178
|
if shp_wrap.datatype != cls.__name__:
|
|
162
179
|
raise ValueError("Model in file does not match the requirement")
|
|
163
180
|
return cls(**shp_wrap.parameters)
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/content/firmware.py
RENAMED
|
@@ -19,7 +19,7 @@ from typing_extensions import Unpack
|
|
|
19
19
|
from shepherd_core import fw_tools
|
|
20
20
|
from shepherd_core.data_models.base.content import ContentModel
|
|
21
21
|
from shepherd_core.data_models.testbed.mcu import MCU
|
|
22
|
-
from shepherd_core.logger import
|
|
22
|
+
from shepherd_core.logger import log
|
|
23
23
|
from shepherd_core.testbed_client import tb_client
|
|
24
24
|
|
|
25
25
|
from .firmware_datatype import FirmwareDType
|
|
@@ -135,8 +135,8 @@ class Firmware(ContentModel, title="Firmware of Target"):
|
|
|
135
135
|
if ("nrf52" in arch or "arm" in arch) and not fw_tools.is_elf_nrf52(file):
|
|
136
136
|
raise ValueError("File is not a ELF for nRF52")
|
|
137
137
|
except RuntimeError:
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
log.warning("ObjCopy not found -> Arch of Firmware can't be verified")
|
|
139
|
+
log.debug("ELF-File '%s' has arch: %s", file.name, arch)
|
|
140
140
|
if "mcu" not in kwargs:
|
|
141
141
|
kwargs["mcu"] = arch_to_mcu[arch]
|
|
142
142
|
|
|
@@ -159,7 +159,7 @@ class Firmware(ContentModel, title="Firmware of Target"):
|
|
|
159
159
|
match = self.data_hash == hash_new
|
|
160
160
|
|
|
161
161
|
if not match:
|
|
162
|
-
|
|
162
|
+
log.warning("FW-Hash does not match with stored value!")
|
|
163
163
|
# TODO: it might be more appropriate to raise here
|
|
164
164
|
return match
|
|
165
165
|
|
|
@@ -14,7 +14,7 @@ from shepherd_core.config import config
|
|
|
14
14
|
from shepherd_core.data_models.base.calibration import CalibrationHarvester
|
|
15
15
|
from shepherd_core.data_models.base.content import ContentModel
|
|
16
16
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
17
|
-
from shepherd_core.logger import
|
|
17
|
+
from shepherd_core.logger import log
|
|
18
18
|
from shepherd_core.testbed_client import tb_client
|
|
19
19
|
|
|
20
20
|
from .energy_environment import EnergyDType
|
|
@@ -310,7 +310,7 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
|
|
|
310
310
|
if values["name"] == "neutral":
|
|
311
311
|
# TODO: same test is later done in calc_algorithm_num() again
|
|
312
312
|
raise ValueError("Resulting Harvester can't be neutral")
|
|
313
|
-
|
|
313
|
+
log.debug("VHrv-Inheritances: %s", chain)
|
|
314
314
|
|
|
315
315
|
# post corrections -> should be in separate validator
|
|
316
316
|
cal = CalibrationHarvester() # TODO: as argument?
|
|
@@ -372,7 +372,7 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
|
|
|
372
372
|
duration_ms = min(max(self.duration_ms, time_min_ms), interval_ms)
|
|
373
373
|
_ratio = (duration_ms / interval_ms) / (self.duration_ms / self.interval_ms)
|
|
374
374
|
if (_ratio - 1) > 0.1:
|
|
375
|
-
|
|
375
|
+
log.debug(
|
|
376
376
|
"Ratio between interval & duration has changed "
|
|
377
377
|
"more than 10%% due to constraints (%.4f)",
|
|
378
378
|
_ratio,
|
|
@@ -10,7 +10,7 @@ from typing_extensions import Self
|
|
|
10
10
|
from shepherd_core.config import config
|
|
11
11
|
from shepherd_core.data_models.base.content import ContentModel
|
|
12
12
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
13
|
-
from shepherd_core.logger import
|
|
13
|
+
from shepherd_core.logger import log
|
|
14
14
|
from shepherd_core.testbed_client import tb_client
|
|
15
15
|
|
|
16
16
|
from .energy_environment import EnergyDType
|
|
@@ -128,7 +128,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
128
128
|
def query_database(cls, values: dict[str, Any]) -> dict[str, Any]:
|
|
129
129
|
values, chain = tb_client.try_completing_model(cls.__name__, values)
|
|
130
130
|
values = tb_client.fill_in_user_data(values)
|
|
131
|
-
|
|
131
|
+
log.debug("VSrc-Inheritances: %s", chain)
|
|
132
132
|
return values
|
|
133
133
|
|
|
134
134
|
@model_validator(mode="after")
|
|
@@ -187,7 +187,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
187
187
|
if not (isinstance(dV_output_en_thrs_mV, (int, float)) and (dV_output_en_thrs_mV >= 0)):
|
|
188
188
|
dV_output_en_thrs_mV = 0
|
|
189
189
|
if not (isinstance(dV_output_imed_low_mV, (int, float)) and (dV_output_imed_low_mV >= 0)):
|
|
190
|
-
|
|
190
|
+
log.warning("VSrc: C_output shouldn't be larger than C_intermediate")
|
|
191
191
|
dV_output_imed_low_mV = 0
|
|
192
192
|
|
|
193
193
|
# decide which hysteresis-thresholds to use for buck-converter
|
|
@@ -224,7 +224,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
224
224
|
enable_storage = self.C_intermediate_uF > 0
|
|
225
225
|
enable_boost = self.enable_boost and enable_storage
|
|
226
226
|
if enable_boost != self.enable_boost:
|
|
227
|
-
|
|
227
|
+
log.warning("VSrc - boost was disabled due to missing storage capacitor!")
|
|
228
228
|
enable_feedback = (
|
|
229
229
|
self.enable_feedback_to_hrv
|
|
230
230
|
and enable_storage
|
|
@@ -235,7 +235,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
235
235
|
reason = "enabled boost, " if enable_boost else ""
|
|
236
236
|
reason += "" if dtype_in == EnergyDType.ivcurve else "input not ivcurve, "
|
|
237
237
|
reason += "" if enable_storage else "no storage capacitor"
|
|
238
|
-
|
|
238
|
+
log.warning("VSRC - feedback to harvester was disabled! Reasons: %s", reason)
|
|
239
239
|
return (
|
|
240
240
|
1 * int(enable_storage)
|
|
241
241
|
+ 2 * int(enable_boost)
|
|
@@ -13,9 +13,9 @@ from pydantic import model_validator
|
|
|
13
13
|
from typing_extensions import Self
|
|
14
14
|
from typing_extensions import deprecated
|
|
15
15
|
|
|
16
|
-
from shepherd_core import logger
|
|
17
16
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
18
17
|
from shepherd_core.data_models.testbed.gpio import GPIO
|
|
18
|
+
from shepherd_core.logger import log
|
|
19
19
|
|
|
20
20
|
# defaults (pre-init complex types)
|
|
21
21
|
zero_duration = timedelta(seconds=0)
|
|
@@ -190,7 +190,7 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
|
|
|
190
190
|
if self.duration and self.duration.total_seconds() < 0:
|
|
191
191
|
raise ValueError("Duration can't be negative.")
|
|
192
192
|
if self.uart_decode:
|
|
193
|
-
|
|
193
|
+
log.error(
|
|
194
194
|
"Feature GpioTracing.uart_decode reserved for future use. "
|
|
195
195
|
"Use UartLogging or manually decode serial with the provided waveform decoder."
|
|
196
196
|
)
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/__init__.py
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
These models import externally from all other model-modules!
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import pickle
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Optional
|
|
8
9
|
from typing import Union
|
|
@@ -11,7 +12,7 @@ import yaml
|
|
|
11
12
|
|
|
12
13
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
13
14
|
from shepherd_core.data_models.base.wrapper import Wrapper
|
|
14
|
-
from shepherd_core.logger import
|
|
15
|
+
from shepherd_core.logger import log
|
|
15
16
|
|
|
16
17
|
from .emulation import Compression
|
|
17
18
|
from .emulation import EmulationTask
|
|
@@ -44,7 +45,10 @@ def prepare_task(config: Union[ShpModel, Path, str], observer: Optional[str] = N
|
|
|
44
45
|
if isinstance(config, str):
|
|
45
46
|
config = Path(config)
|
|
46
47
|
|
|
47
|
-
if isinstance(config, Path):
|
|
48
|
+
if isinstance(config, Path) and config.exists() and config.suffix.lower() == ".pickle":
|
|
49
|
+
with config.resolve().open("rb") as shp_file:
|
|
50
|
+
shp_wrap = pickle.load(shp_file, fix_imports=True) # noqa: S301
|
|
51
|
+
elif isinstance(config, Path) and config.exists() and config.suffix.lower() == ".yaml":
|
|
48
52
|
with config.resolve().open() as shp_file:
|
|
49
53
|
shp_dict = yaml.safe_load(shp_file)
|
|
50
54
|
shp_wrap = Wrapper(**shp_dict)
|
|
@@ -59,12 +63,12 @@ def prepare_task(config: Union[ShpModel, Path, str], observer: Optional[str] = N
|
|
|
59
63
|
|
|
60
64
|
if shp_wrap.datatype == TestbedTasks.__name__:
|
|
61
65
|
if observer is None:
|
|
62
|
-
|
|
66
|
+
log.debug(
|
|
63
67
|
"Task-Set contained TestbedTasks & no observer was provided -> will return TB-Tasks"
|
|
64
68
|
)
|
|
65
69
|
return shp_wrap
|
|
66
70
|
tbt = TestbedTasks(**shp_wrap.parameters)
|
|
67
|
-
|
|
71
|
+
log.debug("Loading Testbed-Tasks %s for %s", tbt.name, observer)
|
|
68
72
|
obt = tbt.get_observer_tasks(observer)
|
|
69
73
|
if obt is None:
|
|
70
74
|
msg = f"Observer '{observer}' is not in TestbedTask-Set"
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/emulation.py
RENAMED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""Configuration for the Observer in Emulation-Mode."""
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
|
+
from collections.abc import Set as AbstractSet
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
from datetime import timedelta
|
|
6
7
|
from enum import Enum
|
|
7
8
|
from pathlib import Path
|
|
9
|
+
from pathlib import PurePosixPath
|
|
8
10
|
from typing import Annotated
|
|
9
11
|
from typing import Optional
|
|
10
12
|
from typing import Union
|
|
@@ -28,7 +30,9 @@ from shepherd_core.data_models.experiment.observer_features import UartLogging
|
|
|
28
30
|
from shepherd_core.data_models.experiment.target_config import vsrc_neutral
|
|
29
31
|
from shepherd_core.data_models.testbed import Testbed
|
|
30
32
|
from shepherd_core.data_models.testbed.cape import TargetPort
|
|
31
|
-
from shepherd_core.logger import
|
|
33
|
+
from shepherd_core.logger import log
|
|
34
|
+
|
|
35
|
+
from .helper_paths import path_posix
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
class Compression(str, Enum):
|
|
@@ -149,9 +153,9 @@ class EmulationTask(ShpModel):
|
|
|
149
153
|
_io is not None for _io in (self.gpio_actuation, self.gpio_tracing, self.uart_logging)
|
|
150
154
|
)
|
|
151
155
|
if self.enable_io and not io_requested:
|
|
152
|
-
|
|
156
|
+
log.warning("Target IO enabled, but no feature requested IO")
|
|
153
157
|
if not self.enable_io and io_requested:
|
|
154
|
-
|
|
158
|
+
log.warning("Target IO not enabled, but a feature requested IO")
|
|
155
159
|
return self
|
|
156
160
|
|
|
157
161
|
@classmethod
|
|
@@ -165,8 +169,8 @@ class EmulationTask(ShpModel):
|
|
|
165
169
|
)
|
|
166
170
|
|
|
167
171
|
return cls(
|
|
168
|
-
input_path=tgt_cfg.energy_env.data_path,
|
|
169
|
-
output_path=root_path / f"emu_{obs.name}.h5",
|
|
172
|
+
input_path=path_posix(tgt_cfg.energy_env.data_path),
|
|
173
|
+
output_path=path_posix(root_path / f"emu_{obs.name}.h5"),
|
|
170
174
|
time_start=copy.copy(xp.time_start),
|
|
171
175
|
duration=xp.duration,
|
|
172
176
|
enable_io=io_requested,
|
|
@@ -180,6 +184,11 @@ class EmulationTask(ShpModel):
|
|
|
180
184
|
sys_logging=xp.sys_logging,
|
|
181
185
|
)
|
|
182
186
|
|
|
187
|
+
def is_contained(self, paths: AbstractSet[PurePosixPath]) -> bool:
|
|
188
|
+
all_ok = any(self.input_path.is_relative_to(path) for path in paths)
|
|
189
|
+
all_ok &= any(self.output_path.is_relative_to(path) for path in paths)
|
|
190
|
+
return all_ok
|
|
191
|
+
|
|
183
192
|
|
|
184
193
|
# TODO: herdConfig
|
|
185
194
|
# - store if path is remote (read & write)
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/firmware_mod.py
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Config for Task that adds the custom ID to the firmware & stores it into a file."""
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from collections.abc import Set as AbstractSet
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from pathlib import PurePosixPath
|
|
5
6
|
from typing import Annotated
|
|
6
7
|
from typing import Optional
|
|
7
8
|
from typing import TypedDict
|
|
@@ -22,7 +23,9 @@ from shepherd_core.data_models.experiment.experiment import Experiment
|
|
|
22
23
|
from shepherd_core.data_models.testbed import Testbed
|
|
23
24
|
from shepherd_core.data_models.testbed.target import IdInt16
|
|
24
25
|
from shepherd_core.data_models.testbed.target import MCUPort
|
|
25
|
-
from shepherd_core.logger import
|
|
26
|
+
from shepherd_core.logger import log
|
|
27
|
+
|
|
28
|
+
from .helper_paths import path_posix
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
class FirmwareModTask(ShpModel):
|
|
@@ -42,7 +45,7 @@ class FirmwareModTask(ShpModel):
|
|
|
42
45
|
FirmwareDType.base64_hex,
|
|
43
46
|
FirmwareDType.path_hex,
|
|
44
47
|
}:
|
|
45
|
-
|
|
48
|
+
log.warning("Firmware is scheduled to get custom-ID but is not in elf-format")
|
|
46
49
|
return self
|
|
47
50
|
|
|
48
51
|
@classmethod
|
|
@@ -68,10 +71,10 @@ class FirmwareModTask(ShpModel):
|
|
|
68
71
|
fw_id = obs.get_target(tgt_id).testbed_id
|
|
69
72
|
|
|
70
73
|
return cls(
|
|
71
|
-
data=fw.data,
|
|
74
|
+
data=path_posix(fw.data) if isinstance(fw.data, Path) else fw.data,
|
|
72
75
|
data_type=fw.data_type,
|
|
73
76
|
custom_id=fw_id,
|
|
74
|
-
firmware_file=
|
|
77
|
+
firmware_file=path_posix(fw_path),
|
|
75
78
|
)
|
|
76
79
|
|
|
77
80
|
@classmethod
|
|
@@ -90,3 +93,9 @@ class FirmwareModTask(ShpModel):
|
|
|
90
93
|
path_new: Path = path / fw.name
|
|
91
94
|
kwargs["firmware_file"] = path_new.with_suffix(".hex")
|
|
92
95
|
return cls(**kwargs)
|
|
96
|
+
|
|
97
|
+
def is_contained(self, paths: AbstractSet[PurePosixPath]) -> bool:
|
|
98
|
+
all_ok = any(self.firmware_file.is_relative_to(path) for path in paths)
|
|
99
|
+
if isinstance(self.data, Path):
|
|
100
|
+
all_ok = any(self.data.is_relative_to(path) for path in paths)
|
|
101
|
+
return all_ok
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Config for the Observer in Harvest-Mode to record IV data from a harvesting-source."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Set as AbstractSet
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
from datetime import timedelta
|
|
5
6
|
from pathlib import Path
|
|
7
|
+
from pathlib import PurePosixPath
|
|
6
8
|
from typing import Annotated
|
|
7
9
|
from typing import Optional
|
|
8
10
|
|
|
@@ -84,3 +86,6 @@ class HarvestTask(ShpModel):
|
|
|
84
86
|
if self.duration and self.duration.total_seconds() < 0:
|
|
85
87
|
raise ValueError("Task-Duration can't be negative.")
|
|
86
88
|
return self
|
|
89
|
+
|
|
90
|
+
def is_contained(self, paths: AbstractSet[PurePosixPath]) -> bool:
|
|
91
|
+
return any(self.output_path.is_relative_to(path) for path in paths)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
r"""Helper FN to avoid unwanted behavior.
|
|
2
|
+
|
|
3
|
+
On windows Path("\xyz") gets transformed to "/xyz", but not on linux.
|
|
4
|
+
When sending an experiment via fastapi, this bug gets triggered.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def path_posix(path: Path) -> Path:
|
|
11
|
+
r"""Help Linux to get from "\xyz" to "/xyz".
|
|
12
|
+
|
|
13
|
+
This isn't a problem on windows and gets triggered when sending XP via fastapi.
|
|
14
|
+
"""
|
|
15
|
+
return Path(path.as_posix().replace("\\", "/"))
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/observer_tasks.py
RENAMED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Collection of tasks for selected observer included in experiment."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Set as AbstractSet
|
|
3
4
|
from datetime import datetime
|
|
4
|
-
from datetime import timedelta
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from pathlib import PurePosixPath
|
|
6
7
|
from typing import Annotated
|
|
7
8
|
from typing import Optional
|
|
8
9
|
|
|
@@ -18,6 +19,7 @@ from shepherd_core.data_models.testbed.testbed import Testbed
|
|
|
18
19
|
|
|
19
20
|
from .emulation import EmulationTask
|
|
20
21
|
from .firmware_mod import FirmwareModTask
|
|
22
|
+
from .helper_paths import path_posix
|
|
21
23
|
from .programming import ProgrammingTask
|
|
22
24
|
|
|
23
25
|
|
|
@@ -27,7 +29,7 @@ class ObserverTasks(ShpModel):
|
|
|
27
29
|
observer: NameStr
|
|
28
30
|
|
|
29
31
|
# PRE PROCESS
|
|
30
|
-
time_prep: datetime # TODO:
|
|
32
|
+
time_prep: Optional[datetime] = None # TODO: currently not used
|
|
31
33
|
root_path: Path
|
|
32
34
|
|
|
33
35
|
# fw mod, store as hex-file and program
|
|
@@ -55,24 +57,14 @@ class ObserverTasks(ShpModel):
|
|
|
55
57
|
if not tb.shared_storage:
|
|
56
58
|
raise ValueError("Implementation currently relies on shared storage!")
|
|
57
59
|
|
|
58
|
-
t_start = (
|
|
59
|
-
xp.time_start
|
|
60
|
-
if isinstance(xp.time_start, datetime)
|
|
61
|
-
else datetime.now().astimezone() + timedelta(minutes=3)
|
|
62
|
-
) # TODO: this is messed up, just a hotfix
|
|
63
|
-
|
|
64
60
|
obs = tb.get_observer(tgt_id)
|
|
65
|
-
|
|
66
|
-
root_path = tb.data_on_observer / xp_dir
|
|
67
|
-
# TODO: Paths should be "friendlier"
|
|
68
|
-
# - replace whitespace with "_" and remove non-alphanum?
|
|
69
|
-
|
|
61
|
+
root_path = tb.data_on_observer / "experiments" / xp.folder_name()
|
|
70
62
|
fw_paths = [root_path / f"fw{_i}_{obs.name}.hex" for _i in [1, 2]]
|
|
71
63
|
|
|
72
64
|
return cls(
|
|
73
65
|
observer=obs.name,
|
|
74
|
-
time_prep=
|
|
75
|
-
root_path=root_path,
|
|
66
|
+
# time_prep=
|
|
67
|
+
root_path=path_posix(root_path),
|
|
76
68
|
fw1_mod=FirmwareModTask.from_xp(xp, tb, tgt_id, 1, fw_paths[0]),
|
|
77
69
|
fw2_mod=FirmwareModTask.from_xp(xp, tb, tgt_id, 2, fw_paths[1]),
|
|
78
70
|
fw1_prog=ProgrammingTask.from_xp(xp, tb, tgt_id, 1, fw_paths[0]),
|
|
@@ -100,3 +92,12 @@ class ObserverTasks(ShpModel):
|
|
|
100
92
|
raise ValueError("Emu-Task should have a valid output-path")
|
|
101
93
|
values[self.observer] = self.emulation.output_path
|
|
102
94
|
return values
|
|
95
|
+
|
|
96
|
+
def is_contained(self, paths: AbstractSet[PurePosixPath]) -> bool:
|
|
97
|
+
all_ok = any(self.root_path.is_relative_to(path) for path in paths)
|
|
98
|
+
all_ok &= self.fw1_mod.is_contained(paths)
|
|
99
|
+
all_ok &= self.fw2_mod.is_contained(paths)
|
|
100
|
+
all_ok &= self.fw1_prog.is_contained(paths)
|
|
101
|
+
all_ok &= self.fw2_prog.is_contained(paths)
|
|
102
|
+
all_ok &= self.emulation.is_contained(paths)
|
|
103
|
+
return all_ok
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/programming.py
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Config for a Task programming the selected target."""
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from collections.abc import Set as AbstractSet
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from pathlib import PurePosixPath
|
|
5
6
|
from typing import Annotated
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
@@ -21,6 +22,8 @@ from shepherd_core.data_models.testbed.mcu import ProgrammerProtocol
|
|
|
21
22
|
from shepherd_core.data_models.testbed.target import MCUPort
|
|
22
23
|
from shepherd_core.data_models.testbed.testbed import Testbed
|
|
23
24
|
|
|
25
|
+
from .helper_paths import path_posix
|
|
26
|
+
|
|
24
27
|
|
|
25
28
|
class ProgrammingTask(ShpModel):
|
|
26
29
|
"""Config for a Task programming the selected target."""
|
|
@@ -66,7 +69,7 @@ class ProgrammingTask(ShpModel):
|
|
|
66
69
|
return None
|
|
67
70
|
|
|
68
71
|
return cls(
|
|
69
|
-
firmware_file=
|
|
72
|
+
firmware_file=path_posix(fw_path),
|
|
70
73
|
target_port=obs.get_target_port(tgt_id),
|
|
71
74
|
mcu_port=mcu_port,
|
|
72
75
|
mcu_type=fw.mcu.name,
|
|
@@ -74,3 +77,6 @@ class ProgrammingTask(ShpModel):
|
|
|
74
77
|
datarate=fw.mcu.prog_datarate,
|
|
75
78
|
protocol=fw.mcu.prog_protocol,
|
|
76
79
|
)
|
|
80
|
+
|
|
81
|
+
def is_contained(self, paths: AbstractSet[PurePosixPath]) -> bool:
|
|
82
|
+
return any(self.firmware_file.is_relative_to(path) for path in paths)
|
{shepherd_core-2025.6.1 → shepherd_core-2025.6.2}/shepherd_core/data_models/task/testbed_tasks.py
RENAMED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Collection of tasks for all observers included in experiment."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from pathlib import PurePosixPath
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
4
6
|
from typing import Annotated
|
|
5
7
|
from typing import Optional
|
|
6
8
|
|
|
@@ -17,6 +19,9 @@ from shepherd_core.data_models.testbed.testbed import Testbed
|
|
|
17
19
|
|
|
18
20
|
from .observer_tasks import ObserverTasks
|
|
19
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Set as AbstractSet
|
|
24
|
+
|
|
20
25
|
|
|
21
26
|
class TestbedTasks(ShpModel):
|
|
22
27
|
"""Collection of tasks for all observers included in experiment."""
|
|
@@ -56,3 +61,10 @@ class TestbedTasks(ShpModel):
|
|
|
56
61
|
for obt in self.observer_tasks:
|
|
57
62
|
values = {**values, **obt.get_output_paths()}
|
|
58
63
|
return values
|
|
64
|
+
|
|
65
|
+
def is_contained(self) -> bool:
|
|
66
|
+
paths_allowed: AbstractSet[PurePosixPath] = {
|
|
67
|
+
PurePosixPath("/var/shepherd/"),
|
|
68
|
+
PurePosixPath("/tmp/"), # noqa: S108
|
|
69
|
+
}
|
|
70
|
+
return all(obt.is_contained(paths_allowed) for obt in self.observer_tasks)
|
|
@@ -28,7 +28,7 @@ from typing import Union
|
|
|
28
28
|
|
|
29
29
|
import numpy as np
|
|
30
30
|
|
|
31
|
-
from shepherd_core.logger import
|
|
31
|
+
from shepherd_core.logger import log
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class Parity(str, Enum):
|
|
@@ -109,10 +109,10 @@ class Uart:
|
|
|
109
109
|
raise ValueError("Only bit-order LSB-first is supported ATM")
|
|
110
110
|
|
|
111
111
|
if self.inversion:
|
|
112
|
-
|
|
112
|
+
log.debug("inversion was detected / issued -> will invert signal")
|
|
113
113
|
self._convert_analog2digital(invert=True)
|
|
114
114
|
if self.detect_inversion():
|
|
115
|
-
|
|
115
|
+
log.error("Signal still inverted?!? Check parameters and input")
|
|
116
116
|
|
|
117
117
|
# results
|
|
118
118
|
self.events_symbols: Optional[np.ndarray] = None
|
|
@@ -136,7 +136,7 @@ class Uart:
|
|
|
136
136
|
self.events_sig = self.events_sig[data_f == 1]
|
|
137
137
|
|
|
138
138
|
if len(data_0) > len(self.events_sig):
|
|
139
|
-
|
|
139
|
+
log.debug(
|
|
140
140
|
"filtered out %d/%d events (redundant)",
|
|
141
141
|
len(data_0) - len(self.events_sig),
|
|
142
142
|
len(data_0),
|
|
@@ -145,7 +145,7 @@ class Uart:
|
|
|
145
145
|
def _add_duration(self) -> None:
|
|
146
146
|
"""Calculate third column -> duration of state in [baud-ticks]."""
|
|
147
147
|
if self.events_sig.shape[1] > 2:
|
|
148
|
-
|
|
148
|
+
log.warning("Tried to add state-duration, but it seems already present")
|
|
149
149
|
return
|
|
150
150
|
if not hasattr(self, "dur_tick"):
|
|
151
151
|
raise ValueError("Make sure that baud-rate was calculated before running add_dur()")
|
|
@@ -223,7 +223,7 @@ class Uart:
|
|
|
223
223
|
symbol = 0
|
|
224
224
|
pos_df = None
|
|
225
225
|
else:
|
|
226
|
-
|
|
226
|
+
log.debug("Error - Long pause - but SigLow (@%d)", time)
|
|
227
227
|
continue
|
|
228
228
|
if pos_df is None and value == 0:
|
|
229
229
|
# Start of frame (first low after pause / EOF)
|
|
@@ -245,7 +245,7 @@ class Uart:
|
|
|
245
245
|
symbol = 0
|
|
246
246
|
pos_df = None
|
|
247
247
|
if off_tick and value == 0:
|
|
248
|
-
|
|
248
|
+
log.debug("Error - Off-sized step - but SigLow (@%d)", time)
|
|
249
249
|
self.events_symbols = np.concatenate(content).reshape((len(content), 2))
|
|
250
250
|
# TODO: numpy is converting timestamp to string -> must be added as tuple (ts, symbol)
|
|
251
251
|
# symbol_events[:, 0] = symbol_events[:, 0].astype(float) # noqa: ERA001
|