CrackNuts 0.0.1.dev2__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.
- cracknuts/__init__.py +5 -0
- cracknuts/__main__.py +33 -0
- cracknuts/acquisition/__init__.py +3 -0
- cracknuts/acquisition/acquisition.py +554 -0
- cracknuts/cracker/__init__.py +0 -0
- cracknuts/cracker/basic_cracker.py +334 -0
- cracknuts/cracker/cracker.py +548 -0
- cracknuts/cracker/mock_cracker.py +163 -0
- cracknuts/cracker/protocol.py +83 -0
- cracknuts/cracker/stateful_cracker.py +214 -0
- cracknuts/logger.py +88 -0
- cracknuts/solver/__init__.py +0 -0
- cracknuts/solver/trace.py +524 -0
- cracknuts/utils/__init__.py +0 -0
- cracknuts/utils/hex_util.py +38 -0
- cracknuts-0.0.1.dev2.dist-info/LICENSE +21 -0
- cracknuts-0.0.1.dev2.dist-info/METADATA +63 -0
- cracknuts-0.0.1.dev2.dist-info/RECORD +21 -0
- cracknuts-0.0.1.dev2.dist-info/WHEEL +5 -0
- cracknuts-0.0.1.dev2.dist-info/entry_points.txt +2 -0
- cracknuts-0.0.1.dev2.dist-info/top_level.txt +1 -0
cracknuts/__init__.py
ADDED
cracknuts/__main__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
import cracknuts
|
|
6
|
+
from cracknuts.cracker import protocol
|
|
7
|
+
from cracknuts.cracker.mock_cracker import MockCracker
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group(help="A library for cracker device.")
|
|
11
|
+
@click.version_option(version=cracknuts.__version__, message="%(version)s")
|
|
12
|
+
def main(): ...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@main.command(help="Start a mock cracker.")
|
|
16
|
+
@click.option("--host", default="127.0.0.1", show_default=True, help="The host to attach to.")
|
|
17
|
+
@click.option("--port", default=protocol.DEFAULT_PORT, show_default=True, help="The port to attach to.", type=int)
|
|
18
|
+
@click.option(
|
|
19
|
+
"--logging_level",
|
|
20
|
+
default="INFO",
|
|
21
|
+
show_default=True,
|
|
22
|
+
help="The logging level of mock cracker.",
|
|
23
|
+
type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]),
|
|
24
|
+
)
|
|
25
|
+
def start_mock_cracker(
|
|
26
|
+
host: str = "127.0.0.1", port: int = protocol.DEFAULT_PORT, logging_level: str | int = logging.INFO
|
|
27
|
+
):
|
|
28
|
+
mock_cracker = MockCracker(host, port, logging_level)
|
|
29
|
+
mock_cracker.start()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
main()
|
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import datetime
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from cracknuts import logger
|
|
10
|
+
from cracknuts.cracker.stateful_cracker import StatefulCracker
|
|
11
|
+
from cracknuts.solver.trace import ScarrTraceDataset, NumpyTraceDataset
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AcqProgress:
|
|
15
|
+
def __init__(self, finished, total):
|
|
16
|
+
self.finished: int = finished
|
|
17
|
+
self.total: int = total
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Acquisition(abc.ABC):
|
|
21
|
+
STATUS_STOPPED: int = 0
|
|
22
|
+
STATUS_TESTING: int = 1
|
|
23
|
+
STATUS_RUNNING: int = 2
|
|
24
|
+
_STATUS_PAUSED_SWITCH: int = -1
|
|
25
|
+
|
|
26
|
+
DO_ERROR_HANDLER_STRATEGY_EXIT: int = 0
|
|
27
|
+
DO_ERROR_HANDLER_STRATEGY_CONTINUE_UNTIL_MAX_ERROR_COUNT: int = 1
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
cracker: StatefulCracker,
|
|
32
|
+
trace_count: int = 1000,
|
|
33
|
+
sample_length: int = 1024,
|
|
34
|
+
sample_offset: int = 0,
|
|
35
|
+
data_length: int = 0,
|
|
36
|
+
trigger_judge_wait_time: float = 0.05,
|
|
37
|
+
trigger_judge_timeout: float = 1.0,
|
|
38
|
+
do_error_handler_strategy: int = DO_ERROR_HANDLER_STRATEGY_EXIT,
|
|
39
|
+
do_error_max_count: int = -1,
|
|
40
|
+
file_format: str = "scarr",
|
|
41
|
+
file_path: str = "auto",
|
|
42
|
+
):
|
|
43
|
+
self._logger = logger.get_logger(self)
|
|
44
|
+
self._last_wave: dict[int, np.ndarray] | None = {1: np.zeros(1)}
|
|
45
|
+
self._status: int = self.STATUS_STOPPED
|
|
46
|
+
self._current_trace_count = 1
|
|
47
|
+
self._run_thread_pause_event: threading.Event = threading.Event()
|
|
48
|
+
|
|
49
|
+
self.cracker: StatefulCracker = cracker
|
|
50
|
+
self.trace_count: int = trace_count
|
|
51
|
+
self.sample_length = sample_length
|
|
52
|
+
self.sample_offset: int = sample_offset
|
|
53
|
+
self.data_length: int = data_length
|
|
54
|
+
self.trigger_judge_wait_time: float = trigger_judge_wait_time # second
|
|
55
|
+
self.trigger_judge_timeout: float = trigger_judge_timeout # second
|
|
56
|
+
self.do_error_handler_strategy: int = do_error_handler_strategy
|
|
57
|
+
self.do_error_max_count: int = do_error_max_count # -1 never exit
|
|
58
|
+
self.file_format: str = file_format
|
|
59
|
+
self.file_path: str = file_path
|
|
60
|
+
|
|
61
|
+
self._on_wave_loaded_callback: typing.Callable[[np.ndarray], None] | None = None
|
|
62
|
+
self._on_status_change_listeners: list[typing.Callable[[int], None]] = []
|
|
63
|
+
self._on_run_progress_changed_listeners: list[typing.Callable[[dict], None]] = []
|
|
64
|
+
|
|
65
|
+
def get_status(self):
|
|
66
|
+
return self._status
|
|
67
|
+
|
|
68
|
+
def set_cracker(self, cracker: StatefulCracker):
|
|
69
|
+
self.cracker = cracker
|
|
70
|
+
|
|
71
|
+
def on_status_changed(self, callback: typing.Callable[[int], None]) -> None:
|
|
72
|
+
"""
|
|
73
|
+
User should not use this function. If you need to perform actions when the ACQ state changes,
|
|
74
|
+
please use the node functions in the ACQ lifecycle point: `init`, `do`, and `finish`.
|
|
75
|
+
|
|
76
|
+
status: 0 stopped, 1 testing, 2 running 3 paused
|
|
77
|
+
"""
|
|
78
|
+
self._on_status_change_listeners.append(callback)
|
|
79
|
+
|
|
80
|
+
def on_run_progress_changed(self, callback: typing.Callable[[dict], None]) -> None:
|
|
81
|
+
self._on_run_progress_changed_listeners.append(callback)
|
|
82
|
+
|
|
83
|
+
def on_wave_loaded(self, callback: typing.Callable[[np.ndarray], None]) -> None:
|
|
84
|
+
self._on_wave_loaded_callback = callback
|
|
85
|
+
|
|
86
|
+
def run(
|
|
87
|
+
self,
|
|
88
|
+
count: int = 1,
|
|
89
|
+
sample_length: int = None,
|
|
90
|
+
sample_offset: int = None,
|
|
91
|
+
data_length: int = None,
|
|
92
|
+
trigger_judge_wait_time: float | None = None,
|
|
93
|
+
trigger_judge_timeout: float | None = None,
|
|
94
|
+
do_error_max_count: int | None = None,
|
|
95
|
+
do_error_handler_strategy: int | None = None,
|
|
96
|
+
file_format: str | None = "scarr",
|
|
97
|
+
file_path: str | None = "auto",
|
|
98
|
+
):
|
|
99
|
+
if self._status < 0:
|
|
100
|
+
self.resume()
|
|
101
|
+
else:
|
|
102
|
+
self._run(
|
|
103
|
+
test=False,
|
|
104
|
+
count=count,
|
|
105
|
+
sample_length=sample_length,
|
|
106
|
+
sample_offset=sample_offset,
|
|
107
|
+
data_length=data_length,
|
|
108
|
+
trigger_judge_wait_time=trigger_judge_wait_time,
|
|
109
|
+
trigger_judge_timeout=trigger_judge_timeout,
|
|
110
|
+
do_error_max_count=do_error_max_count,
|
|
111
|
+
do_error_handler_strategy=do_error_handler_strategy,
|
|
112
|
+
file_format=file_format,
|
|
113
|
+
file_path=file_path,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def run_sync(
|
|
117
|
+
self,
|
|
118
|
+
count=1,
|
|
119
|
+
sample_length: int = None,
|
|
120
|
+
sample_offset: int = None,
|
|
121
|
+
trigger_judge_wait_time: float | None = None,
|
|
122
|
+
trigger_judge_timeout: float | None = None,
|
|
123
|
+
do_error_max_count: int | None = None,
|
|
124
|
+
do_error_handler_strategy: int | None = None,
|
|
125
|
+
file_format: str | None = "scarr",
|
|
126
|
+
):
|
|
127
|
+
try:
|
|
128
|
+
self._do_run(
|
|
129
|
+
test=False,
|
|
130
|
+
count=count,
|
|
131
|
+
sample_length=sample_length,
|
|
132
|
+
sample_offset=sample_offset,
|
|
133
|
+
trigger_judge_wait_time=trigger_judge_wait_time,
|
|
134
|
+
trigger_judge_timeout=trigger_judge_timeout,
|
|
135
|
+
do_error_max_count=do_error_max_count,
|
|
136
|
+
do_error_handler_strategy=do_error_handler_strategy,
|
|
137
|
+
file_format=file_format,
|
|
138
|
+
)
|
|
139
|
+
self._logger.debug("stop by timeout.")
|
|
140
|
+
except KeyboardInterrupt:
|
|
141
|
+
self._logger.debug("stop by interrupted.")
|
|
142
|
+
self.stop()
|
|
143
|
+
|
|
144
|
+
def test(
|
|
145
|
+
self,
|
|
146
|
+
count=-1,
|
|
147
|
+
sample_length: int = None,
|
|
148
|
+
sample_offset: int = None,
|
|
149
|
+
trigger_judge_wait_time: float | None = None,
|
|
150
|
+
trigger_judge_timeout: float | None = None,
|
|
151
|
+
do_error_max_count: int | None = None,
|
|
152
|
+
do_error_handler_strategy: int | None = None,
|
|
153
|
+
):
|
|
154
|
+
if self._status < 0:
|
|
155
|
+
self._logger.debug("Resume to test mode.")
|
|
156
|
+
self.resume()
|
|
157
|
+
else:
|
|
158
|
+
self._logger.debug("Start test mode.")
|
|
159
|
+
self._run(
|
|
160
|
+
test=True,
|
|
161
|
+
count=count,
|
|
162
|
+
sample_length=sample_length,
|
|
163
|
+
sample_offset=sample_offset,
|
|
164
|
+
trigger_judge_wait_time=trigger_judge_wait_time,
|
|
165
|
+
trigger_judge_timeout=trigger_judge_timeout,
|
|
166
|
+
do_error_max_count=do_error_max_count,
|
|
167
|
+
do_error_handler_strategy=do_error_handler_strategy,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def test_sync(
|
|
171
|
+
self,
|
|
172
|
+
count=-1,
|
|
173
|
+
sample_length: int = None,
|
|
174
|
+
sample_offset: int = None,
|
|
175
|
+
trigger_judge_wait_time: float | None = None,
|
|
176
|
+
trigger_judge_timeout: float | None = None,
|
|
177
|
+
do_error_max_count: int | None = None,
|
|
178
|
+
do_error_handler_strategy: int | None = None,
|
|
179
|
+
):
|
|
180
|
+
try:
|
|
181
|
+
self._do_run(
|
|
182
|
+
test=True,
|
|
183
|
+
count=count,
|
|
184
|
+
sample_length=sample_length,
|
|
185
|
+
sample_offset=sample_offset,
|
|
186
|
+
trigger_judge_wait_time=trigger_judge_wait_time,
|
|
187
|
+
trigger_judge_timeout=trigger_judge_timeout,
|
|
188
|
+
do_error_max_count=do_error_max_count,
|
|
189
|
+
do_error_handler_strategy=do_error_handler_strategy,
|
|
190
|
+
)
|
|
191
|
+
except KeyboardInterrupt:
|
|
192
|
+
self._logger.debug("stop by interrupted.")
|
|
193
|
+
self.stop()
|
|
194
|
+
|
|
195
|
+
def pause(self):
|
|
196
|
+
if self._status > 0:
|
|
197
|
+
self._run_thread_pause_event.clear()
|
|
198
|
+
self._status = self._status * self._STATUS_PAUSED_SWITCH
|
|
199
|
+
|
|
200
|
+
def resume(self):
|
|
201
|
+
if self._status < 0:
|
|
202
|
+
self._run_thread_pause_event.set()
|
|
203
|
+
self._status = self._status * self._STATUS_PAUSED_SWITCH
|
|
204
|
+
|
|
205
|
+
def stop(self):
|
|
206
|
+
if not self._run_thread_pause_event.is_set():
|
|
207
|
+
self._run_thread_pause_event.set()
|
|
208
|
+
self._status = self.STATUS_STOPPED
|
|
209
|
+
|
|
210
|
+
def _run(
|
|
211
|
+
self,
|
|
212
|
+
test: bool = True,
|
|
213
|
+
count: int = 1,
|
|
214
|
+
sample_length: int = None,
|
|
215
|
+
sample_offset: int = None,
|
|
216
|
+
data_length: int = None,
|
|
217
|
+
trigger_judge_wait_time: float | None = None,
|
|
218
|
+
trigger_judge_timeout: float | None = None,
|
|
219
|
+
do_error_max_count: int | None = None,
|
|
220
|
+
do_error_handler_strategy: int | None = None,
|
|
221
|
+
file_format: str | None = "scarr",
|
|
222
|
+
file_path: str | None = "auto",
|
|
223
|
+
):
|
|
224
|
+
self._run_thread_pause_event.set()
|
|
225
|
+
threading.Thread(
|
|
226
|
+
target=self._do_run,
|
|
227
|
+
kwargs={
|
|
228
|
+
"test": test,
|
|
229
|
+
"count": count,
|
|
230
|
+
"sample_length": sample_length,
|
|
231
|
+
"sample_offset": sample_offset,
|
|
232
|
+
"data_length": data_length,
|
|
233
|
+
"trigger_judge_wait_time": trigger_judge_wait_time,
|
|
234
|
+
"trigger_judge_timeout": trigger_judge_timeout,
|
|
235
|
+
"do_error_max_count": do_error_max_count,
|
|
236
|
+
"do_error_handler_strategy": do_error_handler_strategy,
|
|
237
|
+
"file_format": file_format,
|
|
238
|
+
"file_path": file_path,
|
|
239
|
+
},
|
|
240
|
+
).start()
|
|
241
|
+
|
|
242
|
+
def _do_run(
|
|
243
|
+
self,
|
|
244
|
+
test: bool = True,
|
|
245
|
+
count: int = 1,
|
|
246
|
+
sample_length: int = 1024,
|
|
247
|
+
sample_offset: int = None,
|
|
248
|
+
data_length: int = None,
|
|
249
|
+
trigger_judge_wait_time: float | None = None,
|
|
250
|
+
trigger_judge_timeout: float | None = None,
|
|
251
|
+
do_error_max_count: int | None = None,
|
|
252
|
+
do_error_handler_strategy: int | None = None,
|
|
253
|
+
file_format: str | None = "scarr",
|
|
254
|
+
file_path: str | None = "auto",
|
|
255
|
+
):
|
|
256
|
+
if self._status > 0:
|
|
257
|
+
raise Exception(f'AcquisitionTemplate is already running in {'run' if self._status == 2 else 'test'} mode.')
|
|
258
|
+
|
|
259
|
+
if not test:
|
|
260
|
+
self._status = self.STATUS_RUNNING
|
|
261
|
+
self._status_changed()
|
|
262
|
+
else:
|
|
263
|
+
self._status = self.STATUS_TESTING
|
|
264
|
+
self._status_changed()
|
|
265
|
+
|
|
266
|
+
self.trace_count = count
|
|
267
|
+
if sample_length is not None:
|
|
268
|
+
self.sample_length = sample_length
|
|
269
|
+
if sample_offset is not None:
|
|
270
|
+
self.sample_offset = sample_offset
|
|
271
|
+
if data_length is not None:
|
|
272
|
+
self.data_length = data_length
|
|
273
|
+
if trigger_judge_wait_time is not None:
|
|
274
|
+
self.trigger_judge_wait_time = trigger_judge_wait_time
|
|
275
|
+
if trigger_judge_timeout is not None:
|
|
276
|
+
self.trigger_judge_timeout = trigger_judge_timeout
|
|
277
|
+
if do_error_max_count is not None:
|
|
278
|
+
self.do_error_max_count = do_error_max_count
|
|
279
|
+
if do_error_handler_strategy is not None:
|
|
280
|
+
self.do_error_handler_strategy = do_error_handler_strategy
|
|
281
|
+
if file_format is not None:
|
|
282
|
+
self.file_format = file_format
|
|
283
|
+
if file_path is not None:
|
|
284
|
+
self.file_path = file_path
|
|
285
|
+
self.pre_init()
|
|
286
|
+
try:
|
|
287
|
+
self.init()
|
|
288
|
+
except Exception as e:
|
|
289
|
+
self._logger.error("Initialization error: %s", e.args)
|
|
290
|
+
return
|
|
291
|
+
self._post_init()
|
|
292
|
+
self._loop(not test, self.file_path, self.file_format)
|
|
293
|
+
self._pre_finish()
|
|
294
|
+
self._finish()
|
|
295
|
+
self._post_finish()
|
|
296
|
+
|
|
297
|
+
def _status_changed(self):
|
|
298
|
+
for listener in self._on_status_change_listeners:
|
|
299
|
+
listener(self._status)
|
|
300
|
+
|
|
301
|
+
def _loop(self, persistent: bool = True, file_path: str = None, file_format: str = "scarr"):
|
|
302
|
+
do_error_count = 0
|
|
303
|
+
trace_index = 0
|
|
304
|
+
self._progress_changed(AcqProgress(trace_index, self.trace_count))
|
|
305
|
+
|
|
306
|
+
cracker_version = self.cracker.get_version()
|
|
307
|
+
if persistent:
|
|
308
|
+
if file_path is None or file_path == "auto":
|
|
309
|
+
file_path = "./dataset/" + datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
|
310
|
+
if file_format == "scarr":
|
|
311
|
+
file_path += ".zarr"
|
|
312
|
+
elif file_format == "numpy":
|
|
313
|
+
file_path += ".npy"
|
|
314
|
+
|
|
315
|
+
if file_format == "scarr":
|
|
316
|
+
dataset = ScarrTraceDataset.new(
|
|
317
|
+
file_path,
|
|
318
|
+
1,
|
|
319
|
+
self.trace_count,
|
|
320
|
+
self.sample_length,
|
|
321
|
+
self.data_length,
|
|
322
|
+
version=f"({cracker_version}, {cracker_version})",
|
|
323
|
+
) # todo channel
|
|
324
|
+
elif file_format == "numpy":
|
|
325
|
+
dataset = NumpyTraceDataset.new(
|
|
326
|
+
file_path,
|
|
327
|
+
1,
|
|
328
|
+
self.trace_count,
|
|
329
|
+
self.sample_length,
|
|
330
|
+
self.data_length,
|
|
331
|
+
version=f"({cracker_version}, {cracker_version})",
|
|
332
|
+
) # todo channel
|
|
333
|
+
else:
|
|
334
|
+
self._logger.warning(f"Unsupported file format: {file_format}")
|
|
335
|
+
else:
|
|
336
|
+
dataset = None
|
|
337
|
+
|
|
338
|
+
while self._status != 0 and self.trace_count - trace_index != 0:
|
|
339
|
+
if self._status < 0:
|
|
340
|
+
self._status_changed()
|
|
341
|
+
self._run_thread_pause_event.wait()
|
|
342
|
+
self._status_changed()
|
|
343
|
+
self._logger.debug("Get wave data: %s", trace_index)
|
|
344
|
+
self.pre_do()
|
|
345
|
+
start = time.time()
|
|
346
|
+
try:
|
|
347
|
+
data = self.do()
|
|
348
|
+
except Exception as e:
|
|
349
|
+
self._logger.error("Do error: %s", e.args)
|
|
350
|
+
do_error_count += 1
|
|
351
|
+
if self.do_error_handler_strategy == self.DO_ERROR_HANDLER_STRATEGY_EXIT:
|
|
352
|
+
self._logger.error("Exit with do error")
|
|
353
|
+
elif do_error_count > self.do_error_max_count:
|
|
354
|
+
self._logger.error(
|
|
355
|
+
f"Exit with do function get error count: {do_error_count} is grate than do_error_max_count"
|
|
356
|
+
)
|
|
357
|
+
break
|
|
358
|
+
else:
|
|
359
|
+
self._logger.error(f"Do function get error count: {do_error_count}")
|
|
360
|
+
continue
|
|
361
|
+
self._logger.debug(f"count: {trace_index} delay: {time.time() - start}")
|
|
362
|
+
trigger_judge_start_time = time.time()
|
|
363
|
+
while self._status != 0:
|
|
364
|
+
trigger_judge_time = time.time() - trigger_judge_start_time
|
|
365
|
+
if trigger_judge_time > self.trigger_judge_timeout:
|
|
366
|
+
self._logger.error(
|
|
367
|
+
"Triggered judge timeout and will get next waves, " "judge time: %s and timeout is %s",
|
|
368
|
+
trigger_judge_time,
|
|
369
|
+
self.trigger_judge_timeout,
|
|
370
|
+
)
|
|
371
|
+
break
|
|
372
|
+
self._logger.debug("Judge trigger status.")
|
|
373
|
+
# if self._is_triggered():
|
|
374
|
+
if True:
|
|
375
|
+
self._last_wave = self._get_waves(self.sample_offset, self.sample_length)
|
|
376
|
+
if self._last_wave is not None:
|
|
377
|
+
self._logger.debug(
|
|
378
|
+
"Got wave: %s.",
|
|
379
|
+
{k: v.shape for k, v in self._last_wave.items()},
|
|
380
|
+
)
|
|
381
|
+
# self._logger.debug('Got wave: ')
|
|
382
|
+
if self._on_wave_loaded_callback and callable(self._on_wave_loaded_callback):
|
|
383
|
+
try:
|
|
384
|
+
self._on_wave_loaded_callback(self._last_wave)
|
|
385
|
+
except Exception as e:
|
|
386
|
+
self._logger.error("Wave loaded event callback error: %s", e.args)
|
|
387
|
+
break
|
|
388
|
+
|
|
389
|
+
time.sleep(self.trigger_judge_wait_time)
|
|
390
|
+
if dataset is not None:
|
|
391
|
+
dataset.set_trace(0, trace_index, self._last_wave[1], data)
|
|
392
|
+
# dataset.set_trace(1, trace_index, self._last_wave[2], data) # todo second channel
|
|
393
|
+
self._post_do()
|
|
394
|
+
trace_index += 1
|
|
395
|
+
self._current_trace_count = trace_index
|
|
396
|
+
self._progress_changed(AcqProgress(trace_index, self.trace_count))
|
|
397
|
+
|
|
398
|
+
if dataset is not None:
|
|
399
|
+
dataset.dump()
|
|
400
|
+
self._status = self.STATUS_STOPPED
|
|
401
|
+
self._status_changed()
|
|
402
|
+
|
|
403
|
+
def _progress_changed(self, progress: "AcqProgress"):
|
|
404
|
+
for listener in self._on_run_progress_changed_listeners:
|
|
405
|
+
listener({"finished": progress.finished, "total": progress.total})
|
|
406
|
+
|
|
407
|
+
def _loop_without_log(self):
|
|
408
|
+
...
|
|
409
|
+
# for i in range(self.trace_count):
|
|
410
|
+
# # print('yes', self._logger.handlers[0].stream)
|
|
411
|
+
# # self._logger.debug('Get wave data: %s', i)
|
|
412
|
+
# self.pre_do()
|
|
413
|
+
# self.do()
|
|
414
|
+
# trigger_judge_start_time = time.time()
|
|
415
|
+
# while self._status:
|
|
416
|
+
# trigger_judge_time = time.time() - trigger_judge_start_time
|
|
417
|
+
# if trigger_judge_time > self.trigger_judge_timeout:
|
|
418
|
+
# # self._logger.error("Triggered judge timeout and will get next waves, "
|
|
419
|
+
# # "judge time: %s and timeout is %s",
|
|
420
|
+
# # trigger_judge_time, self._trigger_judge_timeout)
|
|
421
|
+
# break
|
|
422
|
+
# # self._logger.debug('Judge trigger status.')
|
|
423
|
+
# if self._is_triggered():
|
|
424
|
+
# self._last_wave = self._get_waves()
|
|
425
|
+
# if self._last_wave is not None:
|
|
426
|
+
# ...
|
|
427
|
+
# # self._logger.debug('Got wave: %s.', self._last_wave.shape)
|
|
428
|
+
# if self._on_wave_loaded_callback and callable(self._on_wave_loaded_callback):
|
|
429
|
+
# try:
|
|
430
|
+
# self._on_wave_loaded_callback(self._last_wave)
|
|
431
|
+
# except Exception as e:
|
|
432
|
+
# ...
|
|
433
|
+
# # self._logger.error('Wave loaded event callback error: %s', e.args)
|
|
434
|
+
# time.sleep(1)
|
|
435
|
+
# break
|
|
436
|
+
# time.sleep(self.trigger_judge_wait_time)
|
|
437
|
+
# self._save_wave()
|
|
438
|
+
# self._post_do()
|
|
439
|
+
|
|
440
|
+
def connect_scrat(self):
|
|
441
|
+
"""
|
|
442
|
+
Connect to scrat device
|
|
443
|
+
:return:
|
|
444
|
+
"""
|
|
445
|
+
...
|
|
446
|
+
|
|
447
|
+
def connect_cracker(self):
|
|
448
|
+
"""
|
|
449
|
+
Connect to cracker device.
|
|
450
|
+
:return:
|
|
451
|
+
"""
|
|
452
|
+
self.cracker.connect()
|
|
453
|
+
|
|
454
|
+
def connect_net(self): ...
|
|
455
|
+
|
|
456
|
+
def config_scrat(self): ...
|
|
457
|
+
|
|
458
|
+
def config_cracker(self): ...
|
|
459
|
+
|
|
460
|
+
def pre_init(self):
|
|
461
|
+
self.cracker.sync_config_to_cracker()
|
|
462
|
+
|
|
463
|
+
@abc.abstractmethod
|
|
464
|
+
def init(self): ...
|
|
465
|
+
|
|
466
|
+
def _post_init(self): ...
|
|
467
|
+
|
|
468
|
+
def transfer(self): ...
|
|
469
|
+
|
|
470
|
+
def pre_do(self):
|
|
471
|
+
self.cracker.osc_single()
|
|
472
|
+
|
|
473
|
+
@abc.abstractmethod
|
|
474
|
+
def do(self): ...
|
|
475
|
+
|
|
476
|
+
def _do(self):
|
|
477
|
+
try:
|
|
478
|
+
self.do()
|
|
479
|
+
return True
|
|
480
|
+
except Exception as e:
|
|
481
|
+
self._logger.error("Do error: %s", e.args)
|
|
482
|
+
return False
|
|
483
|
+
|
|
484
|
+
def _post_do(self): ...
|
|
485
|
+
|
|
486
|
+
def _is_triggered(self):
|
|
487
|
+
return self.cracker.osc_is_triggered()
|
|
488
|
+
|
|
489
|
+
def _get_waves(self, offset: int, sample_count: int) -> dict[int, np.ndarray]:
|
|
490
|
+
enable_channels = [k for k, v in self.cracker.get_current_config().osc_analog_channel_enable.items() if v]
|
|
491
|
+
wave_dict = {}
|
|
492
|
+
for c in enable_channels:
|
|
493
|
+
status, wave_dict[c] = self.cracker.osc_get_analog_wave(c, offset, sample_count)
|
|
494
|
+
return wave_dict
|
|
495
|
+
|
|
496
|
+
def save_data(self, data_type: str = "zarr"):
|
|
497
|
+
"""
|
|
498
|
+
Save wave, key and other info to acquisition dataset file.
|
|
499
|
+
"""
|
|
500
|
+
# if data_type == 'zarr':
|
|
501
|
+
# zarr.create()
|
|
502
|
+
...
|
|
503
|
+
|
|
504
|
+
def _pre_finish(self): ...
|
|
505
|
+
|
|
506
|
+
def _post_finish(self): ...
|
|
507
|
+
|
|
508
|
+
def _save_dataset(self): ...
|
|
509
|
+
|
|
510
|
+
def _finish(self):
|
|
511
|
+
pass
|
|
512
|
+
|
|
513
|
+
def get_last_wave(self) -> dict[int, np.ndarray]:
|
|
514
|
+
return self._last_wave
|
|
515
|
+
|
|
516
|
+
@staticmethod
|
|
517
|
+
def builder():
|
|
518
|
+
return AcquisitionBuilder()
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class AcquisitionBuilder:
|
|
522
|
+
def __init__(self):
|
|
523
|
+
self._cracker = None
|
|
524
|
+
self._do_function = lambda _: ...
|
|
525
|
+
self._init_function = lambda _: ...
|
|
526
|
+
|
|
527
|
+
def cracker(self, cracker: StatefulCracker):
|
|
528
|
+
self._cracker = cracker
|
|
529
|
+
return self
|
|
530
|
+
|
|
531
|
+
def init(self, init_function: typing.Callable[[StatefulCracker], None]):
|
|
532
|
+
if init_function:
|
|
533
|
+
self._init_function = init_function
|
|
534
|
+
return self
|
|
535
|
+
|
|
536
|
+
def do(self, do_function: typing.Callable[[StatefulCracker], None]):
|
|
537
|
+
if do_function:
|
|
538
|
+
self._do_function = do_function
|
|
539
|
+
return self
|
|
540
|
+
|
|
541
|
+
def build(self, **kwargs):
|
|
542
|
+
if self._cracker is None:
|
|
543
|
+
raise ValueError("No cracker")
|
|
544
|
+
|
|
545
|
+
builder_self = self
|
|
546
|
+
|
|
547
|
+
class AnonymousAcquisition(Acquisition):
|
|
548
|
+
def init(self):
|
|
549
|
+
builder_self._init_function(self.cracker)
|
|
550
|
+
|
|
551
|
+
def do(self):
|
|
552
|
+
return builder_self._do_function(self.cracker)
|
|
553
|
+
|
|
554
|
+
return AnonymousAcquisition(builder_self._cracker, **kwargs)
|
|
File without changes
|