shepherd-core 2025.4.2__py3-none-any.whl → 2025.5.2__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.
Files changed (29) hide show
  1. shepherd_core/data_models/__init__.py +2 -0
  2. shepherd_core/data_models/content/_external_fixtures.yaml +32 -32
  3. shepherd_core/data_models/content/energy_environment.py +2 -2
  4. shepherd_core/data_models/content/virtual_harvester.py +4 -4
  5. shepherd_core/data_models/content/virtual_harvester_fixture.yaml +2 -2
  6. shepherd_core/data_models/content/virtual_source.py +4 -2
  7. shepherd_core/data_models/content/virtual_source_fixture.yaml +3 -3
  8. shepherd_core/data_models/experiment/experiment.py +2 -2
  9. shepherd_core/data_models/experiment/observer_features.py +102 -8
  10. shepherd_core/data_models/experiment/target_config.py +5 -0
  11. shepherd_core/data_models/task/__init__.py +6 -3
  12. shepherd_core/data_models/task/emulation.py +19 -3
  13. shepherd_core/data_models/task/programming.py +2 -1
  14. shepherd_core/data_models/testbed/mcu_fixture.yaml +4 -4
  15. shepherd_core/data_models/virtual_source_doc.txt +3 -3
  16. shepherd_core/fw_tools/converter.py +6 -3
  17. shepherd_core/fw_tools/validation.py +8 -4
  18. shepherd_core/reader.py +75 -46
  19. shepherd_core/testbed_client/client_abc_fix.py +2 -3
  20. shepherd_core/testbed_client/fixtures.py +2 -6
  21. shepherd_core/version.py +1 -1
  22. shepherd_core/vsource/virtual_harvester_simulation.py +1 -1
  23. shepherd_core/vsource/virtual_source_simulation.py +1 -1
  24. shepherd_core/writer.py +8 -8
  25. {shepherd_core-2025.4.2.dist-info → shepherd_core-2025.5.2.dist-info}/METADATA +1 -1
  26. {shepherd_core-2025.4.2.dist-info → shepherd_core-2025.5.2.dist-info}/RECORD +29 -29
  27. {shepherd_core-2025.4.2.dist-info → shepherd_core-2025.5.2.dist-info}/WHEEL +1 -1
  28. {shepherd_core-2025.4.2.dist-info → shepherd_core-2025.5.2.dist-info}/top_level.txt +0 -0
  29. {shepherd_core-2025.4.2.dist-info → shepherd_core-2025.5.2.dist-info}/zip-safe +0 -0
@@ -31,6 +31,7 @@ from .experiment.observer_features import GpioLevel
31
31
  from .experiment.observer_features import GpioTracing
32
32
  from .experiment.observer_features import PowerTracing
33
33
  from .experiment.observer_features import SystemLogging
34
+ from .experiment.observer_features import UartTracing
34
35
  from .experiment.target_config import TargetConfig
35
36
 
36
37
  __all__ = [
@@ -54,6 +55,7 @@ __all__ = [
54
55
  "ShpModel",
55
56
  "SystemLogging",
56
57
  "TargetConfig",
58
+ "UartTracing",
57
59
  "VirtualHarvesterConfig",
58
60
  "VirtualSourceConfig",
59
61
  "Wrapper",
@@ -1,5 +1,5 @@
1
1
  - datatype: EnergyEnvironment
2
- created: 2024-02-25 12:45:58.488609+02:00
2
+ created: 2025-05-12 17:28:39.756999+02:00
3
3
  parameters:
4
4
  id: 2639560972524229652
5
5
  name: eenv_static_2000mV_10mA_3600s
@@ -22,7 +22,7 @@
22
22
  indoor: true
23
23
  location: Lab-VSrc
24
24
  - datatype: EnergyEnvironment
25
- created: 2024-02-25 12:45:58.497654+02:00
25
+ created: 2025-05-12 17:28:39.764595+02:00
26
26
  parameters:
27
27
  id: 9823394105967169626
28
28
  name: eenv_static_2000mV_1mA_3600s
@@ -45,7 +45,7 @@
45
45
  indoor: true
46
46
  location: Lab-VSrc
47
47
  - datatype: EnergyEnvironment
48
- created: 2024-02-25 12:45:58.506739+02:00
48
+ created: 2025-05-12 17:28:39.772144+02:00
49
49
  parameters:
50
50
  id: 3900615675169501222
51
51
  name: eenv_static_2000mV_50mA_3600s
@@ -68,7 +68,7 @@
68
68
  indoor: true
69
69
  location: Lab-VSrc
70
70
  - datatype: EnergyEnvironment
71
- created: 2024-02-25 12:45:58.515790+02:00
71
+ created: 2025-05-12 17:28:39.779737+02:00
72
72
  parameters:
73
73
  id: 14796673729431137386
74
74
  name: eenv_static_2000mV_5mA_3600s
@@ -91,7 +91,7 @@
91
91
  indoor: true
92
92
  location: Lab-VSrc
93
93
  - datatype: EnergyEnvironment
94
- created: 2024-02-25 12:45:58.524761+02:00
94
+ created: 2025-05-12 17:28:39.787329+02:00
95
95
  parameters:
96
96
  id: 6648482606607441403
97
97
  name: eenv_static_3000mV_10mA_3600s
@@ -114,7 +114,7 @@
114
114
  indoor: true
115
115
  location: Lab-VSrc
116
116
  - datatype: EnergyEnvironment
117
- created: 2024-02-25 12:45:58.533513+02:00
117
+ created: 2025-05-12 17:28:39.794922+02:00
118
118
  parameters:
119
119
  id: 13566000951043177991
120
120
  name: eenv_static_3000mV_1mA_3600s
@@ -137,7 +137,7 @@
137
137
  indoor: true
138
138
  location: Lab-VSrc
139
139
  - datatype: EnergyEnvironment
140
- created: 2024-02-25 12:45:58.542278+02:00
140
+ created: 2025-05-12 17:28:39.802410+02:00
141
141
  parameters:
142
142
  id: 7977778327156610158
143
143
  name: eenv_static_3000mV_50mA_3600s
@@ -160,7 +160,7 @@
160
160
  indoor: true
161
161
  location: Lab-VSrc
162
162
  - datatype: EnergyEnvironment
163
- created: 2024-02-25 12:45:58.550974+02:00
163
+ created: 2025-05-12 17:28:39.810147+02:00
164
164
  parameters:
165
165
  id: 4900162978999238419
166
166
  name: eenv_static_3000mV_5mA_3600s
@@ -183,7 +183,7 @@
183
183
  indoor: true
184
184
  location: Lab-VSrc
185
185
  - datatype: Firmware
186
- created: 2024-02-25 12:45:58.568363+02:00
186
+ created: 2025-05-12 17:28:39.825659+02:00
187
187
  parameters:
188
188
  id: 3000
189
189
  name: msp430_deep_sleep
@@ -198,10 +198,10 @@
198
198
  mcu:
199
199
  id: 1002
200
200
  name: MSP430FR
201
- description: 16MHz Ultra-Low-Pwr MCU with 128 KB FRAM
201
+ description: 16MHz Ultra-Low-Pwr MCU with 256 KB FRAM
202
202
  comment: null
203
203
  platform: MSP430
204
- core: MSP430FR5962
204
+ core: MSP430FR5994
205
205
  prog_protocol: SBW
206
206
  prog_voltage: 3.0
207
207
  prog_datarate: 500000
@@ -211,7 +211,7 @@
211
211
  data_hash: null
212
212
  data_local: false
213
213
  - datatype: Firmware
214
- created: 2024-02-25 12:45:58.578594+02:00
214
+ created: 2025-05-12 17:28:39.834276+02:00
215
215
  parameters:
216
216
  id: 3001
217
217
  name: msp430_spi_fram
@@ -226,10 +226,10 @@
226
226
  mcu:
227
227
  id: 1002
228
228
  name: MSP430FR
229
- description: 16MHz Ultra-Low-Pwr MCU with 128 KB FRAM
229
+ description: 16MHz Ultra-Low-Pwr MCU with 256 KB FRAM
230
230
  comment: null
231
231
  platform: MSP430
232
- core: MSP430FR5962
232
+ core: MSP430FR5994
233
233
  prog_protocol: SBW
234
234
  prog_voltage: 3.0
235
235
  prog_datarate: 500000
@@ -239,7 +239,7 @@
239
239
  data_hash: null
240
240
  data_local: false
241
241
  - datatype: Firmware
242
- created: 2024-02-25 12:45:58.589223+02:00
242
+ created: 2025-05-12 17:28:39.842993+02:00
243
243
  parameters:
244
244
  id: 3002
245
245
  name: msp430_testable
@@ -254,10 +254,10 @@
254
254
  mcu:
255
255
  id: 1002
256
256
  name: MSP430FR
257
- description: 16MHz Ultra-Low-Pwr MCU with 128 KB FRAM
257
+ description: 16MHz Ultra-Low-Pwr MCU with 256 KB FRAM
258
258
  comment: null
259
259
  platform: MSP430
260
- core: MSP430FR5962
260
+ core: MSP430FR5994
261
261
  prog_protocol: SBW
262
262
  prog_voltage: 3.0
263
263
  prog_datarate: 500000
@@ -267,7 +267,7 @@
267
267
  data_hash: null
268
268
  data_local: false
269
269
  - datatype: Firmware
270
- created: 2024-02-25 12:45:58.599274+02:00
270
+ created: 2025-05-12 17:28:39.851412+02:00
271
271
  parameters:
272
272
  id: 7163917825449888392
273
273
  name: nrf52_deep_sleep
@@ -282,20 +282,20 @@
282
282
  mcu:
283
283
  id: 1001
284
284
  name: nRF52
285
- description: Panasonic PAN1780, ENW-89854A1KF, Bluetooth 5 Low Energy Module
285
+ description: MCU with RF, 802.15.4, Bluetooth v5.0, 2.4GHz
286
286
  comment: null
287
287
  platform: nRF52
288
288
  core: nRF52840
289
289
  prog_protocol: SWD
290
290
  prog_voltage: 3.0
291
291
  prog_datarate: 500000
292
- fw_name_default: nrf52_demo_rf
292
+ fw_name_default: nrf52_deep_sleep
293
293
  data: /var/shepherd/content/fw/nes_lab/nrf52_deep_sleep/build.elf
294
294
  data_type: path_elf
295
295
  data_hash: null
296
296
  data_local: false
297
297
  - datatype: Firmware
298
- created: 2024-02-25 12:45:58.609313+02:00
298
+ created: 2025-05-12 17:28:39.859962+02:00
299
299
  parameters:
300
300
  id: 2000
301
301
  name: nrf52_demo_rf
@@ -310,20 +310,20 @@
310
310
  mcu:
311
311
  id: 1001
312
312
  name: nRF52
313
- description: Panasonic PAN1780, ENW-89854A1KF, Bluetooth 5 Low Energy Module
313
+ description: MCU with RF, 802.15.4, Bluetooth v5.0, 2.4GHz
314
314
  comment: null
315
315
  platform: nRF52
316
316
  core: nRF52840
317
317
  prog_protocol: SWD
318
318
  prog_voltage: 3.0
319
319
  prog_datarate: 500000
320
- fw_name_default: nrf52_demo_rf
320
+ fw_name_default: nrf52_deep_sleep
321
321
  data: /var/shepherd/content/fw/nes_lab/nrf52_demo_rf/build.elf
322
322
  data_type: path_elf
323
323
  data_hash: null
324
324
  data_local: false
325
325
  - datatype: Firmware
326
- created: 2024-02-25 12:45:58.619155+02:00
326
+ created: 2025-05-12 17:28:39.868340+02:00
327
327
  parameters:
328
328
  id: 3174430733058172825
329
329
  name: nrf52_rf_survey
@@ -339,20 +339,20 @@
339
339
  mcu:
340
340
  id: 1001
341
341
  name: nRF52
342
- description: Panasonic PAN1780, ENW-89854A1KF, Bluetooth 5 Low Energy Module
342
+ description: MCU with RF, 802.15.4, Bluetooth v5.0, 2.4GHz
343
343
  comment: null
344
344
  platform: nRF52
345
345
  core: nRF52840
346
346
  prog_protocol: SWD
347
347
  prog_voltage: 3.0
348
348
  prog_datarate: 500000
349
- fw_name_default: nrf52_demo_rf
349
+ fw_name_default: nrf52_deep_sleep
350
350
  data: /var/shepherd/content/fw/nes_lab/nrf52_rf_survey/build.elf
351
351
  data_type: path_elf
352
352
  data_hash: null
353
353
  data_local: false
354
354
  - datatype: Firmware
355
- created: 2024-02-25 12:45:58.628815+02:00
355
+ created: 2025-05-12 17:28:39.876819+02:00
356
356
  parameters:
357
357
  id: 16381936580724580968
358
358
  name: nrf52_rf_test
@@ -367,20 +367,20 @@
367
367
  mcu:
368
368
  id: 1001
369
369
  name: nRF52
370
- description: Panasonic PAN1780, ENW-89854A1KF, Bluetooth 5 Low Energy Module
370
+ description: MCU with RF, 802.15.4, Bluetooth v5.0, 2.4GHz
371
371
  comment: null
372
372
  platform: nRF52
373
373
  core: nRF52840
374
374
  prog_protocol: SWD
375
375
  prog_voltage: 3.0
376
376
  prog_datarate: 500000
377
- fw_name_default: nrf52_demo_rf
377
+ fw_name_default: nrf52_deep_sleep
378
378
  data: /var/shepherd/content/fw/nes_lab/nrf52_rf_test/build.elf
379
379
  data_type: path_elf
380
380
  data_hash: null
381
381
  data_local: false
382
382
  - datatype: Firmware
383
- created: 2024-02-25 12:45:58.638812+02:00
383
+ created: 2025-05-12 17:28:39.885271+02:00
384
384
  parameters:
385
385
  id: 2002
386
386
  name: nrf52_testable
@@ -396,14 +396,14 @@
396
396
  mcu:
397
397
  id: 1001
398
398
  name: nRF52
399
- description: Panasonic PAN1780, ENW-89854A1KF, Bluetooth 5 Low Energy Module
399
+ description: MCU with RF, 802.15.4, Bluetooth v5.0, 2.4GHz
400
400
  comment: null
401
401
  platform: nRF52
402
402
  core: nRF52840
403
403
  prog_protocol: SWD
404
404
  prog_voltage: 3.0
405
405
  prog_datarate: 500000
406
- fw_name_default: nrf52_demo_rf
406
+ fw_name_default: nrf52_deep_sleep
407
407
  data: /var/shepherd/content/fw/nes_lab/nrf52_testable/build.elf
408
408
  data_type: path_elf
409
409
  data_hash: null
@@ -15,8 +15,8 @@ from shepherd_core.testbed_client import tb_client
15
15
  class EnergyDType(str, Enum):
16
16
  """Data-Type-Options for energy environments."""
17
17
 
18
- ivsample = ivsamples = "ivsample"
19
- ivcurve = ivcurves = ivsurface = "ivcurve"
18
+ ivtrace = ivsample = ivsamples = "ivsample"
19
+ ivsurface = ivcurve = ivcurves = "ivcurve"
20
20
  isc_voc = "isc_voc"
21
21
 
22
22
 
@@ -23,9 +23,9 @@ from .energy_environment import EnergyDType
23
23
  class AlgorithmDType(str, Enum):
24
24
  """Options for choosing a harvesting algorithm."""
25
25
 
26
- direct = disable = neutral = "neutral"
27
- isc_voc = "isc_voc"
28
- ivcurve = ivcurves = ("ivcurve",)
26
+ direct = disable = neutral = "neutral" # for just using IVTrace / samples
27
+ isc_voc = "isc_voc" # only recordable ATM
28
+ ivcurve = ivcurves = ivsurface = "ivcurve"
29
29
  constant = cv = "cv"
30
30
  # ci .. constant current -> is this desired?
31
31
  mppt_voc = "mppt_voc"
@@ -37,7 +37,7 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
37
37
  """A vHrv makes a source-characterization (i.e. ivcurve) usable for the vSrc.
38
38
 
39
39
  Mostly used when the file-based energy environment of the virtual source
40
- is not already supplied as pre-harvested ivsample-stream.
40
+ is not already supplied as pre-harvested ivtrace.
41
41
  """
42
42
 
43
43
  # General Metadata & Ownership -> ContentModel
@@ -21,7 +21,7 @@
21
21
  parameters:
22
22
  id: 1100
23
23
  name: ivcurve
24
- description: Postpone harvesting by sampling ivcurves (voltage stepped as sawtooth-wave)
24
+ description: Postpone harvesting by sampling ivsurface / curves (voltage stepped as sawtooth-wave)
25
25
  comment: ~110 Hz, Between 50 & 60 Hz line-frequency to avoid standing waves
26
26
  inherit_from: neutral
27
27
  algorithm: ivcurve
@@ -36,7 +36,7 @@
36
36
  - datatype: VirtualHarvesterConfig
37
37
  parameters:
38
38
  id: 1101
39
- name: ivcurves # synonym
39
+ name: ivsurface # synonym
40
40
  inherit_from: ivcurve
41
41
 
42
42
  - datatype: VirtualHarvesterConfig
@@ -33,7 +33,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
33
33
  The converter-stage is software defined and offers:
34
34
  - buck-boost-combinations,
35
35
  - a simple diode + resistor and
36
- - an intermediate buffer capacitor.
36
+ - an intermediate storage capacitor.
37
37
  """
38
38
 
39
39
  # TODO: I,V,R should be in regular unit (V, A, Ohm)
@@ -82,6 +82,8 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
82
82
  C_output_uF: Annotated[float, Field(ge=0, le=4.29e6)] = 1.0
83
83
  # TODO: C_output is handled internally as delta-V, but should be a I_transient
84
84
  # that makes it visible in simulation as additional i_out_drain
85
+ # TODO: potential weakness, ACD lowpass is capturing transient,
86
+ # but energy is LOST with this model
85
87
 
86
88
  # Extra
87
89
  V_output_log_gpio_threshold_mV: Annotated[float, Field(ge=0, le=4.29e6)] = 1_400
@@ -105,7 +107,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
105
107
  # Buck Converter
106
108
  V_output_mV: Annotated[float, Field(ge=0, le=5_000)] = 2_400
107
109
  V_buck_drop_mV: Annotated[float, Field(ge=0, le=5_000)] = 0
108
- # ⤷ simulate LDO min voltage differential or output-diode
110
+ # ⤷ simulate LDO / diode min voltage differential or output-diode
109
111
 
110
112
  LUT_output_efficiency: LUT1D = 12 * [1.00]
111
113
  # ⤷ array[12] depending on output_current
@@ -93,7 +93,7 @@
93
93
  parameters:
94
94
  id: 1011
95
95
  name: diode+capacitor
96
- description: Simple Converter based on diode and buffer capacitor
96
+ description: Simple Converter based on diode and storage capacitor
97
97
  inherit_from: neutral
98
98
  V_input_drop_mV: 300 # simulate input-diode
99
99
  C_intermediate_uF: 47 # primary storage-Cap
@@ -114,7 +114,7 @@
114
114
  parameters:
115
115
  id: 1013
116
116
  name: diode+resistor+capacitor
117
- description: Simple Converter based on diode, current limiting resistor and buffer capacitor
117
+ description: Simple Converter based on diode, current limiting resistor and storage capacitor
118
118
  inherit_from: diode+capacitor
119
119
  R_input_mOhm: 10000
120
120
 
@@ -133,7 +133,7 @@
133
133
  enable_boost: true # if false -> v_intermediate = v_input, output-switch-hysteresis is still usable
134
134
 
135
135
  harvester:
136
- name: mppt_bq_solar # harvester only active if input is "ivcurves"
136
+ name: mppt_bq_solar # harvester only active if input is ivsurface / curves
137
137
 
138
138
  V_input_max_mV: 3000
139
139
  I_input_max_mA: 100
@@ -46,7 +46,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
46
46
  # feedback
47
47
  email_results: bool = False
48
48
 
49
- sys_logging: SystemLogging = SystemLogging(dmesg=True, ptp=True, shepherd=True)
49
+ sys_logging: SystemLogging = SystemLogging() # = all active
50
50
 
51
51
  # schedule
52
52
  time_start: Optional[datetime] = None # = ASAP
@@ -56,7 +56,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
56
56
  # targets
57
57
  target_configs: Annotated[list[TargetConfig], Field(min_length=1, max_length=128)]
58
58
 
59
- # for debug-purposes and later comp-checks
59
+ # debug
60
60
  lib_ver: Optional[str] = version
61
61
 
62
62
  @model_validator(mode="after")
@@ -10,6 +10,7 @@ from pydantic import Field
10
10
  from pydantic import PositiveFloat
11
11
  from pydantic import model_validator
12
12
  from typing_extensions import Self
13
+ from typing_extensions import deprecated
13
14
 
14
15
  from shepherd_core.data_models.base.shepherd import ShpModel
15
16
  from shepherd_core.data_models.testbed.gpio import GPIO
@@ -22,7 +23,7 @@ class PowerTracing(ShpModel, title="Config for Power-Tracing"):
22
23
  """
23
24
 
24
25
  intermediate_voltage: bool = False
25
- # ⤷ for EMU: record buffer capacitor instead of output (good for V_out = const)
26
+ # ⤷ for EMU: record storage capacitor instead of output (good for V_out = const)
26
27
  # this also includes current!
27
28
 
28
29
  # time
@@ -47,7 +48,87 @@ class PowerTracing(ShpModel, title="Config for Power-Tracing"):
47
48
  if not self.calculate_power and discard_all:
48
49
  raise ValueError("Error in config -> tracing enabled, but output gets discarded")
49
50
  if self.calculate_power:
50
- raise NotImplementedError("postprocessing not implemented ATM")
51
+ raise NotImplementedError(
52
+ "Feature PowerTracing.calculate_power reserved for future use."
53
+ )
54
+ if self.samplerate != 100_000:
55
+ raise NotImplementedError("Feature PowerTracing.samplerate reserved for future use.")
56
+ if self.discard_current:
57
+ raise NotImplementedError(
58
+ "Feature PowerTracing.discard_current reserved for future use."
59
+ )
60
+ if self.discard_voltage:
61
+ raise NotImplementedError(
62
+ "Feature PowerTracing.discard_voltage reserved for future use."
63
+ )
64
+ return self
65
+
66
+
67
+ # NOTE: this was taken from pyserial (removes one dependency)
68
+ BAUDRATES = (
69
+ 50,
70
+ 75,
71
+ 110,
72
+ 134,
73
+ 150,
74
+ 200,
75
+ 300,
76
+ 600,
77
+ 1200,
78
+ 1800,
79
+ 2400,
80
+ 4800,
81
+ 9600,
82
+ 19200,
83
+ 38400,
84
+ 57600,
85
+ 115200,
86
+ 230400,
87
+ 460800,
88
+ 500000,
89
+ 576000,
90
+ 921600,
91
+ 1000000,
92
+ 1152000,
93
+ 1500000,
94
+ 2000000,
95
+ 2500000,
96
+ 3000000,
97
+ 3500000,
98
+ 4000000,
99
+ )
100
+
101
+ PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = "N", "E", "O", "M", "S"
102
+ PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
103
+
104
+ STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
105
+ STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
106
+
107
+
108
+ class UartTracing(ShpModel, title="Config for UART Tracing"):
109
+ """Configuration for recording UART-Output of the Target Nodes.
110
+
111
+ Note that the Communication has to be on a specific port that
112
+ reaches the hardware-module of the SBC.
113
+ """
114
+
115
+ baudrate: Annotated[int, Field(ge=2_400, le=460_800)] = 115_200
116
+ # ⤷ TODO: find maximum that the system can handle
117
+ bytesize: Annotated[int, Field(ge=5, le=8)] = 8
118
+ stopbits: Annotated[float, Field(ge=1, le=2)] = 1
119
+ parity: str = PARITY_NONE
120
+
121
+ @model_validator(mode="after")
122
+ def post_validation(self) -> Self:
123
+ if self.baudrate not in BAUDRATES:
124
+ msg = f"Error in config -> baud-rate must be one of: {BAUDRATES}"
125
+ raise ValueError(msg)
126
+ if self.stopbits not in STOPBITS:
127
+ msg = f"Error in config -> stop-bits must be one of: {STOPBITS}"
128
+ raise ValueError(msg)
129
+ if self.parity not in PARITIES:
130
+ msg = f"Error in config -> parity must be one of: {PARITIES}"
131
+ raise ValueError(msg)
51
132
  return self
52
133
 
53
134
 
@@ -72,7 +153,7 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
72
153
  # TODO: quickfix - uart-log currently done online in userspace
73
154
  # NOTE: gpio-tracing currently shows rather big - but rare - "blind" windows (~1-4us)
74
155
  uart_pin: GPIO = GPIO(name="GPIO8")
75
- uart_baudrate: Annotated[int, Field(ge=2_400, le=921_600)] = 115_200
156
+ uart_baudrate: Annotated[int, Field(ge=2_400, le=1_152_000)] = 115_200
76
157
  # TODO: add a "discard_gpio" (if only uart is wanted)
77
158
 
78
159
  @model_validator(mode="after")
@@ -83,6 +164,15 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
83
164
  raise ValueError("Delay can't be negative.")
84
165
  if self.duration and self.duration.total_seconds() < 0:
85
166
  raise ValueError("Duration can't be negative.")
167
+ if self.mask != 0b11_1111_1111: # GpioTracing.mask
168
+ raise NotImplementedError("Feature GpioTracing.mask reserved for future use.")
169
+ if self.gpios is not None:
170
+ raise NotImplementedError("Feature GpioTracing.gpios reserved for future use.")
171
+ if self.uart_decode:
172
+ raise NotImplementedError(
173
+ "Feature GpioTracing.uart_decode reserved for future use. "
174
+ "Use UartTracing or manually decode serial with the provided waveform decoder."
175
+ )
86
176
  return self
87
177
 
88
178
 
@@ -133,11 +223,15 @@ class GpioActuation(ShpModel, title="Config for GPIO-Actuation"):
133
223
  class SystemLogging(ShpModel, title="Config for System-Logging"):
134
224
  """Configuration for recording Debug-Output of the Observers System-Services."""
135
225
 
136
- dmesg: bool = True
137
- ptp: bool = True
138
- shepherd: bool = True
139
- # TODO: rename to kernel, timesync, sheep
140
- # TODO: add utilization as option
226
+ kernel: bool = True
227
+ time_sync: bool = True
228
+ sheep: bool = True
229
+ sys_util: bool = True
230
+
231
+ # TODO: remove lines below in 2026
232
+ dmesg: Annotated[bool, deprecated("for sheep v0.9.0+, use 'kernel' instead")] = True
233
+ ptp: Annotated[bool, deprecated("for sheep v0.9.0+, use 'time_sync' instead")] = True
234
+ shepherd: Annotated[bool, deprecated("for sheep v0.9.0+, use 'sheep' instead")] = True
141
235
 
142
236
 
143
237
  # TODO: some more interaction would be good
@@ -18,6 +18,7 @@ from shepherd_core.data_models.testbed.target import Target
18
18
  from .observer_features import GpioActuation
19
19
  from .observer_features import GpioTracing
20
20
  from .observer_features import PowerTracing
21
+ from .observer_features import UartTracing
21
22
 
22
23
 
23
24
  class TargetConfig(ShpModel, title="Target Config"):
@@ -38,9 +39,11 @@ class TargetConfig(ShpModel, title="Target Config"):
38
39
 
39
40
  firmware1: Firmware
40
41
  firmware2: Optional[Firmware] = None
42
+ # ⤷ omitted FW gets set to neutral deep-sleep
41
43
 
42
44
  power_tracing: Optional[PowerTracing] = None
43
45
  gpio_tracing: Optional[GpioTracing] = None
46
+ uart_tracing: Optional[UartTracing] = None
44
47
  gpio_actuation: Optional[GpioActuation] = None
45
48
 
46
49
  @model_validator(mode="after")
@@ -79,6 +82,8 @@ class TargetConfig(ShpModel, title="Target Config"):
79
82
  msg = f"Provided custom IDs {c_ids} not enough to cover target range {t_ids}"
80
83
  raise ValueError(msg)
81
84
  # TODO: if custom ids present, firmware must be ELF
85
+ if self.gpio_actuation is not None:
86
+ raise NotImplementedError("Feature GpioActuation reserved for future use.")
82
87
  return self
83
88
 
84
89
  def get_custom_id(self, target_id: int) -> Optional[int]:
@@ -54,7 +54,8 @@ def prepare_task(config: Union[ShpModel, Path, str], observer: Optional[str] = N
54
54
  parameters=config.model_dump(),
55
55
  )
56
56
  else:
57
- raise TypeError("had unknown input: %s", type(config))
57
+ msg = f"had unknown input: {type(config)}"
58
+ raise TypeError(msg)
58
59
 
59
60
  if shp_wrap.datatype == TestbedTasks.__name__:
60
61
  if observer is None:
@@ -66,7 +67,8 @@ def prepare_task(config: Union[ShpModel, Path, str], observer: Optional[str] = N
66
67
  logger.debug("Loading Testbed-Tasks %s for %s", tbt.name, observer)
67
68
  obt = tbt.get_observer_tasks(observer)
68
69
  if obt is None:
69
- raise ValueError("Observer '%s' is not in TestbedTask-Set", observer)
70
+ msg = f"Observer '{observer}' is not in TestbedTask-Set"
71
+ raise ValueError(msg)
70
72
  shp_wrap = Wrapper(
71
73
  datatype=type(obt).__name__,
72
74
  parameters=obt.model_dump(),
@@ -92,6 +94,7 @@ def extract_tasks(shp_wrap: Wrapper, *, no_task_sets: bool = True) -> list[ShpMo
92
94
  raise ValueError("Model in Wrapper was TestbedTasks -> Task-Sets not allowed!")
93
95
  content = [TestbedTasks(**shp_wrap.parameters)]
94
96
  else:
95
- raise ValueError("Extractor had unknown task: %s", shp_wrap.datatype)
97
+ msg = f"Extractor had unknown task: {shp_wrap.datatype}"
98
+ raise ValueError(msg)
96
99
 
97
100
  return content
@@ -23,8 +23,10 @@ from shepherd_core.data_models.experiment.observer_features import GpioActuation
23
23
  from shepherd_core.data_models.experiment.observer_features import GpioTracing
24
24
  from shepherd_core.data_models.experiment.observer_features import PowerTracing
25
25
  from shepherd_core.data_models.experiment.observer_features import SystemLogging
26
+ from shepherd_core.data_models.experiment.observer_features import UartTracing
26
27
  from shepherd_core.data_models.testbed import Testbed
27
28
  from shepherd_core.data_models.testbed.cape import TargetPort
29
+ from shepherd_core.logger import logger
28
30
 
29
31
 
30
32
  class Compression(str, Enum):
@@ -67,10 +69,10 @@ class EmulationTask(ShpModel):
67
69
  use_cal_default: bool = False
68
70
  # ⤷ Use default calibration values, skip loading from EEPROM
69
71
 
70
- enable_io: bool = False
72
+ enable_io: bool = True
71
73
  # TODO: add direction of pins! also it seems error-prone when only setting _tracing
72
74
  # ⤷ Switch the GPIO level converter to targets on/off
73
- # pre-req for sampling gpio,
75
+ # pre-req for sampling gpio / uart,
74
76
  io_port: TargetPort = TargetPort.A
75
77
  # ⤷ Either Port A or B that gets connected to IO
76
78
  pwr_port: TargetPort = TargetPort.A
@@ -89,6 +91,7 @@ class EmulationTask(ShpModel):
89
91
 
90
92
  power_tracing: Optional[PowerTracing] = PowerTracing()
91
93
  gpio_tracing: Optional[GpioTracing] = GpioTracing()
94
+ uart_tracing: Optional[UartTracing] = UartTracing()
92
95
  gpio_actuation: Optional[GpioActuation] = None
93
96
  sys_logging: Optional[SystemLogging] = SystemLogging()
94
97
 
@@ -127,6 +130,14 @@ class EmulationTask(ShpModel):
127
130
  raise ValueError("Voltage Aux must be in float (0 - 4.5) or string 'main' / 'mid'.")
128
131
  if self.gpio_actuation is not None:
129
132
  raise ValueError("GPIO Actuation not yet implemented!")
133
+
134
+ io_requested = any(
135
+ _io is not None for _io in (self.gpio_actuation, self.gpio_tracing, self.uart_tracing)
136
+ )
137
+ if self.enable_io and not io_requested:
138
+ logger.warning("Target IO enabled, but no feature requested IO")
139
+ if not self.enable_io and io_requested:
140
+ logger.warning("Target IO not enabled, but a feature requested IO")
130
141
  return self
131
142
 
132
143
  @classmethod
@@ -134,6 +145,10 @@ class EmulationTask(ShpModel):
134
145
  def from_xp(cls, xp: Experiment, tb: Testbed, tgt_id: IdInt, root_path: Path) -> Self:
135
146
  obs = tb.get_observer(tgt_id)
136
147
  tgt_cfg = xp.get_target_config(tgt_id)
148
+ io_requested = any(
149
+ _io is not None
150
+ for _io in (tgt_cfg.gpio_actuation, tgt_cfg.gpio_tracing, tgt_cfg.uart_tracing)
151
+ )
137
152
 
138
153
  return cls(
139
154
  input_path=tgt_cfg.energy_env.data_path,
@@ -141,12 +156,13 @@ class EmulationTask(ShpModel):
141
156
  time_start=copy.copy(xp.time_start),
142
157
  duration=xp.duration,
143
158
  abort_on_error=xp.abort_on_error,
144
- enable_io=(tgt_cfg.gpio_tracing is not None) or (tgt_cfg.gpio_actuation is not None),
159
+ enable_io=io_requested,
145
160
  io_port=obs.get_target_port(tgt_id),
146
161
  pwr_port=obs.get_target_port(tgt_id),
147
162
  virtual_source=tgt_cfg.virtual_source,
148
163
  power_tracing=tgt_cfg.power_tracing,
149
164
  gpio_tracing=tgt_cfg.gpio_tracing,
165
+ uart_tracing=tgt_cfg.uart_tracing,
150
166
  gpio_actuation=tgt_cfg.gpio_actuation,
151
167
  sys_logging=xp.sys_logging,
152
168
  )