slm_open_api_package 0.2.10__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.
- slm_api/CPB_example.py +74 -0
- slm_api/__init__.py +5 -0
- slm_api/enums/fast_log_intervals_enum.py +16 -0
- slm_api/enums/sequence_id_enum.py +352 -0
- slm_api/example_multi.py +78 -0
- slm_api/fast_log_example.py +172 -0
- slm_api/flac_example.py +164 -0
- slm_api/helpers/FigureHandler.py +65 -0
- slm_api/helpers/Leq.py +87 -0
- slm_api/helpers/__init__.py +5 -0
- slm_api/helpers/buffer.py +27 -0
- slm_api/helpers/data_handler.py +94 -0
- slm_api/helpers/fft.py +38 -0
- slm_api/helpers/flac_stream_2_samples.py +64 -0
- slm_api/helpers/https_requests.py +79 -0
- slm_api/helpers/measurment_handler.py +20 -0
- slm_api/helpers/sequence_handler.py +43 -0
- slm_api/helpers/stream_handler.py +105 -0
- slm_api/helpers/stream_handlers.py +434 -0
- slm_api/helpers/tmpFileStateMachine.py +93 -0
- slm_api/helpers/websocket_handler.py +12 -0
- slm_api/helpers/webxi_helper_functions.py +79 -0
- slm_api/helpers/webxi_root.pem +24 -0
- slm_api/mp3_example.py +165 -0
- slm_api/multi_device_flac.py +105 -0
- slm_api/multi_instrument_example.py +74 -0
- slm_api/screen_record_example.py +64 -0
- slm_api/webxi/README.md +25 -0
- slm_api/webxi/__init__.py +5 -0
- slm_api/webxi/webxi-header.ksy +32 -0
- slm_api/webxi/webxi-stream.ksy +342 -0
- slm_api/webxi/webxi_header.py +42 -0
- slm_api/webxi/webxi_stream.py +450 -0
- slm_open_api_package-0.2.10.dist-info/METADATA +206 -0
- slm_open_api_package-0.2.10.dist-info/RECORD +37 -0
- slm_open_api_package-0.2.10.dist-info/WHEEL +4 -0
- slm_open_api_package-0.2.10.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
|
|
2
|
+
|
|
3
|
+
from packaging.version import Version as parse_version
|
|
4
|
+
import kaitaistruct
|
|
5
|
+
from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO
|
|
6
|
+
from enum import Enum
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if parse_version(kaitaistruct.__version__) < parse_version('0.9'):
|
|
10
|
+
raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__))
|
|
11
|
+
|
|
12
|
+
class WebxiStream(KaitaiStruct):
|
|
13
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
14
|
+
self._io = _io
|
|
15
|
+
self._parent = _parent
|
|
16
|
+
self._root = _root if _root else self
|
|
17
|
+
self._read()
|
|
18
|
+
|
|
19
|
+
def _read(self):
|
|
20
|
+
self.header = self._root.Header(self._io, self, self._root)
|
|
21
|
+
_on = self.header.message_type
|
|
22
|
+
if _on == self._root.Header.EMessageType.e_state:
|
|
23
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
24
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
25
|
+
self.content = self._root.State(_io__raw_content, self, self._root)
|
|
26
|
+
elif _on == self._root.Header.EMessageType.e_sequence_data:
|
|
27
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
28
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
29
|
+
self.content = self._root.SequenceData(_io__raw_content, self, self._root)
|
|
30
|
+
elif _on == self._root.Header.EMessageType.e_debug:
|
|
31
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
32
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
33
|
+
self.content = self._root.Debug(_io__raw_content, self, self._root)
|
|
34
|
+
elif _on == self._root.Header.EMessageType.e_sync:
|
|
35
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
36
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
37
|
+
self.content = self._root.Sync(_io__raw_content, self, self._root)
|
|
38
|
+
elif _on == self._root.Header.EMessageType.e_aux_sequence_data:
|
|
39
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
40
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
41
|
+
self.content = self._root.AuxSequenceData(_io__raw_content, self, self._root)
|
|
42
|
+
elif _on == self._root.Header.EMessageType.e_package:
|
|
43
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
44
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
45
|
+
self.content = self._root.Package(_io__raw_content, self, self._root)
|
|
46
|
+
elif _on == self._root.Header.EMessageType.e_data_quality:
|
|
47
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
48
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
49
|
+
self.content = self._root.DataQuality(_io__raw_content, self, self._root)
|
|
50
|
+
elif _on == self._root.Header.EMessageType.e_node:
|
|
51
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
52
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
53
|
+
self.content = self._root.Node(_io__raw_content, self, self._root)
|
|
54
|
+
elif _on == self._root.Header.EMessageType.e_status:
|
|
55
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
56
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
57
|
+
self.content = self._root.Status(_io__raw_content, self, self._root)
|
|
58
|
+
elif _on == self._root.Header.EMessageType.e_trigger:
|
|
59
|
+
self._raw_content = self._io.read_bytes(self.header.content_length)
|
|
60
|
+
_io__raw_content = KaitaiStream(BytesIO(self._raw_content))
|
|
61
|
+
self.content = self._root.Trigger(_io__raw_content, self, self._root)
|
|
62
|
+
else:
|
|
63
|
+
self.content = self._io.read_bytes(self.header.content_length)
|
|
64
|
+
|
|
65
|
+
class NodeChange(KaitaiStruct):
|
|
66
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
67
|
+
self._io = _io
|
|
68
|
+
self._parent = _parent
|
|
69
|
+
self._root = _root if _root else self
|
|
70
|
+
self._read()
|
|
71
|
+
|
|
72
|
+
def _read(self):
|
|
73
|
+
self.flags = self._io.read_u2le()
|
|
74
|
+
self.reserved = self._io.read_u2le()
|
|
75
|
+
self.path = self._root.String(self._io, self, self._root)
|
|
76
|
+
self.json = self._root.String(self._io, self, self._root)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Package(KaitaiStruct):
|
|
80
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
81
|
+
self._io = _io
|
|
82
|
+
self._parent = _parent
|
|
83
|
+
self._root = _root if _root else self
|
|
84
|
+
self._read()
|
|
85
|
+
|
|
86
|
+
def _read(self):
|
|
87
|
+
self.number_of_packages = self._io.read_u2le()
|
|
88
|
+
self.reserved = self._io.read_u2le()
|
|
89
|
+
self.packages = [None] * (self.number_of_packages)
|
|
90
|
+
for i in range(self.number_of_packages):
|
|
91
|
+
self.packages[i] = self._root.PackageBlock(self._io, self, self._root)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class AuxValue(KaitaiStruct):
|
|
96
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
97
|
+
self._io = _io
|
|
98
|
+
self._parent = _parent
|
|
99
|
+
self._root = _root if _root else self
|
|
100
|
+
self._read()
|
|
101
|
+
|
|
102
|
+
def _read(self):
|
|
103
|
+
self.relative_time = self._io.read_u4le()
|
|
104
|
+
self.values = self._root.Value(self._io, self, self._root)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class FlacSequenceDataBlock(KaitaiStruct):
|
|
108
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
109
|
+
self._io = _io
|
|
110
|
+
self._parent = _parent
|
|
111
|
+
self._root = _root if _root else self
|
|
112
|
+
self._read()
|
|
113
|
+
|
|
114
|
+
def _read(self):
|
|
115
|
+
self.number_of_sequences = self._io.read_u2le()
|
|
116
|
+
self.sequence_ids = [None] * (self.number_of_sequences)
|
|
117
|
+
for i in range(self.number_of_sequences):
|
|
118
|
+
self.sequence_ids[i] = self._io.read_u2le()
|
|
119
|
+
|
|
120
|
+
self.frame_length = self._io.read_u4le()
|
|
121
|
+
self.frame = [None] * (self.frame_length)
|
|
122
|
+
for i in range(self.frame_length):
|
|
123
|
+
self.frame[i] = self._io.read_u1()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class AuxSequenceDataBlock(KaitaiStruct):
|
|
128
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
129
|
+
self._io = _io
|
|
130
|
+
self._parent = _parent
|
|
131
|
+
self._root = _root if _root else self
|
|
132
|
+
self._read()
|
|
133
|
+
|
|
134
|
+
def _read(self):
|
|
135
|
+
self.sequence_id = self._io.read_u2le()
|
|
136
|
+
self.number_of_values = self._io.read_u2le()
|
|
137
|
+
self.values = [None] * (self.number_of_values)
|
|
138
|
+
for i in range(self.number_of_values):
|
|
139
|
+
self.values[i] = self._root.AuxValue(self._io, self, self._root)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class State(KaitaiStruct):
|
|
144
|
+
|
|
145
|
+
class EState(Enum):
|
|
146
|
+
initial = 0
|
|
147
|
+
error = 1
|
|
148
|
+
deactivated = 2
|
|
149
|
+
activated = 3
|
|
150
|
+
running = 4
|
|
151
|
+
ramping_down = 5
|
|
152
|
+
pause = 6
|
|
153
|
+
stopping = 7
|
|
154
|
+
result_measured = 8
|
|
155
|
+
result_loaded = 9
|
|
156
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
157
|
+
self._io = _io
|
|
158
|
+
self._parent = _parent
|
|
159
|
+
self._root = _root if _root else self
|
|
160
|
+
self._read()
|
|
161
|
+
|
|
162
|
+
def _read(self):
|
|
163
|
+
self.state = KaitaiStream.resolve_enum(self._root.State.EState, self._io.read_u2le())
|
|
164
|
+
self.reserved = self._io.read_u2le()
|
|
165
|
+
self.application_name = self._root.String(self._io, self, self._root)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class DataQuality(KaitaiStruct):
|
|
169
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
170
|
+
self._io = _io
|
|
171
|
+
self._parent = _parent
|
|
172
|
+
self._root = _root if _root else self
|
|
173
|
+
self._read()
|
|
174
|
+
|
|
175
|
+
def _read(self):
|
|
176
|
+
self.number_of_qualities = self._io.read_u2le()
|
|
177
|
+
self.reserved = self._io.read_u2le()
|
|
178
|
+
self.qualities = [None] * (self.number_of_qualities)
|
|
179
|
+
for i in range(self.number_of_qualities):
|
|
180
|
+
self.qualities[i] = self._root.QualityBlock(self._io, self, self._root)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class AuxSequenceData(KaitaiStruct):
|
|
185
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
186
|
+
self._io = _io
|
|
187
|
+
self._parent = _parent
|
|
188
|
+
self._root = _root if _root else self
|
|
189
|
+
self._read()
|
|
190
|
+
|
|
191
|
+
def _read(self):
|
|
192
|
+
self.number_of_sequences = self._io.read_u2le()
|
|
193
|
+
self.reserved = self._io.read_u2le()
|
|
194
|
+
self.aux_sequence_data_blocks = [None] * (self.number_of_sequences)
|
|
195
|
+
for i in range(self.number_of_sequences):
|
|
196
|
+
self.aux_sequence_data_blocks[i] = self._root.AuxSequenceDataBlock(self._io, self, self._root)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class SequenceData(KaitaiStruct):
|
|
201
|
+
|
|
202
|
+
class EMessageFormat(Enum):
|
|
203
|
+
raw = 0
|
|
204
|
+
mp3 = 1
|
|
205
|
+
flac = 2
|
|
206
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
207
|
+
self._io = _io
|
|
208
|
+
self._parent = _parent
|
|
209
|
+
self._root = _root if _root else self
|
|
210
|
+
self._read()
|
|
211
|
+
|
|
212
|
+
def _read(self):
|
|
213
|
+
self.number_of_blocks = self._io.read_u2le()
|
|
214
|
+
self.message_format = KaitaiStream.resolve_enum(self._root.SequenceData.EMessageFormat, self._io.read_u1())
|
|
215
|
+
self.reserved = self._io.read_u1()
|
|
216
|
+
self.sequence_blocks = [None] * (self.number_of_blocks)
|
|
217
|
+
for i in range(self.number_of_blocks):
|
|
218
|
+
_on = self.message_format
|
|
219
|
+
if _on == self._root.SequenceData.EMessageFormat.raw:
|
|
220
|
+
self.sequence_blocks[i] = self._root.RawSequenceDataBlock(self._io, self, self._root)
|
|
221
|
+
elif _on == self._root.SequenceData.EMessageFormat.mp3:
|
|
222
|
+
self.sequence_blocks[i] = self._root.Mp3SequenceDataBlock(self._io, self, self._root)
|
|
223
|
+
elif _on == self._root.SequenceData.EMessageFormat.flac:
|
|
224
|
+
self.sequence_blocks[i] = self._root.FlacSequenceDataBlock(self._io, self, self._root)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class String(KaitaiStruct):
|
|
229
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
230
|
+
self._io = _io
|
|
231
|
+
self._parent = _parent
|
|
232
|
+
self._root = _root if _root else self
|
|
233
|
+
self._read()
|
|
234
|
+
|
|
235
|
+
def _read(self):
|
|
236
|
+
self.count = self._io.read_u4le()
|
|
237
|
+
self.content = (self._io.read_bytes(self.count)).decode(u"UTF-8")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class PackageBlock(KaitaiStruct):
|
|
241
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
242
|
+
self._io = _io
|
|
243
|
+
self._parent = _parent
|
|
244
|
+
self._root = _root if _root else self
|
|
245
|
+
self._read()
|
|
246
|
+
|
|
247
|
+
def _read(self):
|
|
248
|
+
self.package_id = self._io.read_u2le()
|
|
249
|
+
self.data_length = self._io.read_u2le()
|
|
250
|
+
self.data = [None] * (self.data_length)
|
|
251
|
+
for i in range(self.data_length):
|
|
252
|
+
self.data[i] = self._io.read_u1()
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class Debug(KaitaiStruct):
|
|
257
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
258
|
+
self._io = _io
|
|
259
|
+
self._parent = _parent
|
|
260
|
+
self._root = _root if _root else self
|
|
261
|
+
self._read()
|
|
262
|
+
|
|
263
|
+
def _read(self):
|
|
264
|
+
self.message = self._root.String(self._io, self, self._root)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class TimeFamily(KaitaiStruct):
|
|
268
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
269
|
+
self._io = _io
|
|
270
|
+
self._parent = _parent
|
|
271
|
+
self._root = _root if _root else self
|
|
272
|
+
self._read()
|
|
273
|
+
|
|
274
|
+
def _read(self):
|
|
275
|
+
self.k = self._io.read_u1()
|
|
276
|
+
self.l = self._io.read_u1()
|
|
277
|
+
self.m = self._io.read_u1()
|
|
278
|
+
self.n = self._io.read_u1()
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class Status(KaitaiStruct):
|
|
282
|
+
|
|
283
|
+
class EChannelType(Enum):
|
|
284
|
+
todo = 0
|
|
285
|
+
|
|
286
|
+
class EStatusType(Enum):
|
|
287
|
+
todo1 = 0
|
|
288
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
289
|
+
self._io = _io
|
|
290
|
+
self._parent = _parent
|
|
291
|
+
self._root = _root if _root else self
|
|
292
|
+
self._read()
|
|
293
|
+
|
|
294
|
+
def _read(self):
|
|
295
|
+
self.channel_type = KaitaiStream.resolve_enum(self._root.Status.EChannelType, self._io.read_u2le())
|
|
296
|
+
self.channel_id = self._io.read_u2le()
|
|
297
|
+
self.status_type = KaitaiStream.resolve_enum(self._root.Status.EStatusType, self._io.read_u2le())
|
|
298
|
+
self.reserved = self._io.read_u2le()
|
|
299
|
+
self.value1 = self._io.read_s4le()
|
|
300
|
+
self.value2 = self._io.read_s4le()
|
|
301
|
+
self.str = self._root.String(self._io, self, self._root)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class QualityBlock(KaitaiStruct):
|
|
305
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
306
|
+
self._io = _io
|
|
307
|
+
self._parent = _parent
|
|
308
|
+
self._root = _root if _root else self
|
|
309
|
+
self._read()
|
|
310
|
+
|
|
311
|
+
def _read(self):
|
|
312
|
+
self.quality_id = self._io.read_u2le()
|
|
313
|
+
self.validity = self._io.read_u2le()
|
|
314
|
+
self.reserved = self._io.read_u4le()
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class Sync(KaitaiStruct):
|
|
318
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
319
|
+
self._io = _io
|
|
320
|
+
self._parent = _parent
|
|
321
|
+
self._root = _root if _root else self
|
|
322
|
+
self._read()
|
|
323
|
+
|
|
324
|
+
def _read(self):
|
|
325
|
+
self.sync_id = self._io.read_u4le()
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class Header(KaitaiStruct):
|
|
329
|
+
|
|
330
|
+
class EMessageType(Enum):
|
|
331
|
+
e_sequence_data = 1
|
|
332
|
+
e_data_quality = 2
|
|
333
|
+
e_state = 3
|
|
334
|
+
e_status = 4
|
|
335
|
+
e_trigger = 5
|
|
336
|
+
e_node = 6
|
|
337
|
+
e_sync = 7
|
|
338
|
+
e_debug = 9
|
|
339
|
+
e_package = 10
|
|
340
|
+
e_aux_sequence_data = 11
|
|
341
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
342
|
+
self._io = _io
|
|
343
|
+
self._parent = _parent
|
|
344
|
+
self._root = _root if _root else self
|
|
345
|
+
self._read()
|
|
346
|
+
|
|
347
|
+
def _read(self):
|
|
348
|
+
self.magic = self._io.read_bytes(2)
|
|
349
|
+
if not self.magic == b"\x42\x4B":
|
|
350
|
+
raise kaitaistruct.ValidationNotEqualError(b"\x42\x4B", self.magic, self._io, u"/types/header/seq/0")
|
|
351
|
+
self.header_length = self._io.read_u2le()
|
|
352
|
+
self.message_type = KaitaiStream.resolve_enum(self._root.Header.EMessageType, self._io.read_u2le())
|
|
353
|
+
self.content_version = self._io.read_u2le()
|
|
354
|
+
self.reserved2 = self._io.read_u4le()
|
|
355
|
+
self.time = self._io.read_u8le()
|
|
356
|
+
self.content_length = self._io.read_u4le()
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
class Node(KaitaiStruct):
|
|
360
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
361
|
+
self._io = _io
|
|
362
|
+
self._parent = _parent
|
|
363
|
+
self._root = _root if _root else self
|
|
364
|
+
self._read()
|
|
365
|
+
|
|
366
|
+
def _read(self):
|
|
367
|
+
self.n_changes = self._io.read_u2le()
|
|
368
|
+
self.reserved = self._io.read_u2le()
|
|
369
|
+
self.changes = [None] * (self.n_changes)
|
|
370
|
+
for i in range(self.n_changes):
|
|
371
|
+
self.changes[i] = self._root.NodeChange(self._io, self, self._root)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class Value(KaitaiStruct):
|
|
376
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
377
|
+
self._io = _io
|
|
378
|
+
self._parent = _parent
|
|
379
|
+
self._root = _root if _root else self
|
|
380
|
+
self._read()
|
|
381
|
+
|
|
382
|
+
def _read(self):
|
|
383
|
+
self.value1 = self._io.read_u1()
|
|
384
|
+
self.value2 = self._io.read_u1()
|
|
385
|
+
self.value3 = self._io.read_s1()
|
|
386
|
+
self.value4 = self._io.read_s1()
|
|
387
|
+
|
|
388
|
+
@property
|
|
389
|
+
def calc_value(self):
|
|
390
|
+
if hasattr(self, '_m_calc_value'):
|
|
391
|
+
return self._m_calc_value if hasattr(self, '_m_calc_value') else None
|
|
392
|
+
|
|
393
|
+
self._m_calc_value = ((self.value1 + (self.value2 << 8)) + (self.value3 << 16))
|
|
394
|
+
return self._m_calc_value if hasattr(self, '_m_calc_value') else None
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class Mp3SequenceDataBlock(KaitaiStruct):
|
|
398
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
399
|
+
self._io = _io
|
|
400
|
+
self._parent = _parent
|
|
401
|
+
self._root = _root if _root else self
|
|
402
|
+
self._read()
|
|
403
|
+
|
|
404
|
+
def _read(self):
|
|
405
|
+
self.number_of_sequences = self._io.read_u2le()
|
|
406
|
+
self.sequence_ids = [None] * (self.number_of_sequences)
|
|
407
|
+
for i in range(self.number_of_sequences):
|
|
408
|
+
self.sequence_ids[i] = self._io.read_u2le()
|
|
409
|
+
|
|
410
|
+
self.frame_length = self._io.read_u4le()
|
|
411
|
+
self.frame = [None] * (self.frame_length)
|
|
412
|
+
for i in range(self.frame_length):
|
|
413
|
+
self.frame[i] = self._io.read_u1()
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class RawSequenceDataBlock(KaitaiStruct):
|
|
418
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
419
|
+
self._io = _io
|
|
420
|
+
self._parent = _parent
|
|
421
|
+
self._root = _root if _root else self
|
|
422
|
+
self._read()
|
|
423
|
+
|
|
424
|
+
def _read(self):
|
|
425
|
+
self.sequence_id = self._io.read_u2le()
|
|
426
|
+
self.value_length = self._io.read_u4le()
|
|
427
|
+
self.values = [None] * (self.value_length)
|
|
428
|
+
for i in range(self.value_length):
|
|
429
|
+
self.values[i] = self._io.read_u1()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class Trigger(KaitaiStruct):
|
|
434
|
+
|
|
435
|
+
class ETriggerType(Enum):
|
|
436
|
+
unkown = 0
|
|
437
|
+
level = 1
|
|
438
|
+
start = 2
|
|
439
|
+
def __init__(self, _io, _parent=None, _root=None):
|
|
440
|
+
self._io = _io
|
|
441
|
+
self._parent = _parent
|
|
442
|
+
self._root = _root if _root else self
|
|
443
|
+
self._read()
|
|
444
|
+
|
|
445
|
+
def _read(self):
|
|
446
|
+
self.sequence_id = self._io.read_u2le()
|
|
447
|
+
self.trigger_type = KaitaiStream.resolve_enum(self._root.Trigger.ETriggerType, self._io.read_u2le())
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: slm_open_api_package
|
|
3
|
+
Version: 0.2.10
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Sofus Vingaard
|
|
6
|
+
Author-email: Sofus Vingaard <sofus.krebsvingaard@hbkworld.com>
|
|
7
|
+
Requires-Dist: requests
|
|
8
|
+
Requires-Dist: numpy
|
|
9
|
+
Requires-Dist: websockets
|
|
10
|
+
Requires-Dist: kaitaistruct
|
|
11
|
+
Requires-Dist: packaging
|
|
12
|
+
Requires-Dist: pyqtgraph
|
|
13
|
+
Requires-Dist: pyqt5
|
|
14
|
+
Requires-Dist: pyqt5-qt5<5.15.11
|
|
15
|
+
Requires-Dist: miniaudio
|
|
16
|
+
Requires-Dist: matplotlib>=3.11.1
|
|
17
|
+
Requires-Dist: cryptography>=50.0.1
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# SLM Open API Package
|
|
22
|
+
|
|
23
|
+
Python helpers for streaming measurements and audio from an HBK sound level meter (SLM) through WebXi.
|
|
24
|
+
|
|
25
|
+
This PyPI package is made for the [Open Interface for Sound Level Meter](https://github.com/hbkworld/Open-Interface-for-Sound-Level-Meter) repository. Refer to that repository for more detailed usage information and additional examples.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
pip install slm_open_api_package
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or add it to an `uv` project:
|
|
36
|
+
|
|
37
|
+
```powershell
|
|
38
|
+
uv add slm_open_api_package
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The package requires Python 3.12 or newer and a network connection to a compatible SLM.
|
|
42
|
+
|
|
43
|
+
## Connect To A Device
|
|
44
|
+
|
|
45
|
+
Give every stream one `host`, either an IP address or host name:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
host = "192.168.1.183"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The bundled examples use `set_host()` to read a host from a local `slm_ip` file. If the file is missing, it prompts once and creates it:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from slm_api.helpers import webxi_helper_functions as webxi_helper
|
|
55
|
+
|
|
56
|
+
host = webxi_helper.set_host(__file__)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Basic Leq Stream
|
|
60
|
+
|
|
61
|
+
`WebXiStreamHandler` is the main API. `mode="leq"` is the default and streams one sequence selected by `sequenceID`.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
65
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler
|
|
66
|
+
|
|
67
|
+
streamer = WebXiStreamHandler(
|
|
68
|
+
host="192.168.1.183",
|
|
69
|
+
sequenceID=SequenceIdEnums.LAeq.value,
|
|
70
|
+
mode="leq",
|
|
71
|
+
saving="csv",
|
|
72
|
+
saving_path="saved_data/laeq",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
streamer.startStream()
|
|
77
|
+
except KeyboardInterrupt:
|
|
78
|
+
streamer.stopStream()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`stopStream()` stops the measurement, removes the device stream, and writes buffered saved data. Supported saving formats are `"csv"`, `"json"`, and `"pickle"`; their extensions are added automatically.
|
|
82
|
+
|
|
83
|
+
## Multiple Sequences
|
|
84
|
+
|
|
85
|
+
Based on [example_multi.py](src/slm_api/example_multi.py), use `mode="multi"` for several enabled broadband sequences in a single stream:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from slm_api.helpers.data_handler import DataHandler
|
|
89
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class PrintHandler(DataHandler):
|
|
93
|
+
def handle(self, *, host, name, value, **data):
|
|
94
|
+
print(f"{host} {name}: {value}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
streamer = WebXiStreamHandler(
|
|
98
|
+
host="192.168.1.183",
|
|
99
|
+
sequenceNames=["LAeq", "LCeq", "LAF"],
|
|
100
|
+
mode="multi",
|
|
101
|
+
saving="json",
|
|
102
|
+
saving_path="saved_data/broadband",
|
|
103
|
+
)
|
|
104
|
+
streamer.setDataHandler(PrintHandler())
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
streamer.startStream()
|
|
108
|
+
except KeyboardInterrupt:
|
|
109
|
+
streamer.stopStream()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Enable the requested sequences and frequency weightings on the SLM before starting the stream. Each `DataHandler.handle()` call receives the source `host`, `name`, and `value`. The `saving=` handler continues saving when a custom handler is attached.
|
|
113
|
+
|
|
114
|
+
## Fast Logging
|
|
115
|
+
|
|
116
|
+
Based on [fast_log_example.py](src/slm_api/fast_log_example.py), use `mode="fast_logging"` for fast broadband samples:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from slm_api.enums.fast_log_intervals_enum import FastLogInterval
|
|
120
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
121
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler
|
|
122
|
+
|
|
123
|
+
streamer = WebXiStreamHandler(
|
|
124
|
+
host="192.168.1.183",
|
|
125
|
+
sequenceID=SequenceIdEnums.FastLAF.value,
|
|
126
|
+
mode="fast_logging",
|
|
127
|
+
fast_logging_interval=FastLogInterval.interval_1000ms.value,
|
|
128
|
+
saving="csv",
|
|
129
|
+
saving_path="saved_data/fast_laf",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
streamer.startStream()
|
|
134
|
+
except KeyboardInterrupt:
|
|
135
|
+
streamer.stopStream()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Audio
|
|
139
|
+
|
|
140
|
+
Use the MP3 or FLAC examples for decoded audio samples:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
144
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler
|
|
145
|
+
|
|
146
|
+
streamer = WebXiStreamHandler(
|
|
147
|
+
host="192.168.1.183",
|
|
148
|
+
sequenceID=SequenceIdEnums.MP3Signal.value,
|
|
149
|
+
mode="mp3",
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The matching `flac` form uses `SequenceIdEnums.FLACSignal.value` and `mode="flac"`. Audio setup is enabled by the handler. The SLM can take a few seconds to initialize audio recording when its quality setting changes.
|
|
154
|
+
|
|
155
|
+
## Synchronized Multi-Device Stream
|
|
156
|
+
|
|
157
|
+
Based on [multi_device_flac.py](src/slm_api/multi_device_flac.py), pass `multi_device=True` and start/stop the group through the synchronized helpers:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
161
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler, start_all_synced, stop_all
|
|
162
|
+
|
|
163
|
+
hosts = ["192.168.1.183", "192.168.1.216"]
|
|
164
|
+
streams = [
|
|
165
|
+
WebXiStreamHandler(
|
|
166
|
+
host=host,
|
|
167
|
+
sequenceID=SequenceIdEnums.MP3Signal.value,
|
|
168
|
+
mode="mp3",
|
|
169
|
+
streamName=f"Audio_{host}",
|
|
170
|
+
multi_device=True,
|
|
171
|
+
saving="csv",
|
|
172
|
+
saving_path=f"saved_data/{host}",
|
|
173
|
+
)
|
|
174
|
+
for host in hosts
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
start_all_synced(streams)
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
while True:
|
|
181
|
+
time.sleep(1)
|
|
182
|
+
except KeyboardInterrupt:
|
|
183
|
+
stop_all(streams)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`stop_all()` synchronizes the device measurement stops, flushes saving handlers, and removes each device stream.
|
|
187
|
+
|
|
188
|
+
## Modes
|
|
189
|
+
|
|
190
|
+
| Mode | Use |
|
|
191
|
+
| --- | --- |
|
|
192
|
+
| `"leq"` | One broadband sequence; this is the default. |
|
|
193
|
+
| `"multi"` | Several named broadband sequences. |
|
|
194
|
+
| `"cpb"` | Constant-percentage-band data. |
|
|
195
|
+
| `"fast_logging"` | Fast broadband samples. |
|
|
196
|
+
| `"flac"` / `"mp3"` | Decoded audio samples. |
|
|
197
|
+
| `"screen_record"` | Latest SLM screen image in `streamer.image_bytes`. |
|
|
198
|
+
|
|
199
|
+
Legacy flags such as `mp3=True` remain supported, but `mode=` is preferred. Only select one mode per stream.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Troubleshooting
|
|
203
|
+
|
|
204
|
+
- **No values arrive:** Confirm the requested sequences are enabled on the SLM.
|
|
205
|
+
- **Audio returns no samples after first enable:** Allow the SLM a few seconds to initialize audio recording before retrying.
|
|
206
|
+
- **Saved file is missing:** Call `stopStream()` or `stop_all()`; buffered files are written during shutdown.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
slm_api/CPB_example.py,sha256=dFioae4gS2NWm5Wod87dCglbmO26n7WBvh0mklK_H8Q,2652
|
|
2
|
+
slm_api/__init__.py,sha256=Gl2zixNPabXv08KWFtImHPCBA3YhqkqHfk3V4QF2E84,136
|
|
3
|
+
slm_api/enums/fast_log_intervals_enum.py,sha256=o8JVtxBOiNYhGe9wRtrtpiQZMEm2jjfFQu9ehZWTSn8,398
|
|
4
|
+
slm_api/enums/sequence_id_enum.py,sha256=zFFiS0RzDQPSF4d6mg0iYfaRyyDmKe9YHnKGo7l03_k,6305
|
|
5
|
+
slm_api/example_multi.py,sha256=Tlf7opQBF1wvmaYR3WhKRA_IPkWhSiY3PtP_khTyJZw,2962
|
|
6
|
+
slm_api/fast_log_example.py,sha256=p2mwo8S6NLUazBEA2NDhIUS5Yd0d9CYm_jmyGIDe0pQ,6544
|
|
7
|
+
slm_api/flac_example.py,sha256=eJwxVNzS1D8xAVWibW9-Szu9D9KCVfNYBj6-d4TfCX0,6900
|
|
8
|
+
slm_api/helpers/FigureHandler.py,sha256=WCK7YxSDd1p3-1M2xhmiEh2Qu1teN0-NYIiikcLneZw,2251
|
|
9
|
+
slm_api/helpers/Leq.py,sha256=2ZDTP9pkIZHcZeEDqQtU-nL1dHgvYsbVxR6Sonnw5ck,4021
|
|
10
|
+
slm_api/helpers/__init__.py,sha256=hB7KKDrb-Xuzvjc7WeZRPEyCTlRfizOz3VBJ0qTj1r4,147
|
|
11
|
+
slm_api/helpers/buffer.py,sha256=k1lCKkCKT8mhHCzs28LTU_JaRRo1X7eo9jg5RduYPCk,670
|
|
12
|
+
slm_api/helpers/data_handler.py,sha256=mmKh4dCirCR32yJE12PntzBeNQpHijvV-oPhMrpHlgg,2984
|
|
13
|
+
slm_api/helpers/fft.py,sha256=p31aiPqnvsFhXwncB9Ixuz7DQEJBtNnm_obQzL8sYNI,1146
|
|
14
|
+
slm_api/helpers/flac_stream_2_samples.py,sha256=--WXFeQLnMZ4EMmYMxV9uogn98N98RYRRbQsZwQjA-s,1886
|
|
15
|
+
slm_api/helpers/https_requests.py,sha256=fL7U-_c4r6Ho1LTBkbkVoUy5pvwiNGTBW6WBOJjqxr4,2701
|
|
16
|
+
slm_api/helpers/measurment_handler.py,sha256=BzoRnd2REWPwG7KKrK9zyWdyADLNWoDRih3almUv7vg,920
|
|
17
|
+
slm_api/helpers/sequence_handler.py,sha256=a6jIgSZwXJaaR5QI1PSX-S7Lsr77pBNF-Q-3hGfVw1Y,1596
|
|
18
|
+
slm_api/helpers/stream_handler.py,sha256=dilwA5Y81G1R2yEleFLCveQJqor4e3QYJ-nNyBzQvMg,4283
|
|
19
|
+
slm_api/helpers/stream_handlers.py,sha256=N1Q7g8ihhrjtGT5sNfKXo9p48kiZpVh_oxSMtvY-NU0,20853
|
|
20
|
+
slm_api/helpers/tmpFileStateMachine.py,sha256=mDBL7PjPfEDoo8Tj-7ds4sx4W6-lavsYGLOHi6n5F-E,3431
|
|
21
|
+
slm_api/helpers/websocket_handler.py,sha256=QQtoMtSE3lojIQ2WpNb6dl5u1iKVGTbynu_oqaX4uVE,497
|
|
22
|
+
slm_api/helpers/webxi_helper_functions.py,sha256=Kc8YECW4wL63JW2DDw1iUY4k_DfYa9ih_TnaQYQ5_K4,3651
|
|
23
|
+
slm_api/helpers/webxi_root.pem,sha256=Vo-uzcN0ZomwWJWp1xaLzSA8mDqlxUAp_c1P31820Jc,1456
|
|
24
|
+
slm_api/mp3_example.py,sha256=Hh8m9emaIOVStgCqG-Vj3KA8mWqn39bfE-IeW3buMXg,6810
|
|
25
|
+
slm_api/multi_device_flac.py,sha256=eiZ0NYhuMbAHfVhf--qhyRU33v8YwIyc5nn_CPGiF0Q,3767
|
|
26
|
+
slm_api/multi_instrument_example.py,sha256=Rg21SSrQ5Ly6ze66cT21jpH-8JOXvdlkBZrxXwOrWLI,1997
|
|
27
|
+
slm_api/screen_record_example.py,sha256=hgeWpEYI2YcsHt8IvB3FOzC19S_5h_sq8jCvSo4BeeA,2183
|
|
28
|
+
slm_api/webxi/README.md,sha256=tlACB4cUWebZTrzmzzGlRwwW5hCpO4tSv6tOasx7uxc,1345
|
|
29
|
+
slm_api/webxi/__init__.py,sha256=iT4laRwuAPXHLZNrYBvwrBHEoIwNyQ0fG6CbQYcVCEY,118
|
|
30
|
+
slm_api/webxi/webxi-header.ksy,sha256=vapyptJbqS8n9c7FiQFbWRv4GuO50KG5_D1a2gJEji8,500
|
|
31
|
+
slm_api/webxi/webxi-stream.ksy,sha256=tve0OzI0ANE-HfPxQLgDHX3-jNwJ3wfwEJKTC38Ne2U,6557
|
|
32
|
+
slm_api/webxi/webxi_header.py,sha256=xHuL3h6OXol2iK6yjXouw9QFvtTQbDn0JpZK-zsadtg,1469
|
|
33
|
+
slm_api/webxi/webxi_stream.py,sha256=CBo6-AqtWvk60WKyFYCkOAI_pDQBd5Kf-0zuPi73iWQ,17310
|
|
34
|
+
slm_open_api_package-0.2.10.dist-info/WHEEL,sha256=9IUYslYuG_asT4WlWvfk_K76nveuLvSTKDoLeL0cV-Q,80
|
|
35
|
+
slm_open_api_package-0.2.10.dist-info/entry_points.txt,sha256=jJT0x7ixsqHY2_HAjA_WRaBt-4vgmpYS4bzCIIcnIXg,51
|
|
36
|
+
slm_open_api_package-0.2.10.dist-info/METADATA,sha256=D94TMF6PpcvbiOz5-LSEWI7jxVe5QJGgbKrK0lre630,6073
|
|
37
|
+
slm_open_api_package-0.2.10.dist-info/RECORD,,
|