pymodaq 3.6.12__py3-none-any.whl → 4.0.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.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +13 -6
- pymodaq/control_modules/__init__.py +0 -7
- pymodaq/control_modules/daq_move.py +965 -2
- pymodaq/control_modules/daq_move_ui.py +319 -0
- pymodaq/control_modules/daq_viewer.py +1573 -3
- pymodaq/control_modules/daq_viewer_ui.py +393 -0
- pymodaq/control_modules/mocks.py +51 -0
- pymodaq/control_modules/move_utility_classes.py +709 -8
- pymodaq/control_modules/utils.py +256 -0
- pymodaq/control_modules/viewer_utility_classes.py +663 -6
- pymodaq/daq_utils.py +89 -0
- pymodaq/dashboard.py +91 -72
- pymodaq/examples/custom_app.py +12 -11
- pymodaq/examples/custom_viewer.py +10 -10
- pymodaq/examples/function_plotter.py +16 -13
- pymodaq/examples/nonlinearscanner.py +8 -6
- pymodaq/examples/parameter_ex.py +7 -7
- pymodaq/examples/preset_MockCamera.xml +1 -0
- pymodaq/extensions/__init__.py +16 -0
- pymodaq/extensions/console.py +76 -0
- pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
- pymodaq/extensions/daq_scan.py +1339 -0
- pymodaq/extensions/daq_scan_ui.py +240 -0
- pymodaq/extensions/h5browser.py +23 -0
- pymodaq/{pid → extensions/pid}/__init__.py +4 -2
- pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
- pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
- pymodaq/{pid → extensions/pid}/utils.py +52 -6
- pymodaq/extensions/utils.py +40 -0
- pymodaq/post_treatment/__init__.py +6 -0
- pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
- pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
- pymodaq/post_treatment/load_and_plot.py +219 -0
- pymodaq/post_treatment/process_to_scalar.py +263 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
- pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +32 -13
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
- pymodaq/utils/__init__.py +0 -29
- pymodaq/utils/abstract/__init__.py +48 -0
- pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
- pymodaq/utils/array_manipulation.py +379 -8
- pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
- pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
- pymodaq/utils/config.py +448 -0
- pymodaq/utils/conftests.py +5 -0
- pymodaq/utils/daq_utils.py +828 -8
- pymodaq/utils/data.py +1873 -7
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
- pymodaq/{daq_utils → utils}/enums.py +12 -7
- pymodaq/utils/exceptions.py +37 -0
- pymodaq/utils/factory.py +82 -0
- pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
- pymodaq/utils/gui_utils/custom_app.py +129 -0
- pymodaq/utils/gui_utils/file_io.py +66 -0
- pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
- pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
- pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
- pymodaq/utils/gui_utils/widgets/label.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
- pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
- pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
- pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
- pymodaq/utils/h5modules/__init__.py +1 -0
- pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
- pymodaq/utils/h5modules/browsing.py +683 -0
- pymodaq/utils/h5modules/data_saving.py +839 -0
- pymodaq/utils/h5modules/h5logging.py +110 -0
- pymodaq/utils/h5modules/module_saving.py +350 -0
- pymodaq/utils/h5modules/saving.py +914 -0
- pymodaq/utils/h5modules/utils.py +85 -0
- pymodaq/utils/logger.py +64 -6
- pymodaq/utils/managers/action_manager.py +460 -0
- pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
- pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
- pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
- pymodaq/utils/managers/parameter_manager.py +110 -0
- pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
- pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
- pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
- pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
- pymodaq/utils/math_utils.py +546 -10
- pymodaq/{daq_utils → utils}/messenger.py +5 -1
- pymodaq/utils/parameter/__init__.py +2 -15
- pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
- pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
- pymodaq/utils/parameter/utils.py +206 -11
- pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
- pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
- pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
- pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
- pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
- pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
- pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
- pymodaq/utils/plotting/navigator.py +355 -0
- pymodaq/utils/plotting/scan_selector.py +480 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
- pymodaq/utils/plotting/utils/filter.py +538 -0
- pymodaq/utils/plotting/utils/lineout.py +224 -0
- pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
- pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
- pymodaq/utils/plotting/widgets.py +76 -0
- pymodaq/utils/scanner/__init__.py +10 -0
- pymodaq/utils/scanner/scan_factory.py +204 -0
- pymodaq/utils/scanner/scanner.py +271 -0
- pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
- pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
- pymodaq/utils/scanner/scanners/sequential.py +192 -0
- pymodaq/utils/scanner/scanners/tabular.py +294 -0
- pymodaq/utils/scanner/utils.py +83 -0
- pymodaq/utils/slicing.py +47 -0
- pymodaq/utils/svg/__init__.py +6 -0
- pymodaq/utils/svg/svg_renderer.py +20 -0
- pymodaq/utils/svg/svg_view.py +35 -0
- pymodaq/utils/svg/svg_viewer2D.py +51 -0
- pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
- pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
- pymodaq/utils/units.py +216 -0
- pymodaq-4.0.1.dist-info/METADATA +159 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
- pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
- pymodaq/daq_move/daq_move_gui.py +0 -279
- pymodaq/daq_move/daq_move_gui.ui +0 -534
- pymodaq/daq_move/daq_move_main.py +0 -1042
- pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
- pymodaq/daq_move/utility_classes.py +0 -671
- pymodaq/daq_scan.py +0 -2160
- pymodaq/daq_utils/array_manipulation.py +0 -386
- pymodaq/daq_utils/config.py +0 -273
- pymodaq/daq_utils/conftests.py +0 -7
- pymodaq/daq_utils/custom_parameter_tree.py +0 -9
- pymodaq/daq_utils/daq_enums.py +0 -133
- pymodaq/daq_utils/daq_utils.py +0 -1402
- pymodaq/daq_utils/exceptions.py +0 -71
- pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
- pymodaq/daq_utils/gui_utils/file_io.py +0 -75
- pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
- pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
- pymodaq/daq_utils/h5exporters.py +0 -242
- pymodaq/daq_utils/h5modules.py +0 -1559
- pymodaq/daq_utils/h5utils.py +0 -241
- pymodaq/daq_utils/managers/action_manager.py +0 -236
- pymodaq/daq_utils/managers/parameter_manager.py +0 -57
- pymodaq/daq_utils/math_utils.py +0 -705
- pymodaq/daq_utils/parameter/__init__.py +0 -1
- pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
- pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
- pymodaq/daq_utils/parameter/utils.py +0 -136
- pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
- pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
- pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
- pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
- pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
- pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
- pymodaq/daq_utils/plotting/items/__init__.py +0 -0
- pymodaq/daq_utils/plotting/navigator.py +0 -500
- pymodaq/daq_utils/plotting/scan_selector.py +0 -289
- pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
- pymodaq/daq_utils/plotting/utils/filter.py +0 -236
- pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
- pymodaq/daq_utils/scanner.py +0 -1289
- pymodaq/daq_utils/tree_layout/__init__.py +0 -0
- pymodaq/daq_viewer/__init__.py +0 -0
- pymodaq/daq_viewer/daq_gui_settings.py +0 -237
- pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
- pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
- pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
- pymodaq/daq_viewer/utility_classes.py +0 -673
- pymodaq/examples/logger_image/__init__.py +0 -0
- pymodaq/examples/logger_image/logger_displayer.py +0 -121
- pymodaq/examples/logger_image/setup.svg +0 -3119
- pymodaq/examples/logger_image/setup_svg.py +0 -114
- pymodaq/h5browser.py +0 -39
- pymodaq/utils/scanner.py +0 -15
- pymodaq-3.6.12.dist-info/METADATA +0 -39
- pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
- pymodaq-3.6.12.dist-info/top_level.txt +0 -1
- /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
- /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
- /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
- /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
- /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
- /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
- /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
- /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,7 +1,1577 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""
|
|
3
|
-
Created
|
|
3
|
+
Created on Wed Jan 10 16:54:14 2018
|
|
4
4
|
|
|
5
|
-
@author:
|
|
5
|
+
@author: Weber Sébastien
|
|
6
6
|
"""
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
from collections import OrderedDict
|
|
9
|
+
import copy
|
|
10
|
+
import datetime
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import sys
|
|
14
|
+
from typing import List, Tuple, Union
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
from easydict import EasyDict as edict
|
|
18
|
+
import numpy as np
|
|
19
|
+
from qtpy import QtWidgets
|
|
20
|
+
from qtpy.QtCore import Qt, QObject, Slot, QThread, Signal
|
|
21
|
+
|
|
22
|
+
from pymodaq.utils.data import DataRaw, DataFromPlugins, DataToExport, Axis, DataDistribution
|
|
23
|
+
from pymodaq.utils.logger import set_logger, get_module_name
|
|
24
|
+
from pymodaq.control_modules.utils import ControlModule
|
|
25
|
+
from pymodaq.utils.gui_utils.file_io import select_file
|
|
26
|
+
from pymodaq.utils.gui_utils.utils import widget_to_png_to_bytes
|
|
27
|
+
import pymodaq.utils.scanner
|
|
28
|
+
from pymodaq.utils.tcp_server_client import TCPClient
|
|
29
|
+
from pymodaq.utils.gui_utils.widgets.lcd import LCD
|
|
30
|
+
from pymodaq.utils.config import Config, get_set_local_dir
|
|
31
|
+
from pymodaq.utils.h5modules.browsing import browse_data
|
|
32
|
+
from pymodaq.utils.h5modules.saving import H5Saver
|
|
33
|
+
from pymodaq.utils.h5modules import module_saving
|
|
34
|
+
from pymodaq.utils.daq_utils import ThreadCommand
|
|
35
|
+
from pymodaq.utils.parameter import ioxml
|
|
36
|
+
from pymodaq.utils.parameter import utils as putils
|
|
37
|
+
from pymodaq.control_modules.viewer_utility_classes import params as daq_viewer_params
|
|
38
|
+
from pymodaq.utils import daq_utils as utils
|
|
39
|
+
from pymodaq.utils.messenger import deprecation_msg
|
|
40
|
+
from pymodaq.utils.gui_utils import DockArea, get_splash_sc, Dock
|
|
41
|
+
from pymodaq.utils.managers.parameter_manager import ParameterManager, Parameter
|
|
42
|
+
from pymodaq.control_modules.daq_viewer_ui import DAQ_Viewer_UI
|
|
43
|
+
from pymodaq.control_modules.utils import DET_TYPES, get_viewer_plugins, DAQTypesEnum
|
|
44
|
+
from pymodaq.utils.plotting.data_viewers.viewer import ViewerBase, ViewersEnum
|
|
45
|
+
from pymodaq.utils.enums import enum_checker
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
logger = set_logger(get_module_name(__file__))
|
|
49
|
+
config = Config()
|
|
50
|
+
|
|
51
|
+
local_path = get_set_local_dir()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DAQ_Viewer(ParameterManager, ControlModule):
|
|
55
|
+
""" Main PyMoDAQ class to drive detectors
|
|
56
|
+
|
|
57
|
+
Qt object and generic UI to drive actuators. The class is giving you full functionality to select (daq_detector),
|
|
58
|
+
initialize detectors (init_hardware), grab or snap data (grab_data) and save them (save_new, save_current). If
|
|
59
|
+
a DockArea is given as parent widget, the full User Interface (DAQ_Viewer_UI) is loaded allowing easy control of the
|
|
60
|
+
instrument.
|
|
61
|
+
|
|
62
|
+
Attributes
|
|
63
|
+
----------
|
|
64
|
+
grab_done_signal: Signal[OrderedDict]
|
|
65
|
+
Signal emitted when the data from the plugin (and eventually from the data viewers) has been received. To be
|
|
66
|
+
used by connected objects.
|
|
67
|
+
custom_sig: Signal[ThreadCommand]
|
|
68
|
+
use this to propagate info/data coming from the hardware plugin to another object
|
|
69
|
+
overshoot_signal: Signal[bool]
|
|
70
|
+
This signal is emitted when some 0D data from the plugin is higher than the overshoot threshold set in the
|
|
71
|
+
settings
|
|
72
|
+
|
|
73
|
+
See Also
|
|
74
|
+
--------
|
|
75
|
+
ControlModule, DAQ_Viewer_UI, ParameterManager
|
|
76
|
+
|
|
77
|
+
Notes
|
|
78
|
+
-----
|
|
79
|
+
A particular signal from the 2D DataViewer is directly connected to the plugin: ROI_select_signal. The position and
|
|
80
|
+
size of the corresponding ROI is then directly transferred to a plugin function named `ROISelect` that you have to
|
|
81
|
+
create if one want to receive infos from the ROI
|
|
82
|
+
"""
|
|
83
|
+
settings_name = 'daq_viewer_settings'
|
|
84
|
+
custom_sig = Signal(ThreadCommand) # particular case where DAQ_Viewer is used for a custom module
|
|
85
|
+
|
|
86
|
+
grab_done_signal = Signal(DataToExport)
|
|
87
|
+
|
|
88
|
+
_update_settings_signal = Signal(edict)
|
|
89
|
+
overshoot_signal = Signal(bool)
|
|
90
|
+
data_saved = Signal()
|
|
91
|
+
grab_status = Signal(bool)
|
|
92
|
+
|
|
93
|
+
params = daq_viewer_params
|
|
94
|
+
|
|
95
|
+
def __init__(self, parent=None, title="Testing",
|
|
96
|
+
daq_type=config('viewer', 'daq_type'),
|
|
97
|
+
dock_settings=None, dock_viewer=None):
|
|
98
|
+
|
|
99
|
+
self.logger = set_logger(f'{logger.name}.{title}')
|
|
100
|
+
self.logger.info(f'Initializing DAQ_Viewer: {title}')
|
|
101
|
+
|
|
102
|
+
QObject.__init__(self)
|
|
103
|
+
ParameterManager.__init__(self)
|
|
104
|
+
ControlModule.__init__(self)
|
|
105
|
+
|
|
106
|
+
daq_type = enum_checker(DAQTypesEnum, daq_type)
|
|
107
|
+
self._daq_type: DAQTypesEnum = daq_type
|
|
108
|
+
|
|
109
|
+
self._viewer_types: List[ViewersEnum] = []
|
|
110
|
+
self._viewers: List[ViewerBase] = []
|
|
111
|
+
|
|
112
|
+
if isinstance(parent, DockArea):
|
|
113
|
+
self.dockarea = parent
|
|
114
|
+
else:
|
|
115
|
+
self.dockarea = None
|
|
116
|
+
|
|
117
|
+
self.parent = parent
|
|
118
|
+
if parent is not None:
|
|
119
|
+
self.ui: DAQ_Viewer_UI = DAQ_Viewer_UI(parent, title, daq_type=daq_type,
|
|
120
|
+
dock_settings=dock_settings,
|
|
121
|
+
dock_viewer=dock_viewer)
|
|
122
|
+
else:
|
|
123
|
+
self.ui: DAQ_Viewer_UI = None
|
|
124
|
+
|
|
125
|
+
if self.ui is not None:
|
|
126
|
+
QtWidgets.QApplication.processEvents()
|
|
127
|
+
self.ui.add_setting_tree(self.settings_tree)
|
|
128
|
+
self.ui.command_sig.connect(self.process_ui_cmds)
|
|
129
|
+
self.ui.add_setting_tree(self.settings_tree)
|
|
130
|
+
self.viewers = self.ui.viewers
|
|
131
|
+
self._viewer_types = self.ui.viewer_types
|
|
132
|
+
|
|
133
|
+
self.splash_sc = get_splash_sc()
|
|
134
|
+
|
|
135
|
+
self._title = title
|
|
136
|
+
|
|
137
|
+
self.module_and_data_saver: Union[module_saving.DetectorSaver,
|
|
138
|
+
module_saving.DetectorEnlargeableSaver,
|
|
139
|
+
module_saving.DetectorExtendedSaver] = None
|
|
140
|
+
self.setup_saving_objects()
|
|
141
|
+
|
|
142
|
+
self._external_h5_data = None
|
|
143
|
+
|
|
144
|
+
self.settings.child('main_settings', 'DAQ_type').setValue(self.daq_type.name)
|
|
145
|
+
self._detectors: List[str] = [det_dict['name'] for det_dict in DET_TYPES[self.daq_type.name]]
|
|
146
|
+
if len(self._detectors) > 0: # will be 0 if no valid plugins are installed
|
|
147
|
+
self._detector: str = self._detectors[0]
|
|
148
|
+
self.settings.child('main_settings', 'detector_type').setValue(self._detector)
|
|
149
|
+
|
|
150
|
+
self._grabing: bool = False
|
|
151
|
+
self._do_bkg: bool = False
|
|
152
|
+
self._take_bkg: bool = False
|
|
153
|
+
|
|
154
|
+
self._grab_done: bool = False
|
|
155
|
+
self._start_grab_time: float = 0. # used for the refreshing rate
|
|
156
|
+
self._received_data: int = 0
|
|
157
|
+
|
|
158
|
+
self._lcd: LCD = None
|
|
159
|
+
|
|
160
|
+
self._bkg: List[DataFromPlugins] = None # buffer to store background
|
|
161
|
+
|
|
162
|
+
self._save_file_pathname: Path = None # to store last active path, will be an Path object
|
|
163
|
+
|
|
164
|
+
self._snapshot_pathname: Path = None
|
|
165
|
+
self._current_data: DataToExport = None
|
|
166
|
+
self._data_to_save_export: DataToExport = None
|
|
167
|
+
|
|
168
|
+
self._do_save_data: bool = False
|
|
169
|
+
|
|
170
|
+
self._set_setting_tree() # to activate parameters of default Mock detector
|
|
171
|
+
|
|
172
|
+
self.grab_done_signal.connect(self._save_export_data)
|
|
173
|
+
|
|
174
|
+
def __repr__(self):
|
|
175
|
+
return f'{self.__class__.__name__}: {self.title} ({self.daq_type}/{self.detector}'
|
|
176
|
+
|
|
177
|
+
def setup_saving_objects(self):
|
|
178
|
+
self.module_and_data_saver = module_saving.DetectorSaver(self)
|
|
179
|
+
self._h5saver_continuous = H5Saver(save_type='detector')
|
|
180
|
+
self._h5saver_continuous.show_settings(False)
|
|
181
|
+
self._h5saver_continuous.settings.child('do_save').sigValueChanged.connect(self._init_continuous_save)
|
|
182
|
+
if self.ui is not None:
|
|
183
|
+
self.ui.add_setting_tree(self._h5saver_continuous.settings_tree)
|
|
184
|
+
|
|
185
|
+
def process_ui_cmds(self, cmd: utils.ThreadCommand):
|
|
186
|
+
"""Process commands sent by actions done in the ui
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
cmd: ThreadCommand
|
|
191
|
+
Possible values are:
|
|
192
|
+
* init
|
|
193
|
+
* quit
|
|
194
|
+
* grab
|
|
195
|
+
* snap
|
|
196
|
+
* stop
|
|
197
|
+
* show_log
|
|
198
|
+
* detector_changed
|
|
199
|
+
* daq_type_changed
|
|
200
|
+
* save_current
|
|
201
|
+
* save_new
|
|
202
|
+
* do_bkg
|
|
203
|
+
* take_bkg
|
|
204
|
+
* viewers_changed
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
if cmd.command == 'init':
|
|
208
|
+
self.init_hardware(cmd.attribute[0])
|
|
209
|
+
elif cmd.command == 'quit':
|
|
210
|
+
self.quit_fun()
|
|
211
|
+
elif cmd.command == 'stop':
|
|
212
|
+
self.stop()
|
|
213
|
+
elif cmd.command == 'show_log':
|
|
214
|
+
self.show_log()
|
|
215
|
+
elif cmd.command == 'grab':
|
|
216
|
+
self.grab_data(cmd.attribute, snap_state=False)
|
|
217
|
+
elif cmd.command == 'snap':
|
|
218
|
+
self.grab_data(False, snap_state=True)
|
|
219
|
+
elif cmd.command == 'save_new':
|
|
220
|
+
self.save_new()
|
|
221
|
+
elif cmd.command == 'save_current':
|
|
222
|
+
self.save_current()
|
|
223
|
+
elif cmd.command == 'open':
|
|
224
|
+
self.load_data()
|
|
225
|
+
elif cmd.command == 'detector_changed':
|
|
226
|
+
if cmd.attribute != '':
|
|
227
|
+
self.detector_changed_from_ui(cmd.attribute)
|
|
228
|
+
elif cmd.command == 'daq_type_changed':
|
|
229
|
+
if cmd.attribute != '':
|
|
230
|
+
self.daq_type_changed_from_ui(cmd.attribute)
|
|
231
|
+
elif cmd.command == 'take_bkg':
|
|
232
|
+
self.take_bkg()
|
|
233
|
+
elif cmd.command == 'do_bkg':
|
|
234
|
+
self.do_bkg = cmd.attribute
|
|
235
|
+
elif cmd.command == 'viewers_changed':
|
|
236
|
+
self._viewer_types: List[ViewersEnum] = cmd.attribute['viewer_types']
|
|
237
|
+
self.viewers = cmd.attribute['viewers']
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def bkg(self):
|
|
241
|
+
return self._bkg
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def viewer_docks(self):
|
|
245
|
+
""":obj:`list` of Viewer Docks from the UI"""
|
|
246
|
+
if self.ui is not None:
|
|
247
|
+
return self.ui.viewer_docks
|
|
248
|
+
|
|
249
|
+
def daq_type_changed_from_ui(self, daq_type: DAQTypesEnum):
|
|
250
|
+
daq_type = enum_checker(DAQTypesEnum, daq_type)
|
|
251
|
+
self._daq_type = daq_type
|
|
252
|
+
self.settings.child('main_settings', 'DAQ_type').setValue(daq_type.name)
|
|
253
|
+
self.detectors = [det_dict['name'] for det_dict in DET_TYPES[daq_type.name]]
|
|
254
|
+
self.detector = self.detectors[0]
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def daq_type(self) -> DAQTypesEnum:
|
|
258
|
+
""":obj:`DAQTypesEnum`: Get/Set the daq_type
|
|
259
|
+
|
|
260
|
+
Update the detector property with the list of available detectors of a given daq_type
|
|
261
|
+
"""
|
|
262
|
+
return self._daq_type
|
|
263
|
+
|
|
264
|
+
@daq_type.setter
|
|
265
|
+
def daq_type(self, daq_type: DAQTypesEnum):
|
|
266
|
+
daq_type = enum_checker(DAQTypesEnum, daq_type)
|
|
267
|
+
|
|
268
|
+
self._daq_type = daq_type
|
|
269
|
+
if self.ui is not None:
|
|
270
|
+
self.ui.daq_type = daq_type
|
|
271
|
+
self.settings.child('main_settings', 'DAQ_type').setValue(daq_type.name)
|
|
272
|
+
self.detectors = [det_dict['name'] for det_dict in DET_TYPES[daq_type.name]]
|
|
273
|
+
self.detector = self.detectors[0]
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def daq_types(self):
|
|
277
|
+
""":obj:`list` of :obj:`str`: List of available DAQ_TYPES"""
|
|
278
|
+
return DAQTypesEnum.names()
|
|
279
|
+
|
|
280
|
+
def detector_changed_from_ui(self, detector):
|
|
281
|
+
self._detector = detector
|
|
282
|
+
self._set_setting_tree()
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
def detector(self):
|
|
286
|
+
""":obj:`str`: Get/Set the detector among detectors property"""
|
|
287
|
+
return self._detector
|
|
288
|
+
|
|
289
|
+
@detector.setter
|
|
290
|
+
def detector(self, det):
|
|
291
|
+
if det not in self.detectors:
|
|
292
|
+
raise ValueError(f'{det} is not a valid Detector: {self.detectors}')
|
|
293
|
+
self._detector = det
|
|
294
|
+
if self.ui is not None:
|
|
295
|
+
self.ui.detector = det
|
|
296
|
+
self._set_setting_tree()
|
|
297
|
+
|
|
298
|
+
def detectors_changed_from_ui(self, detectors):
|
|
299
|
+
self._detectors = detectors
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def detectors(self):
|
|
303
|
+
""":obj:`list` of :obj:`str`: List of available detectors of the current daq_type"""
|
|
304
|
+
return self._detectors
|
|
305
|
+
|
|
306
|
+
@detectors.setter
|
|
307
|
+
def detectors(self, detectors):
|
|
308
|
+
self._detectors = detectors
|
|
309
|
+
if self.ui is not None:
|
|
310
|
+
self.ui.detectors = detectors
|
|
311
|
+
|
|
312
|
+
@property
|
|
313
|
+
def grab_state(self):
|
|
314
|
+
""":obj:`bool`: Get the current grabbing status"""
|
|
315
|
+
return self._grabing
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def do_bkg(self):
|
|
320
|
+
""":obj:`bool`: Get/Set if background subtraction should be done"""
|
|
321
|
+
return self._do_bkg
|
|
322
|
+
|
|
323
|
+
@do_bkg.setter
|
|
324
|
+
def do_bkg(self, doit: bool):
|
|
325
|
+
self._do_bkg = doit
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def viewers(self) -> List[ViewerBase]:
|
|
329
|
+
""":obj:`list` of Viewers from the UI"""
|
|
330
|
+
if self.ui is not None:
|
|
331
|
+
return self._viewers
|
|
332
|
+
|
|
333
|
+
@viewers.setter
|
|
334
|
+
def viewers(self, viewers):
|
|
335
|
+
for viewer in self._viewers:
|
|
336
|
+
try:
|
|
337
|
+
viewer.data_to_export_signal.disconnect()
|
|
338
|
+
except:
|
|
339
|
+
pass
|
|
340
|
+
for viewer in viewers:
|
|
341
|
+
viewer.data_to_export_signal.connect(self._get_data_from_viewer)
|
|
342
|
+
if hasattr(viewer, 'ROI_select_signal'):
|
|
343
|
+
viewer.ROI_select_signal.connect(
|
|
344
|
+
lambda roi_pos_size: self.command_hardware.emit(ThreadCommand('ROISelect', roi_pos_size)))
|
|
345
|
+
self._viewers = viewers
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def viewers_docks(self):
|
|
349
|
+
if self.ui is not None:
|
|
350
|
+
return self.ui.viewer_docks
|
|
351
|
+
|
|
352
|
+
def quit_fun(self):
|
|
353
|
+
"""Quit the application, closing the hardware and other modules
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
# insert anything that needs to be closed before leaving
|
|
357
|
+
|
|
358
|
+
if self._initialized_state: # means initialized
|
|
359
|
+
self.init_hardware(False)
|
|
360
|
+
self.quit_signal.emit()
|
|
361
|
+
|
|
362
|
+
if self._lcd is not None:
|
|
363
|
+
try:
|
|
364
|
+
self._lcd.parent.close()
|
|
365
|
+
except Exception as e:
|
|
366
|
+
self.logger.exception(str(e))
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
if self.ui is not None:
|
|
370
|
+
self.ui.close()
|
|
371
|
+
|
|
372
|
+
except Exception as e:
|
|
373
|
+
self.logger.exception(str(e))
|
|
374
|
+
|
|
375
|
+
if __name__ == '__main__':
|
|
376
|
+
self.parent.close()
|
|
377
|
+
|
|
378
|
+
# #####################################
|
|
379
|
+
# Methods for running the acquisition
|
|
380
|
+
|
|
381
|
+
def init_hardware_ui(self, do_init=True):
|
|
382
|
+
"""Send a command to the underlying UI to click the init button"""
|
|
383
|
+
if self.ui is not None:
|
|
384
|
+
self.ui.do_init()
|
|
385
|
+
|
|
386
|
+
def init_det(self):
|
|
387
|
+
deprecation_msg(f'The function *init_det* is deprecated, use init_hardware_ui')
|
|
388
|
+
self.init_hardware_ui(True)
|
|
389
|
+
|
|
390
|
+
def ini_det_fun(self):
|
|
391
|
+
deprecation_msg(f'The function *ini_det_fun* is deprecated, use init_hardware')
|
|
392
|
+
self.init_hardware(True)
|
|
393
|
+
|
|
394
|
+
def init_hardware(self, do_init=True):
|
|
395
|
+
"""Init the selected detector
|
|
396
|
+
|
|
397
|
+
Parameters
|
|
398
|
+
----------
|
|
399
|
+
do_init: bool
|
|
400
|
+
If True, create a DAQ_Detector instance and move it into a separated thread, connected its signals/slots
|
|
401
|
+
to the DAQ_Viewer object (self)
|
|
402
|
+
If False, force the instrument to close and kill the Thread (still not done properly in some cases)
|
|
403
|
+
"""
|
|
404
|
+
if not do_init:
|
|
405
|
+
try:
|
|
406
|
+
self.command_hardware.emit(ThreadCommand(command="close"))
|
|
407
|
+
QtWidgets.QApplication.processEvents()
|
|
408
|
+
if self.ui is not None:
|
|
409
|
+
self.ui.detector_init = False
|
|
410
|
+
|
|
411
|
+
except Exception as e:
|
|
412
|
+
self.logger.exception(str(e))
|
|
413
|
+
else:
|
|
414
|
+
try:
|
|
415
|
+
|
|
416
|
+
hardware = DAQ_Detector(self._title, self.settings, self.detector)
|
|
417
|
+
self._hardware_thread = QThread()
|
|
418
|
+
if config('viewer', 'viewer_in_thread'):
|
|
419
|
+
hardware.moveToThread(self._hardware_thread)
|
|
420
|
+
|
|
421
|
+
self.command_hardware[ThreadCommand].connect(hardware.queue_command)
|
|
422
|
+
hardware.data_detector_sig[list].connect(self.show_data)
|
|
423
|
+
hardware.data_detector_temp_sig[list].connect(self.show_temp_data)
|
|
424
|
+
hardware.status_sig[ThreadCommand].connect(self.thread_status)
|
|
425
|
+
self._update_settings_signal[edict].connect(hardware.update_settings)
|
|
426
|
+
|
|
427
|
+
self._hardware_thread.hardware = hardware
|
|
428
|
+
if config('viewer', 'viewer_in_thread'):
|
|
429
|
+
self._hardware_thread.start()
|
|
430
|
+
self.command_hardware.emit(ThreadCommand("ini_detector", attribute=[
|
|
431
|
+
self.settings.child('detector_settings').saveState(), self.controller]))
|
|
432
|
+
if self.ui is not None:
|
|
433
|
+
for dock in self.ui.viewer_docks:
|
|
434
|
+
dock.setEnabled(True)
|
|
435
|
+
|
|
436
|
+
except Exception as e:
|
|
437
|
+
self.logger.exception(str(e))
|
|
438
|
+
|
|
439
|
+
def snap(self):
|
|
440
|
+
"""Programmatic click on the UI snap button"""
|
|
441
|
+
self.grab_data(False, snap_state=True)
|
|
442
|
+
|
|
443
|
+
def grab(self):
|
|
444
|
+
"""Programmatic click on the UI grab button"""
|
|
445
|
+
if self.ui is not None:
|
|
446
|
+
self.manage_ui_actions('grab', 'setChecked', not self._grabing)
|
|
447
|
+
self.grab_data(not self._grabing, snap_state=False)
|
|
448
|
+
|
|
449
|
+
def snapshot(self, pathname=None, dosave=False, send_to_tcpip=False):
|
|
450
|
+
"""Do one single grab (snap) and eventually save the data.
|
|
451
|
+
|
|
452
|
+
Parameters
|
|
453
|
+
----------
|
|
454
|
+
pathname: str or Path object
|
|
455
|
+
The path where to save data
|
|
456
|
+
dosave: bool
|
|
457
|
+
Do save or just grab data
|
|
458
|
+
send_to_tcpip: bool
|
|
459
|
+
If True, send the grabed data through the TCP/IP pipe
|
|
460
|
+
"""
|
|
461
|
+
try:
|
|
462
|
+
self._do_save_data = dosave
|
|
463
|
+
if pathname is None:
|
|
464
|
+
raise (ValueError("filepathanme has not been defined in snapshot"))
|
|
465
|
+
|
|
466
|
+
self._save_file_pathname = pathname
|
|
467
|
+
self.grab_data(grab_state=False, send_to_tcpip=send_to_tcpip, snap_state=True)
|
|
468
|
+
except Exception as e:
|
|
469
|
+
self.logger.exception(str(e))
|
|
470
|
+
|
|
471
|
+
def grab_data(self, grab_state=False, send_to_tcpip=False, snap_state=False):
|
|
472
|
+
"""Generic method to grab or snap data from the selected (and initialized) detector
|
|
473
|
+
|
|
474
|
+
Parameters
|
|
475
|
+
----------
|
|
476
|
+
grab_state: bool
|
|
477
|
+
Defines the grab status: if True: do live grabing if False stops the grab
|
|
478
|
+
send_to_tcpip: bool
|
|
479
|
+
If True, send the grabed data through the TCP/IP pipe
|
|
480
|
+
snap_state: bool
|
|
481
|
+
if True performs a single grab
|
|
482
|
+
"""
|
|
483
|
+
self._grabing = grab_state
|
|
484
|
+
self._send_to_tcpip = send_to_tcpip
|
|
485
|
+
self._grab_done = False
|
|
486
|
+
|
|
487
|
+
if self.ui is not None:
|
|
488
|
+
self.ui.data_ready = False
|
|
489
|
+
|
|
490
|
+
self._start_grab_time = time.perf_counter()
|
|
491
|
+
if snap_state:
|
|
492
|
+
self.update_status(f'{self._title}: Snap')
|
|
493
|
+
self.command_hardware.emit(
|
|
494
|
+
ThreadCommand("single", [self.settings.child('main_settings', 'Naverage').value()]))
|
|
495
|
+
else:
|
|
496
|
+
if not grab_state:
|
|
497
|
+
self.update_status(f'{self._title}: Stop Grab')
|
|
498
|
+
self.command_hardware.emit(ThreadCommand("stop_grab", ))
|
|
499
|
+
else:
|
|
500
|
+
self.thread_status(ThreadCommand("update_channels", ))
|
|
501
|
+
self.update_status(f'{self._title}: Continuous Grab')
|
|
502
|
+
self.command_hardware.emit(
|
|
503
|
+
ThreadCommand("grab", [self.settings.child('main_settings', 'Naverage').value()]))
|
|
504
|
+
|
|
505
|
+
def take_bkg(self):
|
|
506
|
+
"""Do a snap and store data to be used as background into an attribute: `self._bkg`
|
|
507
|
+
|
|
508
|
+
The content of the bkg will be saved if data is further saved with do_bkg property set to True
|
|
509
|
+
"""
|
|
510
|
+
self._take_bkg = True
|
|
511
|
+
self.grab_data(snap_state=True)
|
|
512
|
+
|
|
513
|
+
def stop_grab(self):
|
|
514
|
+
if self.ui is not None:
|
|
515
|
+
self.manage_ui_actions('grab', 'setChecked', False)
|
|
516
|
+
self.stop()
|
|
517
|
+
|
|
518
|
+
def stop(self):
|
|
519
|
+
self.update_status(f'{self._title}: Stop Grab')
|
|
520
|
+
self.command_hardware.emit(ThreadCommand("stop_all", ))
|
|
521
|
+
self._grabing = False
|
|
522
|
+
|
|
523
|
+
@Slot()
|
|
524
|
+
def _raise_timeout(self):
|
|
525
|
+
""" Print the "timeout occurred" error message in the status bar via the update_status method.
|
|
526
|
+
"""
|
|
527
|
+
self.update_status("Timeout occured", log_type="log")
|
|
528
|
+
|
|
529
|
+
@staticmethod
|
|
530
|
+
def load_data():
|
|
531
|
+
"""Opens a H5 file in the H5Browser module
|
|
532
|
+
|
|
533
|
+
Convenience static method.
|
|
534
|
+
"""
|
|
535
|
+
browse_data()
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def save_current(self):
|
|
539
|
+
"""Save current data into a h5file"""
|
|
540
|
+
self._do_save_data = True
|
|
541
|
+
self._save_file_pathname = select_file(start_path=self._save_file_pathname, save=True,
|
|
542
|
+
ext='h5') # see daq_utils
|
|
543
|
+
self._save_export_data(self._data_to_save_export)
|
|
544
|
+
|
|
545
|
+
def save_new(self):
|
|
546
|
+
"""Snap data and save them into a h5file"""
|
|
547
|
+
self._do_save_data = True
|
|
548
|
+
self._save_file_pathname = select_file(start_path=self._save_file_pathname, save=True,
|
|
549
|
+
ext='h5') # see daq_utils
|
|
550
|
+
self.snapshot(pathname=self._save_file_pathname, dosave=True)
|
|
551
|
+
|
|
552
|
+
def _init_continuous_save(self):
|
|
553
|
+
if self._h5saver_continuous.settings.child('do_save').value():
|
|
554
|
+
|
|
555
|
+
self._h5saver_continuous.settings.child('base_name').setValue('Data')
|
|
556
|
+
self._h5saver_continuous.settings.child('N_saved').show()
|
|
557
|
+
self._h5saver_continuous.settings.child('N_saved').setValue(0)
|
|
558
|
+
self.module_and_data_saver.h5saver = self._h5saver_continuous
|
|
559
|
+
self._h5saver_continuous.init_file(update_h5=True)
|
|
560
|
+
|
|
561
|
+
self.module_and_data_saver = module_saving.DetectorEnlargeableSaver(self)
|
|
562
|
+
self.module_and_data_saver.h5saver = self._h5saver_continuous
|
|
563
|
+
self.module_and_data_saver.get_set_node()
|
|
564
|
+
|
|
565
|
+
self.grab_done_signal.connect(self.append_data)
|
|
566
|
+
else:
|
|
567
|
+
self._do_continuous_save = False
|
|
568
|
+
self._h5saver_continuous.settings.child('N_saved').hide()
|
|
569
|
+
self.grab_done_signal.disconnect(self.append_data)
|
|
570
|
+
|
|
571
|
+
try:
|
|
572
|
+
self._h5saver_continuous.close()
|
|
573
|
+
except Exception as e:
|
|
574
|
+
self.logger.exception(str(e))
|
|
575
|
+
|
|
576
|
+
def append_data(self, where=None):
|
|
577
|
+
"""Appends DataToExport to a DetectorEnlargeableSaver
|
|
578
|
+
|
|
579
|
+
Parameters
|
|
580
|
+
----------
|
|
581
|
+
data: DataToExport
|
|
582
|
+
The data to be added to an enlargeable h5 array
|
|
583
|
+
|
|
584
|
+
See Also
|
|
585
|
+
--------
|
|
586
|
+
DetectorEnlargeableSaver
|
|
587
|
+
"""
|
|
588
|
+
self._add_data_to_saver(self._data_to_save_export, init_step=self._h5saver_continuous.settings['N_saved'] == 0,
|
|
589
|
+
where=None)
|
|
590
|
+
self._h5saver_continuous.settings.child('N_saved').setValue(self._h5saver_continuous.settings['N_saved'] + 1)
|
|
591
|
+
|
|
592
|
+
def insert_data(self, indexes: Tuple[int], where=None, distribution=DataDistribution['uniform']):
|
|
593
|
+
"""Insert DataToExport to a DetectorExtendedSaver at specified indexes
|
|
594
|
+
|
|
595
|
+
Parameters
|
|
596
|
+
----------
|
|
597
|
+
indexes: tuple(int)
|
|
598
|
+
The indexes within the extended array where to place these data
|
|
599
|
+
where: Node or str
|
|
600
|
+
distribution: DataDistribution enum
|
|
601
|
+
save_raw_only: bool
|
|
602
|
+
If True save only Raw data (no data processed from Roi)
|
|
603
|
+
|
|
604
|
+
See Also
|
|
605
|
+
--------
|
|
606
|
+
DAQ_Scan, DetectorExtendedSaver
|
|
607
|
+
"""
|
|
608
|
+
self._add_data_to_saver(self._data_to_save_export, init_step=np.all(np.array(indexes) == 0), where=where,
|
|
609
|
+
indexes=indexes, distribution=distribution)
|
|
610
|
+
|
|
611
|
+
def _add_data_to_saver(self, data: DataToExport, init_step=False, where=None, **kwargs):
|
|
612
|
+
"""Adds DataToExport data to the current node using the declared module_and_data_saver
|
|
613
|
+
|
|
614
|
+
Filters the data to be saved by DataSource as specified in the current H5Saver (see self.module_and_data_saver)
|
|
615
|
+
|
|
616
|
+
Parameters
|
|
617
|
+
----------
|
|
618
|
+
data: DataToExport
|
|
619
|
+
The data to be saved
|
|
620
|
+
init_step: bool
|
|
621
|
+
If True, means this is the first step of saving (if multisaving), then save background if any and a png image
|
|
622
|
+
kwargs: dict
|
|
623
|
+
Other named parameters to be passed as is to the module_and_data_saver
|
|
624
|
+
|
|
625
|
+
See Also
|
|
626
|
+
--------
|
|
627
|
+
DetectorSaver, DetectorEnlargeableSaver, DetectorExtendedSaver
|
|
628
|
+
|
|
629
|
+
"""
|
|
630
|
+
detector_node = self.module_and_data_saver.get_set_node(where)
|
|
631
|
+
data = data if not self.module_and_data_saver.h5saver.settings['save_raw_only'] else\
|
|
632
|
+
self._data_to_save_export.get_data_from_source('raw')
|
|
633
|
+
|
|
634
|
+
self.module_and_data_saver.add_data(detector_node, data, **kwargs)
|
|
635
|
+
|
|
636
|
+
if init_step:
|
|
637
|
+
if self._do_bkg and self._bkg is not None:
|
|
638
|
+
self.module_and_data_saver.add_bkg(detector_node, self._bkg)
|
|
639
|
+
|
|
640
|
+
if self._external_h5_data is not None:
|
|
641
|
+
# todo test this functionnality
|
|
642
|
+
self.module_and_data_saver.add_external_h5(self._external_h5_data)
|
|
643
|
+
|
|
644
|
+
def _save_data(self, path=None, data: DataToExport = None):
|
|
645
|
+
"""Private. Practical implementation to save data into a h5file altogether with metadata, axes, background...
|
|
646
|
+
|
|
647
|
+
Parameters
|
|
648
|
+
----------
|
|
649
|
+
path: Path
|
|
650
|
+
where to save the data as returned from browse_file for instance
|
|
651
|
+
data: DataToExport
|
|
652
|
+
|
|
653
|
+
See Also
|
|
654
|
+
--------
|
|
655
|
+
browse_file, _get_data_from_viewers
|
|
656
|
+
"""
|
|
657
|
+
if path is not None:
|
|
658
|
+
path = Path(path)
|
|
659
|
+
h5saver = H5Saver(save_type='detector')
|
|
660
|
+
h5saver.init_file(update_h5=True, custom_naming=False, addhoc_file_path=path)
|
|
661
|
+
self.module_and_data_saver = module_saving.DetectorSaver(self)
|
|
662
|
+
self.module_and_data_saver.h5saver = h5saver
|
|
663
|
+
|
|
664
|
+
self._add_data_to_saver(data)
|
|
665
|
+
|
|
666
|
+
if self.ui is not None:
|
|
667
|
+
(root, filename) = os.path.split(str(path))
|
|
668
|
+
filename, ext = os.path.splitext(filename)
|
|
669
|
+
image_path = os.path.join(root, filename + '.png')
|
|
670
|
+
self.dockarea.parent().grab().save(image_path)
|
|
671
|
+
|
|
672
|
+
h5saver.close_file()
|
|
673
|
+
self.data_saved.emit()
|
|
674
|
+
|
|
675
|
+
@Slot(OrderedDict)
|
|
676
|
+
def _save_export_data(self, data: DataToExport):
|
|
677
|
+
"""Auxiliary method (Slot) to receive all data (raw and processed from rois) and save them
|
|
678
|
+
|
|
679
|
+
Parameters
|
|
680
|
+
----------
|
|
681
|
+
data: DataToExport
|
|
682
|
+
contains a timestamp and data (raw and extracted from roi in dataviewers) on the dorm:
|
|
683
|
+
`_data_to_save_export = OrderedDict(Ndatas=Ndatas, acq_time_s=acq_time, name=name,
|
|
684
|
+
control_module='DAQ_Viewer')`
|
|
685
|
+
with extra keys for data dimensionality such as Data0D=OrderedDict(...)
|
|
686
|
+
|
|
687
|
+
See Also
|
|
688
|
+
--------
|
|
689
|
+
_save_data
|
|
690
|
+
"""
|
|
691
|
+
|
|
692
|
+
if self._do_save_data:
|
|
693
|
+
self._save_data(self._save_file_pathname, data)
|
|
694
|
+
self._do_save_data = False
|
|
695
|
+
|
|
696
|
+
def _get_data_from_viewer(self, data: DataToExport):
|
|
697
|
+
"""Get all data emitted by the current viewers
|
|
698
|
+
|
|
699
|
+
Each viewer *data_to_export_signal* is connected to this slot. The collected data is stored in another
|
|
700
|
+
DataToExport `self._data_to_save_export` for further processing. All raw data are also stored in this attribute.
|
|
701
|
+
When all viewers have emitted this signal, the collected data are emitted with the
|
|
702
|
+
`grab_done_signal` signal.
|
|
703
|
+
|
|
704
|
+
Parameters
|
|
705
|
+
---------_
|
|
706
|
+
data: DataToExport
|
|
707
|
+
All data collected from the viewers
|
|
708
|
+
|
|
709
|
+
"""
|
|
710
|
+
if self._data_to_save_export is not None: # means that somehow data are not initialized so no further procsessing
|
|
711
|
+
self._received_data += 1
|
|
712
|
+
if len(data) != 0:
|
|
713
|
+
for dat in data:
|
|
714
|
+
dat.origin = self.title
|
|
715
|
+
self._data_to_save_export.append(data)
|
|
716
|
+
|
|
717
|
+
if self._received_data == len(self.viewers):
|
|
718
|
+
self._grab_done = True
|
|
719
|
+
self.grab_done_signal.emit(self._data_to_save_export)
|
|
720
|
+
|
|
721
|
+
@property
|
|
722
|
+
def current_data(self) -> DataToExport:
|
|
723
|
+
return self._data_to_save_export
|
|
724
|
+
|
|
725
|
+
@Slot(list)
|
|
726
|
+
def show_temp_data(self, data: List[DataFromPlugins]):
|
|
727
|
+
"""Send data to their dedicated viewers but those will not emit processed data signal
|
|
728
|
+
|
|
729
|
+
Slot receiving data from plugins emitted with the `data_grabed_signal_temp`
|
|
730
|
+
|
|
731
|
+
Parameters
|
|
732
|
+
----------
|
|
733
|
+
data: list of DataFromPlugins
|
|
734
|
+
"""
|
|
735
|
+
self._init_show_data(data)
|
|
736
|
+
if self.ui is not None:
|
|
737
|
+
self.set_data_to_viewers(data, temp=True)
|
|
738
|
+
|
|
739
|
+
@Slot(list)
|
|
740
|
+
def show_data(self, data: List[DataFromPlugins]):
|
|
741
|
+
"""Send data to their dedicated viewers but those will not emit processed data signal
|
|
742
|
+
|
|
743
|
+
Slot receiving data from plugins emitted with the `data_grabed_signal`
|
|
744
|
+
Process the data as specified in the settings, display them into the dedicated data viewers depending on the
|
|
745
|
+
settings:
|
|
746
|
+
* create a container (OrderedDict `_data_to_save_export`) with info from this DAQ_Viewer (title), a timestamp...
|
|
747
|
+
* call `_process_data`
|
|
748
|
+
* do background subtraction if any
|
|
749
|
+
* check refresh time (if set in the settings) to send or not data to data viewers
|
|
750
|
+
* either send to the data viewers (if refresh time is ok and/or show data option in settings is set)
|
|
751
|
+
* either
|
|
752
|
+
* send grab_done_signal (to the slot _save_export_data ) to save the data
|
|
753
|
+
|
|
754
|
+
Parameters
|
|
755
|
+
----------
|
|
756
|
+
data: list of DataFromPlugins
|
|
757
|
+
|
|
758
|
+
See Also
|
|
759
|
+
--------
|
|
760
|
+
_init_show_data, _process_data
|
|
761
|
+
"""
|
|
762
|
+
try:
|
|
763
|
+
if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value() and self._send_to_tcpip:
|
|
764
|
+
self._command_tcpip.emit(ThreadCommand('data_ready', data))
|
|
765
|
+
if self.ui is not None:
|
|
766
|
+
self.ui.data_ready = True
|
|
767
|
+
self._init_show_data(data)
|
|
768
|
+
|
|
769
|
+
# store raw data for further processing
|
|
770
|
+
self._data_to_save_export = DataToExport(self._title, control_module='DAQ_Viewer', data=data)
|
|
771
|
+
|
|
772
|
+
if self.settings['main_settings', 'live_averaging']:
|
|
773
|
+
self.settings.child('main_settings', 'N_live_averaging').setValue(self._ind_continuous_grab)
|
|
774
|
+
self._current_data = copy.deepcopy(self._data_to_save_export)
|
|
775
|
+
|
|
776
|
+
self._ind_continuous_grab += 1
|
|
777
|
+
if self._ind_continuous_grab > 1:
|
|
778
|
+
self._data_to_save_export = \
|
|
779
|
+
self._data_to_save_export.average(self._current_data, self._ind_continuous_grab)
|
|
780
|
+
|
|
781
|
+
if self._take_bkg:
|
|
782
|
+
self._bkg = copy.deepcopy(self._data_to_save_export)
|
|
783
|
+
self._take_bkg = False
|
|
784
|
+
|
|
785
|
+
if self._grabing: # if live
|
|
786
|
+
refresh_time = self.settings['main_settings', 'refresh_time']
|
|
787
|
+
refresh = time.perf_counter() - self._start_grab_time > refresh_time / 1000
|
|
788
|
+
if refresh:
|
|
789
|
+
self._start_grab_time = time.perf_counter()
|
|
790
|
+
else:
|
|
791
|
+
refresh = True # if single
|
|
792
|
+
if self.ui is not None and self.settings.child('main_settings', 'show_data').value() and refresh:
|
|
793
|
+
self._received_data = 0 # so that data send back from viewers can be properly counted
|
|
794
|
+
data_to_plot = copy.deepcopy(self._data_to_save_export)
|
|
795
|
+
# process bkg if needed
|
|
796
|
+
if self.do_bkg and self._bkg is not None:
|
|
797
|
+
data_to_plot -= self._bkg
|
|
798
|
+
self.set_data_to_viewers(data_to_plot.data)
|
|
799
|
+
else:
|
|
800
|
+
self._grab_done = True
|
|
801
|
+
self.grab_done_signal.emit(self._data_to_save_export)
|
|
802
|
+
|
|
803
|
+
except Exception as e:
|
|
804
|
+
self.logger.exception(str(e))
|
|
805
|
+
|
|
806
|
+
def _init_show_data(self, data):
|
|
807
|
+
"""Processing before showing data
|
|
808
|
+
|
|
809
|
+
* process the data to check if they overshoot
|
|
810
|
+
* check the data dimensionality to update the dedicated viewers
|
|
811
|
+
|
|
812
|
+
Parameters
|
|
813
|
+
----------
|
|
814
|
+
data: list of DataFromPlugins
|
|
815
|
+
|
|
816
|
+
See Also
|
|
817
|
+
--------
|
|
818
|
+
_process_overshoot
|
|
819
|
+
"""
|
|
820
|
+
self._process_overshoot(data)
|
|
821
|
+
self._viewer_types = [ViewersEnum(data.dim.name) for data in data]
|
|
822
|
+
if self.ui is not None:
|
|
823
|
+
if self.ui.viewer_types != self._viewer_types:
|
|
824
|
+
self.ui.update_viewers(self._viewer_types)
|
|
825
|
+
|
|
826
|
+
def set_data_to_viewers(self, data, temp=False):
|
|
827
|
+
"""Process data dimensionality and send appropriate data to their data viewers
|
|
828
|
+
|
|
829
|
+
Parameters
|
|
830
|
+
----------
|
|
831
|
+
data: list of DataFromPlugins
|
|
832
|
+
temp: bool
|
|
833
|
+
if True notify the data viewers to display data as temporary (meaning not exporting processed data from roi)
|
|
834
|
+
|
|
835
|
+
See Also
|
|
836
|
+
--------
|
|
837
|
+
ViewerBase, Viewer0D, Viewer1D, Viewer2D
|
|
838
|
+
"""
|
|
839
|
+
for ind, data in enumerate(data):
|
|
840
|
+
self.viewers[ind].title = data.name
|
|
841
|
+
self.viewer_docks[ind].setTitle(self._title + ' ' + data.name)
|
|
842
|
+
|
|
843
|
+
if temp:
|
|
844
|
+
self.viewers[ind].show_data_temp(data)
|
|
845
|
+
else:
|
|
846
|
+
self.viewers[ind].show_data(data)
|
|
847
|
+
|
|
848
|
+
def value_changed(self, param):
|
|
849
|
+
"""ParameterManager subclassed method. Process events from value changed by user in the UI Settings
|
|
850
|
+
|
|
851
|
+
Parameters
|
|
852
|
+
----------
|
|
853
|
+
param: Parameter
|
|
854
|
+
a given parameter whose value has been changed by user
|
|
855
|
+
"""
|
|
856
|
+
path = self.settings.childPath(param)
|
|
857
|
+
if param.name() == 'DAQ_type':
|
|
858
|
+
self._h5saver_continuous.settings.child('do_save').setValue(False)
|
|
859
|
+
self.settings.child('main_settings', 'axes').show(param.value() == 'DAQ2D')
|
|
860
|
+
|
|
861
|
+
elif param.name() == 'show_averaging':
|
|
862
|
+
self.settings.child('main_settings', 'live_averaging').setValue(False)
|
|
863
|
+
self._update_settings_signal.emit(edict(path=path, param=param, change='value'))
|
|
864
|
+
|
|
865
|
+
elif param.name() == 'live_averaging':
|
|
866
|
+
self.settings.child('main_settings', 'show_averaging').setValue(False)
|
|
867
|
+
if param.value():
|
|
868
|
+
self.settings.child('main_settings', 'N_live_averaging').show()
|
|
869
|
+
self._ind_continuous_grab = 0
|
|
870
|
+
self.settings.child('main_settings', 'N_live_averaging').setValue(0)
|
|
871
|
+
else:
|
|
872
|
+
self.settings.child('main_settings', 'N_live_averaging').hide()
|
|
873
|
+
|
|
874
|
+
elif param.name() in putils.iter_children(self.settings.child('main_settings', 'axes'), []):
|
|
875
|
+
if self.daq_type.name == "DAQ2D":
|
|
876
|
+
if param.name() == 'use_calib':
|
|
877
|
+
if param.value() != 'None':
|
|
878
|
+
params = ioxml.XML_file_to_parameter(
|
|
879
|
+
os.path.join(local_path, 'camera_calibrations', param.value() + '.xml'))
|
|
880
|
+
param_obj = Parameter.create(name='calib', type='group', children=params)
|
|
881
|
+
self.settings.child('main_settings', 'axes').restoreState(
|
|
882
|
+
param_obj.child('axes').saveState(), addChildren=False, removeChildren=False)
|
|
883
|
+
self.settings.child('main_settings', 'axes').show()
|
|
884
|
+
else:
|
|
885
|
+
for viewer in self.viewers:
|
|
886
|
+
viewer.x_axis, viewer.y_axis = self.get_scaling_options()
|
|
887
|
+
|
|
888
|
+
elif param.name() == 'continuous_saving_opt':
|
|
889
|
+
self._h5saver_continuous.show_settings(param.value())
|
|
890
|
+
|
|
891
|
+
elif param.name() == 'wait_time':
|
|
892
|
+
self.command_hardware.emit(ThreadCommand('update_wait_time', [param.value()]))
|
|
893
|
+
|
|
894
|
+
elif param.name() == 'connect_server':
|
|
895
|
+
if param.value():
|
|
896
|
+
self.connect_tcp_ip()
|
|
897
|
+
else:
|
|
898
|
+
self._command_tcpip.emit(ThreadCommand('quit', ))
|
|
899
|
+
|
|
900
|
+
elif param.name() == 'ip_address' or param.name == 'port':
|
|
901
|
+
self._command_tcpip.emit(
|
|
902
|
+
ThreadCommand('update_connection', dict(ipaddress=self.settings.child('main_settings', 'tcpip',
|
|
903
|
+
'ip_address').value(),
|
|
904
|
+
port=self.settings.child('main_settings', 'tcpip',
|
|
905
|
+
'port').value())))
|
|
906
|
+
|
|
907
|
+
if path is not None:
|
|
908
|
+
if 'main_settings' not in path:
|
|
909
|
+
self._update_settings_signal.emit(edict(path=path, param=param, change='value'))
|
|
910
|
+
|
|
911
|
+
if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
|
|
912
|
+
self._command_tcpip.emit(ThreadCommand('send_info', dict(path=path, param=param)))
|
|
913
|
+
|
|
914
|
+
def child_added(self, param, data):
|
|
915
|
+
"""Non-mandatory method to be subclassed for actions to perform when a param has been added in self.settings
|
|
916
|
+
|
|
917
|
+
Parameters
|
|
918
|
+
----------
|
|
919
|
+
param: Parameter
|
|
920
|
+
the parameter where child will be added
|
|
921
|
+
data: Parameter
|
|
922
|
+
the child parameter
|
|
923
|
+
"""
|
|
924
|
+
if param.name() not in putils.iter_children(self.settings.child('main_settings'), []):
|
|
925
|
+
self._update_settings_signal.emit(edict(path=putils.get_param_path(param)[1:], param=data[0], change='childAdded'))
|
|
926
|
+
|
|
927
|
+
def param_deleted(self, param):
|
|
928
|
+
"""ParameterManager subclassed method. Process events from parameter deleted by user in the UI Settings
|
|
929
|
+
|
|
930
|
+
Parameters
|
|
931
|
+
----------
|
|
932
|
+
param: Parameter
|
|
933
|
+
a given parameter whose value has been changed by user
|
|
934
|
+
"""
|
|
935
|
+
if param.name() not in putils.iter_children(self.settings.child('main_settings'), []):
|
|
936
|
+
self._update_settings_signal.emit(edict(path=['detector_settings'], param=param, change='parent'))
|
|
937
|
+
|
|
938
|
+
def _set_setting_tree(self):
|
|
939
|
+
"""Apply the specific settings of the selected detector (plugin)
|
|
940
|
+
|
|
941
|
+
Remove previous ones and load on the fly the new ones
|
|
942
|
+
|
|
943
|
+
See Also
|
|
944
|
+
--------
|
|
945
|
+
pymodaq.control_modules.utils:get_viewer_plugins
|
|
946
|
+
"""
|
|
947
|
+
|
|
948
|
+
try:
|
|
949
|
+
if len(self.settings.child('detector_settings').children()) > 0:
|
|
950
|
+
for child in self.settings.child('detector_settings').children():
|
|
951
|
+
child.remove()
|
|
952
|
+
|
|
953
|
+
det_params, _class = get_viewer_plugins(self.daq_type.name, self.detector)
|
|
954
|
+
self.settings.child('detector_settings').addChildren(det_params.children())
|
|
955
|
+
except Exception as e:
|
|
956
|
+
self.logger.exception(str(e))
|
|
957
|
+
|
|
958
|
+
def _process_overshoot(self, data):
|
|
959
|
+
"""Compare data value (0D) to the given overshoot setting
|
|
960
|
+
"""
|
|
961
|
+
if self.settings.child('main_settings', 'overshoot', 'stop_overshoot').value():
|
|
962
|
+
for channels in data:
|
|
963
|
+
for channel in channels['data']:
|
|
964
|
+
if any(channel >= self.settings.child('main_settings', 'overshoot', 'overshoot_value').value()):
|
|
965
|
+
self.overshoot_signal.emit(True)
|
|
966
|
+
|
|
967
|
+
def get_scaling_options(self):
|
|
968
|
+
"""Create axes scaling options depending on the ('main_settings', 'axes') settings
|
|
969
|
+
|
|
970
|
+
Returns
|
|
971
|
+
-------
|
|
972
|
+
pymodaq.utils.data.ScalingOptions
|
|
973
|
+
"""
|
|
974
|
+
scaled_xaxis = Axis(label=self.settings['main_settings', 'axes', 'xaxis', 'xlabel'],
|
|
975
|
+
units=self.settings['main_settings', 'axes', 'xaxis', 'xunits'],
|
|
976
|
+
offset=self.settings['main_settings', 'axes', 'xaxis', 'xoffset'],
|
|
977
|
+
scaling=self.settings['main_settings', 'axes', 'xaxis', 'xscaling'])
|
|
978
|
+
scaled_yaxis = Axis(label=self.settings['main_settings', 'axes', 'yaxis', 'ylabel'],
|
|
979
|
+
units=self.settings['main_settings', 'axes', 'yaxis', 'yunits'],
|
|
980
|
+
offset=self.settings['main_settings', 'axes', 'yaxis', 'yoffset'],
|
|
981
|
+
scaling=self.settings['main_settings', 'axes', 'yaxis', 'yscaling'])
|
|
982
|
+
return scaled_xaxis, scaled_yaxis
|
|
983
|
+
|
|
984
|
+
@Slot(ThreadCommand)
|
|
985
|
+
def thread_status(self, status):
|
|
986
|
+
"""Get back info (using the ThreadCommand object) from the hardware
|
|
987
|
+
|
|
988
|
+
And re-emit this ThreadCommand using the custom_sig signal if it should be used in a higher level module
|
|
989
|
+
|
|
990
|
+
Parameters
|
|
991
|
+
----------
|
|
992
|
+
status: ThreadCommand
|
|
993
|
+
The info returned from the hardware, the command (str) can be either:
|
|
994
|
+
* Update_Status: display messages and log info
|
|
995
|
+
* ini_detector: update the status with "detector initialized" value and init state if attribute not null.
|
|
996
|
+
* close: close the current thread and delete corresponding attribute on cascade.
|
|
997
|
+
* grab : emit grab_status(True)
|
|
998
|
+
* grab_stopped: emit grab_status(False)
|
|
999
|
+
* x_axis: update x_axis from status attribute and User Interface viewer consequently. (Deprecated)
|
|
1000
|
+
* y_axis: update y_axis from status attribute and User Interface viewer consequently. (Deprecated)
|
|
1001
|
+
* update_channel: update the viewer channels in case of 0D DAQ_type (deprecated)
|
|
1002
|
+
* update_settings: Update the "detector setting" node in the settings tree.
|
|
1003
|
+
* update_main_settings: update the "main setting" node in the settings tree
|
|
1004
|
+
* raise_timeout:
|
|
1005
|
+
* show_splash: Display the splash screen with attribute as message
|
|
1006
|
+
* close_splash
|
|
1007
|
+
* init_lcd: display a LCD panel
|
|
1008
|
+
* lcd: display on the LCD panel, the content of the attribute
|
|
1009
|
+
* stop: stop the grab
|
|
1010
|
+
"""
|
|
1011
|
+
if status.command == "Update_Status":
|
|
1012
|
+
if len(status.attribute) > 1:
|
|
1013
|
+
self.update_status(status.attribute[0], log=status.attribute[1])
|
|
1014
|
+
else:
|
|
1015
|
+
self.update_status(status.attribute[0])
|
|
1016
|
+
|
|
1017
|
+
elif status.command == "ini_detector":
|
|
1018
|
+
self.update_status("detector initialized: " + str(status.attribute[0]['initialized']))
|
|
1019
|
+
if self.ui is not None:
|
|
1020
|
+
self.ui.detector_init = status.attribute[0]['initialized']
|
|
1021
|
+
if status.attribute[0]['initialized']:
|
|
1022
|
+
self.controller = status.attribute[0]['controller']
|
|
1023
|
+
self._initialized_state = True
|
|
1024
|
+
else:
|
|
1025
|
+
self._initialized_state = False
|
|
1026
|
+
|
|
1027
|
+
self.init_signal.emit(self._initialized_state)
|
|
1028
|
+
|
|
1029
|
+
elif status.command == "close":
|
|
1030
|
+
try:
|
|
1031
|
+
self.update_status(status.attribute[0])
|
|
1032
|
+
self._hardware_thread.quit()
|
|
1033
|
+
self._hardware_thread.wait()
|
|
1034
|
+
finished = self._hardware_thread.isFinished()
|
|
1035
|
+
if finished:
|
|
1036
|
+
pass
|
|
1037
|
+
else:
|
|
1038
|
+
print('Thread still running')
|
|
1039
|
+
self._hardware_thread.terminate()
|
|
1040
|
+
self.update_status('thread is locked?!', 'log')
|
|
1041
|
+
except Exception as e:
|
|
1042
|
+
self.logger.exception(str(e))
|
|
1043
|
+
|
|
1044
|
+
self._initialized_state = False
|
|
1045
|
+
self.init_signal.emit(self._initialized_state)
|
|
1046
|
+
|
|
1047
|
+
elif status.command == "grab":
|
|
1048
|
+
self.grab_status.emit(True)
|
|
1049
|
+
|
|
1050
|
+
elif status.command == 'grab_stopped':
|
|
1051
|
+
self.grab_status.emit(False)
|
|
1052
|
+
|
|
1053
|
+
elif status.command == "x_axis":
|
|
1054
|
+
deprecation_msg(f'using emit_x_axis in plugins is deprecated use data emission with correct axis to set it.'
|
|
1055
|
+
f'To send it only once, use the data_grabed_signal_temp')
|
|
1056
|
+
|
|
1057
|
+
elif status.command == "y_axis":
|
|
1058
|
+
deprecation_msg(f'using emit_y_axis in plugins is deprecated use data emission with correct axis to set it.'
|
|
1059
|
+
f'To send it only once, use the data_grabed_signal_temp')
|
|
1060
|
+
|
|
1061
|
+
elif status.command == "update_channels":
|
|
1062
|
+
pass
|
|
1063
|
+
|
|
1064
|
+
elif status.command == 'update_main_settings':
|
|
1065
|
+
# this is a way for the plugins to update main settings of the ui (solely values, limits and options)
|
|
1066
|
+
try:
|
|
1067
|
+
if status.attribute[2] == 'value':
|
|
1068
|
+
self.settings.child('main_settings', *status.attribute[0]).setValue(status.attribute[1])
|
|
1069
|
+
elif status.attribute[2] == 'limits':
|
|
1070
|
+
self.settings.child('main_settings', *status.attribute[0]).setLimits(status.attribute[1])
|
|
1071
|
+
elif status.attribute[2] == 'options':
|
|
1072
|
+
self.settings.child('main_settings', *status.attribute[0]).setOpts(**status.attribute[1])
|
|
1073
|
+
except Exception as e:
|
|
1074
|
+
self.logger.exception(str(e))
|
|
1075
|
+
|
|
1076
|
+
elif status.command == 'update_settings':
|
|
1077
|
+
# using this the settings shown in the UI for the plugin reflects the real plugin settings
|
|
1078
|
+
try:
|
|
1079
|
+
self.settings.sigTreeStateChanged.disconnect(
|
|
1080
|
+
self.parameter_tree_changed) # any changes on the detcetor settings will update accordingly the gui
|
|
1081
|
+
except Exception as e:
|
|
1082
|
+
self.logger.exception(str(e))
|
|
1083
|
+
try:
|
|
1084
|
+
if status.attribute[2] == 'value':
|
|
1085
|
+
self.settings.child('detector_settings', *status.attribute[0]).setValue(status.attribute[1])
|
|
1086
|
+
elif status.attribute[2] == 'limits':
|
|
1087
|
+
self.settings.child('detector_settings', *status.attribute[0]).setLimits(status.attribute[1])
|
|
1088
|
+
elif status.attribute[2] == 'options':
|
|
1089
|
+
self.settings.child('detector_settings', *status.attribute[0]).setOpts(**status.attribute[1])
|
|
1090
|
+
elif status.attribute[2] == 'childAdded':
|
|
1091
|
+
child = Parameter.create(name='tmp')
|
|
1092
|
+
child.restoreState(status.attribute[1][0])
|
|
1093
|
+
self.settings.child('detector_settings', *status.attribute[0]).addChild(status.attribute[1][0])
|
|
1094
|
+
|
|
1095
|
+
except Exception as e:
|
|
1096
|
+
self.logger.exception(str(e))
|
|
1097
|
+
self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)
|
|
1098
|
+
|
|
1099
|
+
elif status.command == 'raise_timeout':
|
|
1100
|
+
self._raise_timeout()
|
|
1101
|
+
|
|
1102
|
+
elif status.command == 'show_splash':
|
|
1103
|
+
self.ui.settings_tree.setEnabled(False)
|
|
1104
|
+
self.splash_sc.show()
|
|
1105
|
+
self.splash_sc.raise_()
|
|
1106
|
+
self.splash_sc.showMessage(status.attribute[0], color=Qt.white)
|
|
1107
|
+
|
|
1108
|
+
elif status.command == 'close_splash':
|
|
1109
|
+
self.splash_sc.close()
|
|
1110
|
+
self.ui.settings_tree.setEnabled(True)
|
|
1111
|
+
|
|
1112
|
+
elif status.command == 'init_lcd':
|
|
1113
|
+
if self._lcd is not None:
|
|
1114
|
+
try:
|
|
1115
|
+
self._lcd.parent.close()
|
|
1116
|
+
except Exception as e:
|
|
1117
|
+
self.logger.exception(str(e))
|
|
1118
|
+
# lcd module
|
|
1119
|
+
lcd = QtWidgets.QWidget()
|
|
1120
|
+
self._lcd = LCD(lcd, **status.attribute[0])
|
|
1121
|
+
lcd.setVisible(True)
|
|
1122
|
+
QtWidgets.QApplication.processEvents()
|
|
1123
|
+
|
|
1124
|
+
elif status.command == 'lcd':
|
|
1125
|
+
self._lcd.setvalues(status.attribute[0])
|
|
1126
|
+
|
|
1127
|
+
elif status.command == 'stop':
|
|
1128
|
+
self.stop()
|
|
1129
|
+
|
|
1130
|
+
self.custom_sig.emit(status) # to be used if needed in custom application connected to this module
|
|
1131
|
+
|
|
1132
|
+
def connect_tcp_ip(self):
|
|
1133
|
+
"""Init a TCPClient in a separated thread to communicate with a distant TCp/IP Server
|
|
1134
|
+
|
|
1135
|
+
Use the settings: ip_adress and port to specify the connection
|
|
1136
|
+
|
|
1137
|
+
See Also
|
|
1138
|
+
--------
|
|
1139
|
+
TCPServer
|
|
1140
|
+
"""
|
|
1141
|
+
if self.settings.child('main_settings', 'tcpip', 'connect_server').value():
|
|
1142
|
+
self._tcpclient_thread = QThread()
|
|
1143
|
+
|
|
1144
|
+
tcpclient = TCPClient(self.settings.child('main_settings', 'tcpip', 'ip_address').value(),
|
|
1145
|
+
self.settings.child('main_settings', 'tcpip', 'port').value(),
|
|
1146
|
+
self.settings.child('detector_settings'))
|
|
1147
|
+
tcpclient.moveToThread(self._tcpclient_thread)
|
|
1148
|
+
self._tcpclient_thread.tcpclient = tcpclient
|
|
1149
|
+
tcpclient.cmd_signal.connect(self.process_tcpip_cmds)
|
|
1150
|
+
|
|
1151
|
+
self._command_tcpip[ThreadCommand].connect(tcpclient.queue_command)
|
|
1152
|
+
|
|
1153
|
+
self._tcpclient_thread.start()
|
|
1154
|
+
tcpclient.init_connection(extra_commands=[ThreadCommand('get_axis', )])
|
|
1155
|
+
|
|
1156
|
+
@Slot(ThreadCommand)
|
|
1157
|
+
def process_tcpip_cmds(self, status):
|
|
1158
|
+
"""Receive commands from the TCP Server (if connected) and process them
|
|
1159
|
+
|
|
1160
|
+
Parameters
|
|
1161
|
+
----------
|
|
1162
|
+
status: ThreadCommand
|
|
1163
|
+
Possible commands are:
|
|
1164
|
+
* 'Send Data: to trigger a snapshot
|
|
1165
|
+
* 'connected': show that connection is ok
|
|
1166
|
+
* 'disconnected': show that connection is not OK
|
|
1167
|
+
* 'Update_Status': update a status command
|
|
1168
|
+
* 'set_info': receive settings from the server side and update them on this side
|
|
1169
|
+
* 'get_axis': request the plugin to send its axis info
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
See Also
|
|
1173
|
+
--------
|
|
1174
|
+
connect_tcp_ip, TCPServer
|
|
1175
|
+
|
|
1176
|
+
"""
|
|
1177
|
+
if 'Send Data' in status.command:
|
|
1178
|
+
self.snapshot('', send_to_tcpip=True)
|
|
1179
|
+
elif status.command == 'connected':
|
|
1180
|
+
self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(True)
|
|
1181
|
+
|
|
1182
|
+
elif status.command == 'disconnected':
|
|
1183
|
+
self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(False)
|
|
1184
|
+
|
|
1185
|
+
elif status.command == 'Update_Status':
|
|
1186
|
+
self.thread_status(status)
|
|
1187
|
+
|
|
1188
|
+
elif status.command == 'set_info':
|
|
1189
|
+
param_dict = ioxml.XML_string_to_parameter(status.attribute[1])[0]
|
|
1190
|
+
param_tmp = Parameter.create(**param_dict)
|
|
1191
|
+
param = self.settings.child('detector_settings', *status.attribute[0][1:])
|
|
1192
|
+
|
|
1193
|
+
param.restoreState(param_tmp.saveState())
|
|
1194
|
+
|
|
1195
|
+
elif status.command == 'get_axis':
|
|
1196
|
+
self.command_hardware.emit(
|
|
1197
|
+
ThreadCommand('get_axis', )) # tells the plugin to emit its axes so that the server will receive them
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
class DAQ_Detector(QObject):
|
|
1201
|
+
"""
|
|
1202
|
+
========================= ==========================
|
|
1203
|
+
**Attributes** **Type**
|
|
1204
|
+
*status_sig* instance of pyqt Signal
|
|
1205
|
+
*data_detector_sig* instance of pyqt Signal
|
|
1206
|
+
*data_detector_temp_sig* instance of pyqt Signal
|
|
1207
|
+
|
|
1208
|
+
*waiting_for_data* boolean
|
|
1209
|
+
*controller* ???
|
|
1210
|
+
*detector_name* string
|
|
1211
|
+
*detector* ???
|
|
1212
|
+
*controller_adress* ???
|
|
1213
|
+
*grab_state* boolean
|
|
1214
|
+
*single_grab* boolean
|
|
1215
|
+
*x_axis* 1D numpy array
|
|
1216
|
+
*y_axis* 1D numpy array
|
|
1217
|
+
*datas* dictionnary
|
|
1218
|
+
*ind_average* int
|
|
1219
|
+
*Naverage* int
|
|
1220
|
+
*average_done* boolean
|
|
1221
|
+
*hardware_averaging* boolean
|
|
1222
|
+
*show_averaging* boolean
|
|
1223
|
+
*wait_time* int
|
|
1224
|
+
*daq_type* string
|
|
1225
|
+
========================= ==========================
|
|
1226
|
+
"""
|
|
1227
|
+
status_sig = Signal(ThreadCommand)
|
|
1228
|
+
data_detector_sig = Signal(list)
|
|
1229
|
+
data_detector_temp_sig = Signal(list)
|
|
1230
|
+
|
|
1231
|
+
def __init__(self, title, settings_parameter, detector_name):
|
|
1232
|
+
super().__init__()
|
|
1233
|
+
self.waiting_for_data = False
|
|
1234
|
+
self.controller = None
|
|
1235
|
+
self.logger = set_logger(f'{logger.name}.{title}.detector')
|
|
1236
|
+
self.detector_name = detector_name
|
|
1237
|
+
self.detector = None
|
|
1238
|
+
self.controller_adress = None
|
|
1239
|
+
self.grab_state = False
|
|
1240
|
+
self.single_grab = False
|
|
1241
|
+
self.datas = None
|
|
1242
|
+
self.ind_average = 0
|
|
1243
|
+
self.Naverage = None
|
|
1244
|
+
self.average_done = False
|
|
1245
|
+
self.hardware_averaging = False
|
|
1246
|
+
self.show_averaging = False
|
|
1247
|
+
self.wait_time = settings_parameter['main_settings', 'wait_time']
|
|
1248
|
+
self.daq_type = DAQTypesEnum[settings_parameter['main_settings', 'DAQ_type']]
|
|
1249
|
+
|
|
1250
|
+
@Slot(edict)
|
|
1251
|
+
def update_settings(self, settings_parameter_dict):
|
|
1252
|
+
"""
|
|
1253
|
+
| Set attribute values in case of "main_settings" path with corresponding parameter values.
|
|
1254
|
+
| Recursively call the method on detector class attribute else.
|
|
1255
|
+
|
|
1256
|
+
======================== ============== ======================================
|
|
1257
|
+
**Parameters** **Type** **Description**
|
|
1258
|
+
settings_parameter_dict dictionnary the (pathname,parameter) dictionnary
|
|
1259
|
+
======================== ============== ======================================
|
|
1260
|
+
|
|
1261
|
+
See Also
|
|
1262
|
+
--------
|
|
1263
|
+
update_settings
|
|
1264
|
+
"""
|
|
1265
|
+
|
|
1266
|
+
path = settings_parameter_dict['path']
|
|
1267
|
+
param = settings_parameter_dict['param']
|
|
1268
|
+
if path[0] == 'main_settings':
|
|
1269
|
+
if hasattr(self, path[-1]):
|
|
1270
|
+
setattr(self, path[-1], param.value())
|
|
1271
|
+
|
|
1272
|
+
elif path[0] == 'detector_settings':
|
|
1273
|
+
self.detector.update_settings(settings_parameter_dict)
|
|
1274
|
+
|
|
1275
|
+
@Slot(ThreadCommand)
|
|
1276
|
+
def queue_command(self, command: ThreadCommand):
|
|
1277
|
+
"""Transfer command from the main module to the hardware module
|
|
1278
|
+
|
|
1279
|
+
Parameters
|
|
1280
|
+
----------
|
|
1281
|
+
command: ThreadCommand
|
|
1282
|
+
The specific (or generic) command (str) to pass to the hardware, either:
|
|
1283
|
+
* ini_detector
|
|
1284
|
+
* close
|
|
1285
|
+
* grab
|
|
1286
|
+
* single
|
|
1287
|
+
* stop_grab
|
|
1288
|
+
* stop_all
|
|
1289
|
+
* update_scanner
|
|
1290
|
+
* move_at_navigator
|
|
1291
|
+
* update_com
|
|
1292
|
+
* update_wait_time
|
|
1293
|
+
* get_axis
|
|
1294
|
+
* any string that the hardware is able to understand
|
|
1295
|
+
"""
|
|
1296
|
+
if command.command == "ini_detector":
|
|
1297
|
+
status = self.ini_detector(*command.attribute)
|
|
1298
|
+
self.status_sig.emit(ThreadCommand(command.command, [status, 'log']))
|
|
1299
|
+
|
|
1300
|
+
elif command.command == "close":
|
|
1301
|
+
status = self.close()
|
|
1302
|
+
self.status_sig.emit(ThreadCommand(command.command, [status, 'log']))
|
|
1303
|
+
|
|
1304
|
+
elif command.command == "grab":
|
|
1305
|
+
self.single_grab = False
|
|
1306
|
+
self.grab_state = True
|
|
1307
|
+
self.grab_data(*command.attribute)
|
|
1308
|
+
|
|
1309
|
+
elif command.command == "single":
|
|
1310
|
+
self.single_grab = True
|
|
1311
|
+
self.grab_state = True
|
|
1312
|
+
self.single(*command.attribute)
|
|
1313
|
+
|
|
1314
|
+
elif command.command == "stop_grab":
|
|
1315
|
+
self.grab_state = False
|
|
1316
|
+
self.status_sig.emit(ThreadCommand("Update_Status", ['Stoping grab']))
|
|
1317
|
+
|
|
1318
|
+
elif command.command == "stop_all":
|
|
1319
|
+
self.grab_state = False
|
|
1320
|
+
self.detector.stop()
|
|
1321
|
+
QtWidgets.QApplication.processEvents()
|
|
1322
|
+
self.status_sig.emit(ThreadCommand("Update_Status", ['Stoping grab']))
|
|
1323
|
+
|
|
1324
|
+
elif command.command == 'update_scanner':
|
|
1325
|
+
self.detector.update_scanner(command.attribute[0])
|
|
1326
|
+
|
|
1327
|
+
elif command.command == 'move_at_navigator':
|
|
1328
|
+
self.detector.move_at_navigator(*command.attribute)
|
|
1329
|
+
|
|
1330
|
+
elif command.command == 'update_com':
|
|
1331
|
+
self.detector.update_com()
|
|
1332
|
+
|
|
1333
|
+
elif command.command == 'update_wait_time':
|
|
1334
|
+
self.wait_time = command.attribute[0]
|
|
1335
|
+
|
|
1336
|
+
elif command.command == 'get_axis':
|
|
1337
|
+
self.detector.get_axis()
|
|
1338
|
+
|
|
1339
|
+
else: # custom commands for particular plugins (see ROISelect in relation to a Viewer2D and the plugin
|
|
1340
|
+
# Mock2D or the spectrometer module 'get_spectro_wl' for instance)
|
|
1341
|
+
if hasattr(self.detector, command.command):
|
|
1342
|
+
cmd = getattr(self.detector, command.command)
|
|
1343
|
+
cmd(command.attribute)
|
|
1344
|
+
|
|
1345
|
+
def ini_detector(self, params_state=None, controller=None):
|
|
1346
|
+
"""
|
|
1347
|
+
Init the detector from params_state parameter and DAQ_type class attribute :
|
|
1348
|
+
* in **0D** profile : update the local status and send the "x_axis" Thread command via a status signal
|
|
1349
|
+
* in **1D** profile : update the local status and send the "x_axis" Thread command via a status signal
|
|
1350
|
+
* in **2D** profile : update the local status and send the "x_axis" and the "y_axis" Thread command via a status signal
|
|
1351
|
+
|
|
1352
|
+
=============== =========== ==========================================
|
|
1353
|
+
**Parameters** **Type** **Description**
|
|
1354
|
+
*params_state* ??? the parameter's state of initialization
|
|
1355
|
+
=============== =========== ==========================================
|
|
1356
|
+
|
|
1357
|
+
See Also
|
|
1358
|
+
--------
|
|
1359
|
+
ini_detector, daq_utils.ThreadCommand
|
|
1360
|
+
"""
|
|
1361
|
+
try:
|
|
1362
|
+
# status="Not initialized"
|
|
1363
|
+
status = edict(initialized=False, info="", x_axis=None, y_axis=None)
|
|
1364
|
+
det_params, class_ = get_viewer_plugins(self.daq_type.name, self.detector_name)
|
|
1365
|
+
self.detector = class_(self, params_state)
|
|
1366
|
+
|
|
1367
|
+
try:
|
|
1368
|
+
self.detector.data_grabed_signal.connect(self.data_ready)
|
|
1369
|
+
self.detector.data_grabed_signal_temp.connect(self.emit_temp_data)
|
|
1370
|
+
infos = self.detector.ini_detector(controller) # return edict(info="", controller=, stage=)
|
|
1371
|
+
status.controller = self.detector.controller
|
|
1372
|
+
|
|
1373
|
+
except Exception as e:
|
|
1374
|
+
logger.exception('Hardware couldn\'t be initialized' + str(e))
|
|
1375
|
+
infos = str(e), False
|
|
1376
|
+
status.controller = None
|
|
1377
|
+
|
|
1378
|
+
if isinstance(infos, edict):
|
|
1379
|
+
status.update(infos)
|
|
1380
|
+
else:
|
|
1381
|
+
status.info = infos[0]
|
|
1382
|
+
status.initialized = infos[1]
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
if status['x_axis'] is not None:
|
|
1386
|
+
x_axis = status['x_axis']
|
|
1387
|
+
self.status_sig.emit(ThreadCommand("x_axis", [x_axis]))
|
|
1388
|
+
if status['y_axis'] is not None:
|
|
1389
|
+
y_axis = status['y_axis']
|
|
1390
|
+
self.status_sig.emit(ThreadCommand("y_axis", [y_axis]))
|
|
1391
|
+
|
|
1392
|
+
self.hardware_averaging = class_.hardware_averaging # to check if averaging can be done directly by the hardware or done here software wise
|
|
1393
|
+
|
|
1394
|
+
return status
|
|
1395
|
+
except Exception as e:
|
|
1396
|
+
self.logger.exception(str(e))
|
|
1397
|
+
return status
|
|
1398
|
+
|
|
1399
|
+
@Slot(list)
|
|
1400
|
+
def emit_temp_data(self, datas):
|
|
1401
|
+
self.data_detector_temp_sig.emit(datas)
|
|
1402
|
+
|
|
1403
|
+
@Slot(list)
|
|
1404
|
+
def data_ready(self, datas):
|
|
1405
|
+
"""
|
|
1406
|
+
| Update the local datas attribute from the given datas parameter if the averaging has to be done software wise.
|
|
1407
|
+
|
|
|
1408
|
+
| Else emit the data detector signals with datas parameter as an attribute.
|
|
1409
|
+
|
|
1410
|
+
=============== ===================== =========================
|
|
1411
|
+
**Parameters** **Type** **Description**
|
|
1412
|
+
*datas* list the datas to be emitted.
|
|
1413
|
+
=============== ===================== =========================
|
|
1414
|
+
|
|
1415
|
+
See Also
|
|
1416
|
+
--------
|
|
1417
|
+
daq_utils.ThreadCommand
|
|
1418
|
+
"""
|
|
1419
|
+
|
|
1420
|
+
# datas validation check for backcompatibility with plugins not exporting new DataFromPlugins list of objects
|
|
1421
|
+
|
|
1422
|
+
for dat in datas:
|
|
1423
|
+
if not isinstance(dat, DataFromPlugins):
|
|
1424
|
+
if 'type' in dat:
|
|
1425
|
+
dat['dim'] = dat['type']
|
|
1426
|
+
dat['type'] = 'raw'
|
|
1427
|
+
|
|
1428
|
+
if not self.hardware_averaging: # to execute if the averaging has to be done software wise
|
|
1429
|
+
self.ind_average += 1
|
|
1430
|
+
if self.ind_average == 1:
|
|
1431
|
+
self.datas = datas
|
|
1432
|
+
else:
|
|
1433
|
+
try:
|
|
1434
|
+
for indpannel, dic in enumerate(datas):
|
|
1435
|
+
self.datas[indpannel]['data'] = \
|
|
1436
|
+
[((self.ind_average - 1) * self.datas[indpannel]['data'][ind] + datas[indpannel]['data'][
|
|
1437
|
+
ind]) / self.ind_average for ind in range(len(datas[indpannel]['data']))]
|
|
1438
|
+
|
|
1439
|
+
if self.show_averaging:
|
|
1440
|
+
self.emit_temp_data(self.datas)
|
|
1441
|
+
|
|
1442
|
+
except Exception as e:
|
|
1443
|
+
self.logger.exception(str(e))
|
|
1444
|
+
|
|
1445
|
+
if self.ind_average == self.Naverage:
|
|
1446
|
+
self.average_done = True
|
|
1447
|
+
self.data_detector_sig.emit(self.datas)
|
|
1448
|
+
self.ind_average = 0
|
|
1449
|
+
else:
|
|
1450
|
+
self.data_detector_sig.emit(datas)
|
|
1451
|
+
self.waiting_for_data = False
|
|
1452
|
+
if not self.grab_state:
|
|
1453
|
+
# self.status_sig.emit(["Update_Status","Grabing braked"])
|
|
1454
|
+
self.detector.stop()
|
|
1455
|
+
|
|
1456
|
+
def single(self, Naverage=1, args_as_dict={}):
|
|
1457
|
+
"""
|
|
1458
|
+
Call the grab method with Naverage parameter as an attribute.
|
|
1459
|
+
|
|
1460
|
+
=============== =========== ==================
|
|
1461
|
+
**Parameters** **Type** **Description**
|
|
1462
|
+
*Naverage* int
|
|
1463
|
+
*savepath* str eventual savepath
|
|
1464
|
+
=============== =========== ==================
|
|
1465
|
+
|
|
1466
|
+
See Also
|
|
1467
|
+
--------
|
|
1468
|
+
daq_utils.ThreadCommand, grab
|
|
1469
|
+
"""
|
|
1470
|
+
try:
|
|
1471
|
+
self.grab_data(Naverage, live=False, **args_as_dict)
|
|
1472
|
+
|
|
1473
|
+
except Exception as e:
|
|
1474
|
+
self.logger.exception(str(e))
|
|
1475
|
+
|
|
1476
|
+
def grab_data(self, Naverage=1, live=True, **kwargs):
|
|
1477
|
+
"""
|
|
1478
|
+
| Update status with 'Start Grabing' Update_status sub command of the Thread command.
|
|
1479
|
+
| Process events and grab naverage is needed.
|
|
1480
|
+
|
|
1481
|
+
=============== =========== ==================
|
|
1482
|
+
**Parameters** **Type** **Description**
|
|
1483
|
+
*Naverage* int
|
|
1484
|
+
=============== =========== ==================
|
|
1485
|
+
|
|
1486
|
+
See Also
|
|
1487
|
+
--------
|
|
1488
|
+
daq_utils.ThreadCommand, grab
|
|
1489
|
+
"""
|
|
1490
|
+
try:
|
|
1491
|
+
self.ind_average = 0
|
|
1492
|
+
self.Naverage = Naverage
|
|
1493
|
+
if Naverage > 1:
|
|
1494
|
+
self.average_done = False
|
|
1495
|
+
# self.status_sig.emit(ThreadCommand("Update_Status", [f'Start Grabing']))
|
|
1496
|
+
self.waiting_for_data = False
|
|
1497
|
+
|
|
1498
|
+
# for live mode:two possibilities: either snap one data and regrab softwarewise (while True) or if
|
|
1499
|
+
# self.detector.live_mode_available is True all data is continuously emited from the plugin
|
|
1500
|
+
if self.detector.live_mode_available:
|
|
1501
|
+
kwargs['wait_time'] = self.wait_time
|
|
1502
|
+
else:
|
|
1503
|
+
kwargs['wait_time'] = 0
|
|
1504
|
+
self.status_sig.emit(ThreadCommand('grab'))
|
|
1505
|
+
while True:
|
|
1506
|
+
try:
|
|
1507
|
+
if not self.waiting_for_data:
|
|
1508
|
+
self.waiting_for_data = True
|
|
1509
|
+
self.detector.grab_data(Naverage, live=live, **kwargs)
|
|
1510
|
+
QtWidgets.QApplication.processEvents()
|
|
1511
|
+
if self.single_grab:
|
|
1512
|
+
if self.hardware_averaging:
|
|
1513
|
+
break
|
|
1514
|
+
else:
|
|
1515
|
+
if self.average_done:
|
|
1516
|
+
break
|
|
1517
|
+
else:
|
|
1518
|
+
QThread.msleep(self.wait_time) #if in live mode apply a waiting time after acquisition
|
|
1519
|
+
if not self.grab_state:
|
|
1520
|
+
break
|
|
1521
|
+
if self.detector.live_mode_available:
|
|
1522
|
+
break
|
|
1523
|
+
except Exception as e:
|
|
1524
|
+
self.logger.exception(str(e))
|
|
1525
|
+
self.status_sig.emit(ThreadCommand('grab_stopped'))
|
|
1526
|
+
|
|
1527
|
+
except Exception as e:
|
|
1528
|
+
self.logger.exception(str(e))
|
|
1529
|
+
|
|
1530
|
+
def close(self):
|
|
1531
|
+
"""
|
|
1532
|
+
close the current instance of DAQ_Detector.
|
|
1533
|
+
"""
|
|
1534
|
+
try:
|
|
1535
|
+
self.detector.stop()
|
|
1536
|
+
status = self.detector.close()
|
|
1537
|
+
except Exception as e:
|
|
1538
|
+
self.logger.exception(str(e))
|
|
1539
|
+
status = str(e)
|
|
1540
|
+
return status
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
def prepare_docks(area, title):
|
|
1544
|
+
dock_settings = Dock(title + " settings", size=(150, 250))
|
|
1545
|
+
dock_viewer = Dock(title + " viewer", size=(350, 350))
|
|
1546
|
+
area.addDock(dock_settings)
|
|
1547
|
+
area.addDock(dock_viewer, 'right', dock_settings)
|
|
1548
|
+
return dict(dock_settings=dock_settings, dock_viewer=dock_viewer)
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
def main(init_qt=True, init_det=False):
|
|
1552
|
+
if init_qt: # used for the test suite
|
|
1553
|
+
app = QtWidgets.QApplication(sys.argv)
|
|
1554
|
+
if config('style', 'darkstyle'):
|
|
1555
|
+
import qdarkstyle
|
|
1556
|
+
app.setStyleSheet(qdarkstyle.load_stylesheet(qdarkstyle.DarkPalette))
|
|
1557
|
+
|
|
1558
|
+
win = QtWidgets.QMainWindow()
|
|
1559
|
+
area = DockArea()
|
|
1560
|
+
win.setCentralWidget(area)
|
|
1561
|
+
win.resize(1000, 500)
|
|
1562
|
+
win.setWindowTitle('PyMoDAQ Viewer')
|
|
1563
|
+
win.show()
|
|
1564
|
+
|
|
1565
|
+
title = "Testing"
|
|
1566
|
+
viewer = DAQ_Viewer(area, title="Testing", daq_type=config('viewer', 'daq_type'),
|
|
1567
|
+
**prepare_docks(area, title))
|
|
1568
|
+
if init_det:
|
|
1569
|
+
viewer.init_hardware_ui(init_det)
|
|
1570
|
+
|
|
1571
|
+
if init_qt:
|
|
1572
|
+
sys.exit(app.exec_())
|
|
1573
|
+
return viewer, win
|
|
1574
|
+
|
|
1575
|
+
|
|
1576
|
+
if __name__ == '__main__':
|
|
1577
|
+
main(init_det=False)
|