shepherd-core 2024.4.1__py3-none-any.whl → 2024.5.1__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 (76) hide show
  1. shepherd_core/__init__.py +3 -3
  2. shepherd_core/calibration_hw_def.py +9 -1
  3. shepherd_core/commons.py +2 -0
  4. shepherd_core/data_models/__init__.py +11 -0
  5. shepherd_core/data_models/base/__init__.py +4 -1
  6. shepherd_core/data_models/base/cal_measurement.py +18 -6
  7. shepherd_core/data_models/base/calibration.py +39 -15
  8. shepherd_core/data_models/base/content.py +10 -2
  9. shepherd_core/data_models/base/shepherd.py +21 -12
  10. shepherd_core/data_models/base/timezone.py +5 -0
  11. shepherd_core/data_models/base/wrapper.py +3 -3
  12. shepherd_core/data_models/content/__init__.py +5 -4
  13. shepherd_core/data_models/content/_external_fixtures.yaml +410 -0
  14. shepherd_core/data_models/content/energy_environment.py +7 -5
  15. shepherd_core/data_models/content/energy_environment_fixture.yaml +53 -0
  16. shepherd_core/data_models/content/firmware.py +12 -5
  17. shepherd_core/data_models/content/firmware_datatype.py +7 -0
  18. shepherd_core/data_models/content/virtual_harvester.py +24 -19
  19. shepherd_core/data_models/content/virtual_harvester_fixture.yaml +160 -0
  20. shepherd_core/data_models/content/virtual_source.py +22 -10
  21. shepherd_core/data_models/content/virtual_source_fixture.yaml +230 -0
  22. shepherd_core/data_models/experiment/__init__.py +5 -4
  23. shepherd_core/data_models/experiment/experiment.py +7 -6
  24. shepherd_core/data_models/experiment/observer_features.py +14 -7
  25. shepherd_core/data_models/experiment/target_config.py +11 -7
  26. shepherd_core/data_models/readme.md +88 -0
  27. shepherd_core/data_models/task/__init__.py +10 -3
  28. shepherd_core/data_models/task/emulation.py +10 -7
  29. shepherd_core/data_models/task/firmware_mod.py +4 -2
  30. shepherd_core/data_models/task/harvest.py +5 -4
  31. shepherd_core/data_models/task/observer_tasks.py +3 -1
  32. shepherd_core/data_models/task/programming.py +3 -1
  33. shepherd_core/data_models/task/testbed_tasks.py +3 -1
  34. shepherd_core/data_models/testbed/__init__.py +5 -2
  35. shepherd_core/data_models/testbed/cape.py +7 -5
  36. shepherd_core/data_models/testbed/cape_fixture.yaml +94 -0
  37. shepherd_core/data_models/testbed/gpio.py +10 -8
  38. shepherd_core/data_models/testbed/gpio_fixture.yaml +166 -0
  39. shepherd_core/data_models/testbed/mcu.py +9 -9
  40. shepherd_core/data_models/testbed/mcu_fixture.yaml +19 -0
  41. shepherd_core/data_models/testbed/observer.py +9 -4
  42. shepherd_core/data_models/testbed/observer_fixture.yaml +221 -0
  43. shepherd_core/data_models/testbed/target.py +4 -2
  44. shepherd_core/data_models/testbed/target_fixture.yaml +137 -0
  45. shepherd_core/data_models/testbed/testbed.py +5 -2
  46. shepherd_core/data_models/testbed/testbed_fixture.yaml +25 -0
  47. shepherd_core/decoder_waveform/__init__.py +2 -0
  48. shepherd_core/decoder_waveform/uart.py +43 -25
  49. shepherd_core/fw_tools/__init__.py +2 -0
  50. shepherd_core/fw_tools/converter.py +20 -9
  51. shepherd_core/fw_tools/converter_elf.py +3 -0
  52. shepherd_core/fw_tools/patcher.py +17 -5
  53. shepherd_core/fw_tools/validation.py +27 -6
  54. shepherd_core/inventory/__init__.py +15 -5
  55. shepherd_core/inventory/python.py +4 -0
  56. shepherd_core/inventory/system.py +6 -2
  57. shepherd_core/inventory/target.py +4 -0
  58. shepherd_core/logger.py +5 -0
  59. shepherd_core/reader.py +38 -23
  60. shepherd_core/testbed_client/__init__.py +2 -0
  61. shepherd_core/testbed_client/cache_path.py +2 -0
  62. shepherd_core/testbed_client/client.py +15 -8
  63. shepherd_core/testbed_client/fixtures.py +27 -11
  64. shepherd_core/testbed_client/user_model.py +8 -3
  65. shepherd_core/vsource/__init__.py +2 -0
  66. shepherd_core/vsource/virtual_converter_model.py +10 -3
  67. shepherd_core/vsource/virtual_harvester_model.py +7 -1
  68. shepherd_core/vsource/virtual_source_model.py +9 -5
  69. shepherd_core/writer.py +26 -21
  70. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/METADATA +2 -1
  71. shepherd_core-2024.5.1.dist-info/RECORD +75 -0
  72. shepherd_core-2024.4.1.dist-info/RECORD +0 -64
  73. /shepherd_core/data_models/{doc_virtual_source.py → virtual_source_doc.txt} +0 -0
  74. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/WHEEL +0 -0
  75. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/top_level.txt +0 -0
  76. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/zip-safe +0 -0
@@ -1,3 +1,5 @@
1
+ """meta-data representation of a testbed-component (physical object)."""
2
+
1
3
  from datetime import datetime
2
4
  from typing import Optional
3
5
 
@@ -24,7 +26,7 @@ MACStr = Annotated[
24
26
 
25
27
 
26
28
  class Observer(ShpModel, title="Shepherd-Sheep"):
27
- """meta-data representation of a testbed-component (physical object)"""
29
+ """meta-data representation of a testbed-component (physical object)."""
28
30
 
29
31
  id: IdInt
30
32
  name: NameStr
@@ -63,7 +65,8 @@ class Observer(ShpModel, title="Shepherd-Sheep"):
63
65
  has_cape = self.cape is not None
64
66
  has_target = (self.target_a is not None) or (self.target_b is not None)
65
67
  if not has_cape and has_target:
66
- raise ValueError(f"Observer '{self.name}' is faulty -> has targets but no cape")
68
+ msg = f"Observer '{self.name}' is faulty -> has targets but no cape"
69
+ raise ValueError(msg)
67
70
  return self
68
71
 
69
72
  def has_target(self, target_id: int) -> bool:
@@ -79,7 +82,8 @@ class Observer(ShpModel, title="Shepherd-Sheep"):
79
82
  return TargetPort.A
80
83
  if self.target_b is not None and target_id == self.target_b.id:
81
84
  return TargetPort.B
82
- raise ValueError(f"Target-ID {target_id} was not found in Observer '{self.name}'")
85
+ msg = f"Target-ID {target_id} was not found in Observer '{self.name}'"
86
+ raise KeyError(msg)
83
87
 
84
88
  def get_target(self, target_id: int) -> Target:
85
89
  if self.has_target(target_id):
@@ -87,4 +91,5 @@ class Observer(ShpModel, title="Shepherd-Sheep"):
87
91
  return self.target_a
88
92
  if self.target_b is not None and target_id == self.target_b.id:
89
93
  return self.target_b
90
- raise ValueError(f"Target-ID {target_id} was not found in Observer '{self.name}'")
94
+ msg = f"Target-ID {target_id} was not found in Observer '{self.name}'"
95
+ raise KeyError(msg)
@@ -0,0 +1,221 @@
1
+ ---
2
+ # observer-cape-target-relation: https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Cape_pre-deployment-tests.xlsx
3
+ # network data: https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/ethernet_MAC_addresses_bbones.ods
4
+ - datatype: observer
5
+ parameters:
6
+ id: 0
7
+ name: sheep0
8
+ ip: 10.0.0.20
9
+ mac: 18:00:C0:FF:EE:77
10
+ room: at-home
11
+ eth_port: unimatrix_zero_one
12
+ description: lab / dev
13
+ longitude: 0
14
+ latitude: 0
15
+ cape:
16
+ name: cape53
17
+ target_a:
18
+ name: nRF52_FRAM_018
19
+ created: 2022-12-12 12:12:12
20
+ active: false
21
+ - datatype: observer
22
+ parameters:
23
+ id: 1
24
+ name: sheep01
25
+ ip: 192.168.165.201
26
+ mac: 18:62:E4:E4:41:8D
27
+ room: II70
28
+ eth_port: B22
29
+ description: mid-mid in room
30
+ cape:
31
+ name: cape51
32
+ target_a:
33
+ name: nRF52_FRAM_001
34
+ created: 2023-09-22 12:12:12
35
+ - datatype: observer
36
+ parameters:
37
+ id: 2
38
+ name: sheep02
39
+ ip: 192.168.165.202
40
+ mac: 18:62:E4:D0:DE:3F
41
+ room: II66
42
+ eth_port: A18
43
+ description: south-west corner
44
+ cape:
45
+ name: cape52
46
+ target_a:
47
+ name: nRF52_FRAM_002
48
+ created: 2023-09-22 12:12:12
49
+ - datatype: observer
50
+ parameters:
51
+ id: 3
52
+ name: sheep03
53
+ ip: 192.168.165.203
54
+ mac: 18:62:E4:D0:9E:6A
55
+ room: II69
56
+ eth_port: B10
57
+ description: north-east-corner
58
+ cape:
59
+ name: cape63
60
+ target_a:
61
+ name: nRF52_FRAM_003
62
+ created: 2023-09-22 12:12:12
63
+ - datatype: observer
64
+ parameters:
65
+ id: 4
66
+ name: sheep04
67
+ ip: 192.168.165.204
68
+ mac: 18:62:E4:D0:61:4D
69
+ room: II72
70
+ eth_port: C6
71
+ description: mid on east-side
72
+ cape:
73
+ name: cape54
74
+ target_a:
75
+ name: nRF52_FRAM_004
76
+ created: 2023-09-22 12:12:12
77
+ - datatype: observer
78
+ parameters:
79
+ id: 5
80
+ name: sheep05
81
+ ip: 192.168.165.205
82
+ mac: 18:62:E4:E3:6E:13
83
+ room: II75
84
+ eth_port: D10
85
+ description: south-west corner
86
+ cape:
87
+ name: cape55
88
+ target_a:
89
+ name: nRF52_FRAM_011
90
+ target_b:
91
+ name: target_nRF52_01 # ONLY VIRTUAL - for unittests
92
+ created: 2023-09-22 12:12:12
93
+ - datatype: observer
94
+ parameters:
95
+ id: 6
96
+ name: sheep06
97
+ ip: 192.168.165.206
98
+ mac: 18:62:E4:D0:AF:0B
99
+ room: II64
100
+ eth_port: L14
101
+ description: mid on north-side
102
+ cape:
103
+ name: cape56
104
+ target_a:
105
+ name: nRF52_FRAM_017 # TODO: not validated
106
+ created: 2023-09-22 12:12:12
107
+ - datatype: observer
108
+ parameters:
109
+ id: 7
110
+ name: sheep07
111
+ ip: 192.168.165.207
112
+ mac: 18:62:E4:E4:39:D7
113
+ room: II66
114
+ eth_port: A20
115
+ description: north-west-corner
116
+ cape:
117
+ name: cape57
118
+ target_a:
119
+ name: nRF52_FRAM_008
120
+ created: 2023-09-22 12:12:12
121
+ - datatype: observer
122
+ parameters:
123
+ id: 8
124
+ name: sheep08
125
+ ip: 192.168.165.208
126
+ mac: 18:62:E4:D0:E5:FB
127
+ room: II69
128
+ eth_port: TBD
129
+ description: north-east-corner
130
+ cape:
131
+ name: cape58
132
+ target_a:
133
+ name: nRF52_FRAM_016
134
+ created: 2023-09-22 12:12:12
135
+ active: false # TODO: cape is broken for now
136
+ - datatype: observer
137
+ parameters:
138
+ id: 9
139
+ name: sheep09
140
+ ip: 192.168.165.209
141
+ mac: 18:62:E4:D0:D4:A9
142
+ room: II71
143
+ eth_port: C4
144
+ description: south-east-corner
145
+ cape:
146
+ name: cape65
147
+ target_a:
148
+ name: nRF52_FRAM_009 # TODO: not validated
149
+ created: 2023-09-22 12:12:12
150
+ - datatype: observer
151
+ parameters:
152
+ id: 10
153
+ name: sheep10
154
+ ip: 192.168.165.210
155
+ mac: 18:62:E4:E4:24:C5
156
+ room: II74
157
+ eth_port: C20
158
+ description: upper mid on east-side
159
+ cape:
160
+ name: cape59
161
+ target_a:
162
+ name: nRF52_FRAM_010
163
+ created: 2023-09-22 12:12:12
164
+ - datatype: observer
165
+ parameters:
166
+ id: 11
167
+ name: sheep11
168
+ ip: 192.168.165.211
169
+ mac: 18:62:E4:E4:0E:5D
170
+ room: II69
171
+ eth_port: B14
172
+ description: lower mid on east-side
173
+ cape:
174
+ name: cape61
175
+ target_a:
176
+ name: nRF52_FRAM_007
177
+ created: 2023-09-22 12:12:12
178
+ - datatype: observer
179
+ parameters:
180
+ id: 12
181
+ name: sheep12
182
+ ip: 192.168.165.212
183
+ mac: 18:62:E4:D0:AA:F7
184
+ room: II71
185
+ eth_port: B24
186
+ description: north-east-corner
187
+ cape:
188
+ name: cape62
189
+ target_a:
190
+ name: nRF52_FRAM_014
191
+ created: 2023-09-22 12:12:12
192
+ - datatype: observer
193
+ parameters:
194
+ id: 13
195
+ name: sheep13
196
+ ip: 192.168.165.213
197
+ mac: 18:62:E4:D0:D7:70
198
+ room: II64C
199
+ eth_port: A4
200
+ description: north-west-corner
201
+ comment:
202
+ cape:
203
+ name: cape60
204
+ target_a:
205
+ name: nRF52_FRAM_005
206
+ created: 2023-09-22 12:12:12
207
+ - datatype: observer
208
+ parameters:
209
+ id: 14
210
+ name: sheep14
211
+ ip: 192.168.165.214
212
+ mac: 18:62:E4:E3:89:43
213
+ room: II64B
214
+ eth_port: L24
215
+ description: north-east-corner in cupboard, elevated
216
+ comment:
217
+ cape:
218
+ name: cape64
219
+ target_a:
220
+ name: nRF52_FRAM_006
221
+ created: 2023-09-22 12:12:12
@@ -1,3 +1,5 @@
1
+ """meta-data representation of a testbed-component (physical object)."""
2
+
1
3
  from datetime import datetime
2
4
  from typing import Optional
3
5
  from typing import Union
@@ -19,7 +21,7 @@ MCUPort = Annotated[int, Field(ge=1, le=2)]
19
21
 
20
22
 
21
23
  class Target(ShpModel, title="Target Node (DuT)"):
22
- """meta-data representation of a testbed-component (physical object)"""
24
+ """meta-data representation of a testbed-component (physical object)."""
23
25
 
24
26
  id: IdInt
25
27
  name: NameStr
@@ -36,7 +38,7 @@ class Target(ShpModel, title="Target Node (DuT)"):
36
38
  mcu1: Union[MCU, NameStr]
37
39
  mcu2: Union[MCU, NameStr, None] = None
38
40
 
39
- # TODO programming pins per mcu should be here (or better in Cape)
41
+ # TODO: programming pins per mcu should be here (or better in Cape)
40
42
 
41
43
  def __str__(self) -> str:
42
44
  return self.name
@@ -0,0 +1,137 @@
1
+ ---
2
+ # more human-readable test-protocol @
3
+ # https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Target_pre-deployment-tests.xlsx
4
+ - datatype: target
5
+ parameters:
6
+ id: 6 # Outer ID - selected by user - can be rearranged
7
+ name: nRF52_FRAM_001 # inner ID - used to link all parts together
8
+ version: v1.0
9
+ description: nRF52 as MCU + Radio, MSP430FR as SPI-FRAM or additional MCU
10
+ comment: Test3 21nA sleep, msp-programming was flaky before -> monitor!
11
+ created: 2023-04-12
12
+ mcu1:
13
+ name: nRF52
14
+ mcu2:
15
+ name: MSP430FR
16
+ - datatype: target
17
+ parameters:
18
+ inherit_from: nRF52_FRAM_001
19
+ id: 10
20
+ name: nRF52_FRAM_002
21
+ comment: Test3 21nA sleep
22
+ - datatype: target
23
+ parameters:
24
+ inherit_from: nRF52_FRAM_001
25
+ id: 7
26
+ name: nRF52_FRAM_003
27
+ comment: Test3 21nA sleep
28
+ - datatype: target
29
+ parameters:
30
+ inherit_from: nRF52_FRAM_001
31
+ id: 3
32
+ name: nRF52_FRAM_004
33
+ comment: Test3 21nA sleep
34
+ - datatype: target
35
+ parameters:
36
+ inherit_from: nRF52_FRAM_001
37
+ id: 11
38
+ name: nRF52_FRAM_005
39
+ comment: Test3 21nA sleep, changed Antenna to lambda/4
40
+ - datatype: target
41
+ parameters:
42
+ inherit_from: nRF52_FRAM_001
43
+ id: 12
44
+ name: nRF52_FRAM_006
45
+ comment: Test3 21nA sleep, changed Antenna to lambda/4
46
+ - datatype: target
47
+ parameters:
48
+ inherit_from: nRF52_FRAM_001
49
+ id: 8
50
+ name: nRF52_FRAM_007
51
+ comment: msp-programming is failing -> defective, msp removed & changed Antenna to lambda/4
52
+ mcu2: null
53
+ active: true
54
+ - datatype: target
55
+ parameters:
56
+ inherit_from: nRF52_FRAM_001
57
+ id: 9
58
+ name: nRF52_FRAM_008
59
+ comment: msp-programming is failing -> defective, msp removed & changed Antenna to lambda/4
60
+ mcu2: null
61
+ active: true
62
+ - datatype: target
63
+ parameters:
64
+ inherit_from: nRF52_FRAM_001
65
+ id: 5
66
+ name: nRF52_FRAM_009
67
+ comment: Test3 21nA sleep
68
+ - datatype: target
69
+ parameters:
70
+ inherit_from: nRF52_FRAM_001
71
+ id: 2
72
+ name: nRF52_FRAM_010
73
+ comment: Test3 21nA sleep
74
+ - datatype: target
75
+ parameters:
76
+ inherit_from: nRF52_FRAM_001
77
+ id: 1
78
+ name: nRF52_FRAM_011
79
+ comment: Test3 21nA sleep, changed Antenna to lambda/4
80
+ - datatype: target
81
+ parameters:
82
+ inherit_from: nRF52_FRAM_001
83
+ id: 1312
84
+ name: nRF52_FRAM_012
85
+ comment: msp-programming is failing -> defective, Antenna-Port destroyed
86
+ active: false
87
+ - datatype: target
88
+ parameters:
89
+ inherit_from: nRF52_FRAM_001
90
+ id: 1313
91
+ name: nRF52_FRAM_013
92
+ comment: Test3 15nA sleep, Test1 fails - several cleanings -> defective
93
+ active: false
94
+ - datatype: target
95
+ parameters:
96
+ inherit_from: nRF52_FRAM_001
97
+ id: 4
98
+ name: nRF52_FRAM_014
99
+ comment: Test3 21nA sleep
100
+ - datatype: target
101
+ parameters:
102
+ inherit_from: nRF52_FRAM_001
103
+ id: 1315
104
+ name: nRF52_FRAM_015
105
+ comment: Test3 19nA sleep, Test1 fails - several cleanings - gpio error on nrf-side -> defective
106
+ active: false
107
+ - datatype: target
108
+ parameters:
109
+ inherit_from: nRF52_FRAM_001
110
+ id: 666
111
+ name: nRF52_FRAM_016
112
+ comment: Test3 21nA sleep
113
+ - datatype: target
114
+ parameters:
115
+ inherit_from: nRF52_FRAM_001
116
+ id: 13
117
+ name: nRF52_FRAM_017
118
+ comment: Test3 21nA sleep, nrf was miss-aligned -> hot air rework
119
+ - datatype: target
120
+ parameters:
121
+ inherit_from: nRF52_FRAM_001
122
+ id: 18
123
+ name: nRF52_FRAM_018
124
+ comment: Test3 21nA sleep, nrf was miss-aligned -> hot air rework
125
+ description: LabPrototype
126
+
127
+ - datatype: target
128
+ parameters:
129
+ id: 1001
130
+ name: target_nRF52_01
131
+ version: v2.1r0
132
+ description: single target PCB, v2.1r0
133
+ comment: ONLY VIRTUAL - NOT REAL
134
+ mcu1:
135
+ name: nRF52
136
+ mcu2: null
137
+ created: 2022-12-12 12:12:12
@@ -1,3 +1,5 @@
1
+ """meta-data representation of a testbed-component (physical object)."""
2
+
1
3
  from datetime import timedelta
2
4
  from pathlib import Path
3
5
  from typing import List
@@ -18,7 +20,7 @@ from .observer import Observer
18
20
 
19
21
 
20
22
  class Testbed(ShpModel):
21
- """meta-data representation of a testbed-component (physical object)"""
23
+ """meta-data representation of a testbed-component (physical object)."""
22
24
 
23
25
  id: IdInt
24
26
  name: NameStr
@@ -87,4 +89,5 @@ class Testbed(ShpModel):
87
89
  continue
88
90
  if _observer.has_target(target_id):
89
91
  return _observer
90
- raise ValueError(f"Target-ID {target_id} was not found in Testbed '{self.name}'")
92
+ msg = f"Target-ID {target_id} was not found in Testbed '{self.name}'"
93
+ raise ValueError(msg)
@@ -0,0 +1,25 @@
1
+ - datatype: testbed
2
+ parameters:
3
+ id: 1337
4
+ name: shepherd_tud_nes
5
+ description: "Shepherd Testbed of the NES Lab Group at TU Dresden, Germany"
6
+ shared_storage: true
7
+ data_on_server: /var/shepherd/
8
+ data_on_observer: /var/shepherd/
9
+ # ./content as read-only for the sheep, shared with server
10
+ # ./experiments on the sheep map to ./experiments/sheep##/ on the server
11
+ observers:
12
+ - name: sheep01
13
+ - name: sheep02
14
+ - name: sheep03
15
+ - name: sheep04
16
+ - name: sheep05
17
+ - name: sheep06
18
+ - name: sheep07
19
+ - name: sheep08
20
+ - name: sheep09
21
+ - name: sheep10
22
+ - name: sheep11
23
+ - name: sheep12
24
+ - name: sheep13
25
+ - name: sheep14
@@ -1,3 +1,5 @@
1
+ """Module for making data in waveforms accessible by decoding protocols."""
2
+
1
3
  from .uart import Uart
2
4
 
3
5
  __all__ = ["Uart"]
@@ -1,4 +1,7 @@
1
- """UART - Decoder - Features:
1
+ """UART - Decoder.
2
+
3
+ Features:
4
+
2
5
  - 1 bit Start (LOW)
3
6
  - 1 .. **8** .. 64 bit data-frame
4
7
  - **1**, 1.5, 2 bit stop (HIGH) - don't care?
@@ -7,12 +10,12 @@
7
10
  - **no** inversion
8
11
 
9
12
  Todo:
10
- ----
11
- - detect bitOrder
12
- - detect dataframe length
13
- - detect parity
13
+ - detect bitOrder
14
+ - detect dataframe length
15
+ - detect parity
14
16
 
15
17
  More Info:
18
+
16
19
  https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter
17
20
  https://sigrok.org/wiki/Protocol_decoder:Uart
18
21
 
@@ -29,19 +32,23 @@ from ..logger import logger
29
32
 
30
33
 
31
34
  class Parity(str, Enum):
35
+ """Options for parity-property of UART data-frame."""
36
+
32
37
  no = "no"
33
38
  even = "odd"
34
39
  odd = "even"
35
40
 
36
41
 
37
42
  class BitOrder(str, Enum):
38
- msb = "msb"
39
- msb_first = "msb"
40
- lsb = "lsb"
41
- lsb_first = "lsb"
43
+ """Options for bit-order-property of UART data-frame."""
44
+
45
+ msb = msb_first = "msb"
46
+ lsb = lsb_first = "lsb"
42
47
 
43
48
 
44
49
  class Uart:
50
+ """Specialized UART decoder."""
51
+
45
52
  def __init__(
46
53
  self,
47
54
  content: Union[Path, np.ndarray],
@@ -51,10 +58,14 @@ class Uart:
51
58
  parity: Optional[Parity] = Parity.no,
52
59
  bit_order: Optional[BitOrder] = BitOrder.lsb_first,
53
60
  ) -> None:
54
- """Provide a file with two columns:
55
- - timestamp (seconds with fraction) and signal (can be analog).
56
- - class-parameters that are None (above) get auto-detected
57
- (some detectors still missing)
61
+ """Provide a file with two columns: TS & Signal.
62
+
63
+ Constraints:
64
+ - timestamp -> seconds with fraction
65
+ - signal -> can be analog or digital
66
+
67
+ Note: class-parameters that are None (above) get auto-detected
68
+ (some detectors still missing).
58
69
  """
59
70
  if isinstance(content, Path):
60
71
  self.events_sig: np.ndarray = np.loadtxt(content.as_posix(), delimiter=",", skiprows=1)
@@ -109,7 +120,7 @@ class Uart:
109
120
  self.text: Optional[str] = None
110
121
 
111
122
  def _convert_analog2digital(self, *, invert: bool = False) -> None:
112
- """Divide dimension in two, divided by mean-value"""
123
+ """Divide dimension in two, divided by mean-value."""
113
124
  data = self.events_sig[:, 1]
114
125
  mean = np.mean(data)
115
126
  if invert:
@@ -118,7 +129,7 @@ class Uart:
118
129
  self.events_sig[:, 1] = data >= mean
119
130
 
120
131
  def _filter_redundant_states(self) -> None:
121
- """Sum of two sequential states is always 1 (True + False) if alternating"""
132
+ """Sum of two sequential states is always 1 (True + False) if alternating."""
122
133
  data_0 = self.events_sig[:, 1]
123
134
  data_1 = np.concatenate([[not data_0[0]], data_0[:-1]])
124
135
  data_f = data_0 + data_1
@@ -132,7 +143,7 @@ class Uart:
132
143
  )
133
144
 
134
145
  def _add_duration(self) -> None:
135
- """Calculate third column -> duration of state in [baud-ticks]"""
146
+ """Calculate third column -> duration of state in [baud-ticks]."""
136
147
  if self.events_sig.shape[1] > 2:
137
148
  logger.warning("Tried to add state-duration, but it seems already present")
138
149
  return
@@ -143,7 +154,8 @@ class Uart:
143
154
  self.events_sig = np.append(self.events_sig[:-1, :], dur_steps / self.dur_tick, axis=1)
144
155
 
145
156
  def detect_inversion(self) -> bool:
146
- """Analyze bit-state during long pauses (unchanged states)
157
+ """Analyze bit-state during long pauses (unchanged states).
158
+
147
159
  - pause should be HIGH for non-inverted mode (default)
148
160
  - assumes max frame size of 64 bit + x for safety
149
161
  """
@@ -157,7 +169,7 @@ class Uart:
157
169
  return mean_state < 0.5
158
170
 
159
171
  def detect_baud_rate(self) -> int:
160
- """Analyze the smallest step"""
172
+ """Analyze the smallest step."""
161
173
  events = self.events_sig[:1000, :] # speedup for large datasets
162
174
  dur_steps = events[1:, 0] - events[:-1, 0]
163
175
  def_step = np.percentile(dur_steps[dur_steps > 0], 10)
@@ -167,23 +179,29 @@ class Uart:
167
179
  return round(1 / mean_tick)
168
180
 
169
181
  def detect_half_stop(self) -> bool:
170
- """Looks into the spacing between time-steps"""
182
+ """Look into the spacing between time-steps to determine use of half stop."""
171
183
  events = self.events_sig[:1000, :] # speedup for large datasets
172
184
  return np.sum((events > 1.333 * self.dur_tick) & (events < 1.667 * self.dur_tick)) > 0
173
185
 
174
186
  def detect_dataframe_length(self) -> int:
175
- """Look after longest pauses
176
- - accumulate steps until a state with uneven step-size is found
187
+ """Try to determine length of dataframe.
188
+
189
+ Algo will look for longest pauses & accumulate steps until
190
+ a state with uneven step-size is found.
177
191
  """
192
+ raise NotImplementedError
178
193
 
179
194
  def get_symbols(self, *, force_redo: bool = False) -> np.ndarray:
180
- """Ways to detect EOF:
195
+ """Extract symbols from events.
196
+
197
+ Ways to detect EOF:
181
198
  - long pause on HIGH
182
199
  - off_tick pause on high
183
200
  - bit_pos > max
201
+
184
202
  # TODO:
185
203
  - slowest FN -> speedup with numba or parallelization?
186
- - dset could be divided (long pauses) and threaded for speedup
204
+ - dset could be divided (long pauses) and threaded for speedup.
187
205
  """
188
206
  if force_redo:
189
207
  self.events_symbols = None
@@ -235,7 +253,7 @@ class Uart:
235
253
  return self.events_symbols
236
254
 
237
255
  def get_lines(self, *, force_redo: bool = False) -> np.ndarray:
238
- """Timestamped symbols to line, cut at \r, \r\n or \n"""
256
+ r"""Timestamped symbols to line, cut at \r, \r\n or \n."""
239
257
  if force_redo:
240
258
  self.events_lines = None
241
259
  if self.events_lines is not None:
@@ -267,7 +285,7 @@ class Uart:
267
285
  return self.events_lines
268
286
 
269
287
  def get_text(self, *, force_redo: bool = False) -> str:
270
- """Remove timestamps and just return the whole string"""
288
+ """Remove timestamps and just return the whole string."""
271
289
  if force_redo:
272
290
  self.text = None
273
291
  if self.text is not None:
@@ -1,3 +1,5 @@
1
+ """Helper-functions for handling firmware around the testbed."""
2
+
1
3
  from typing import Any
2
4
 
3
5
  try: