pyForceDAQ 2.0.5.dev3__tar.gz → 2.0.5.dev4__tar.gz
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.
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/PKG-INFO +1 -1
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/pyproject.toml +1 -1
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/settings.py +3 -2
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/constants.py +3 -3
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_gui_status.py +7 -3
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_layout.py +18 -9
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_run.py +14 -13
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/launcher.py +8 -1
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/__init__.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/__main__.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/__init__.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/clock.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/data_recorder.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/file_writer.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/lsl.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/misc.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/process_priority_manager.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/sensor.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/sensor_process.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/types.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/udp_connection.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/__init__.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/_pyATIDAQ.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/calibration_dll.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/calibration_iaftt.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/read_daq_mock_sensor.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/read_daq_nidaqmx.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/daq/read_daq_pydaqmx.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/force.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/__init__.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_level_indicator.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_pg_surface.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_plotter.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/_scaling.py +0 -0
- {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/gui/forceDAQ_logo.png +0 -0
|
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Tuple
|
|
|
7
7
|
|
|
8
8
|
import tomlkit
|
|
9
9
|
|
|
10
|
-
from ..constants import CALIBRATION_FOLDER, DATA_FOLDER
|
|
10
|
+
from ..constants import CALIBRATION_FOLDER, DATA_FOLDER, SETTINGS_FILE_EXTENSION
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DAQConfiguration(object):
|
|
@@ -185,11 +185,12 @@ class AppSettings(object):
|
|
|
185
185
|
self.recording_section = "Recording"
|
|
186
186
|
|
|
187
187
|
self.filepath = Path(filename)
|
|
188
|
+
self.filepath = self.filepath.with_suffix(SETTINGS_FILE_EXTENSION)
|
|
188
189
|
if os.path.isfile(self.filepath):
|
|
189
190
|
self.load()
|
|
190
191
|
else:
|
|
191
192
|
self.save() # defaults
|
|
192
|
-
|
|
193
|
+
print(f"WARNING: {self.filepath} not found, creating new settings file with defaults")
|
|
193
194
|
self.output_filename = ""
|
|
194
195
|
|
|
195
196
|
def _asdict(self):
|
|
@@ -5,8 +5,8 @@ MOCK_SENSOR = 9
|
|
|
5
5
|
DAQ_TYPE = NIDAQMX # default to nidaqmx, use constants.MOCK_SENSOR for mock sensor, constants.PYDAQMX for PyDAQmx
|
|
6
6
|
USE_AIFTT = True # <-- change to False to use ATI DLL for calibration conversion, otherwise use atiiaftt
|
|
7
7
|
|
|
8
|
-
SETTINGS_FILE_EXTENSION = ".
|
|
9
|
-
DEFAULT_SETTINGS_FILE = "pyForceDAQ" + SETTINGS_FILE_EXTENSION
|
|
8
|
+
SETTINGS_FILE_EXTENSION = ".toml"
|
|
9
|
+
DEFAULT_SETTINGS_FILE = "pyForceDAQ.settings" + SETTINGS_FILE_EXTENSION
|
|
10
10
|
DEFAULT_OUTPUT_FILENAME = None
|
|
11
|
-
CALIBRATION_FOLDER = "
|
|
11
|
+
CALIBRATION_FOLDER = "."
|
|
12
12
|
DATA_FOLDER = "data"
|
|
@@ -2,7 +2,7 @@ __author__ = "Oliver Lindemann"
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
from time import sleep
|
|
5
|
-
from typing import Tuple
|
|
5
|
+
from typing import List, Tuple
|
|
6
6
|
|
|
7
7
|
from expyriment import io, misc
|
|
8
8
|
|
|
@@ -27,16 +27,19 @@ def _text2number_array(txt):
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class GUIStatus(object):
|
|
30
|
+
|
|
30
31
|
def __init__(
|
|
31
32
|
self,
|
|
32
33
|
gui_settings: GUISettings,
|
|
33
34
|
recorder: DataRecorder,
|
|
34
35
|
screen_size: Tuple[int, int],
|
|
36
|
+
top_left_info:List[str] = [""]
|
|
35
37
|
):
|
|
36
38
|
|
|
37
39
|
self.gs = gui_settings
|
|
38
40
|
self.recorder = recorder
|
|
39
41
|
self.screen_size = screen_size
|
|
42
|
+
self.top_left_info = top_left_info
|
|
40
43
|
|
|
41
44
|
self.scaling_plotter = Scaling(
|
|
42
45
|
min=gui_settings.data_min_max[0],
|
|
@@ -133,8 +136,9 @@ class GUIStatus(object):
|
|
|
133
136
|
|
|
134
137
|
return RecordingScreen(
|
|
135
138
|
window_size=self.screen_size,
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
txt_top_left=self.top_left_info,
|
|
140
|
+
txt_top_right=info_file,
|
|
141
|
+
txt_top_center=info_recording,
|
|
138
142
|
text_colour=txt_col,
|
|
139
143
|
no_pause_option = not self.recorder.has_file_writer
|
|
140
144
|
)
|
|
@@ -2,6 +2,8 @@ __author__ = "Oliver Lindemann"
|
|
|
2
2
|
|
|
3
3
|
# helper functions
|
|
4
4
|
import os
|
|
5
|
+
from copy import copy
|
|
6
|
+
from typing import List
|
|
5
7
|
|
|
6
8
|
import pygame
|
|
7
9
|
from expyriment import stimuli
|
|
@@ -31,6 +33,7 @@ def get_pygame_rect(stimulus, screen_size):
|
|
|
31
33
|
return pygame.Rect(rect_pos, stim_size)
|
|
32
34
|
|
|
33
35
|
|
|
36
|
+
|
|
34
37
|
def logo_text_line(text):
|
|
35
38
|
blank = stimuli.Canvas(size=(600, 400))
|
|
36
39
|
logo = stimuli.Picture(
|
|
@@ -56,7 +59,11 @@ def make_text_line(text, position, text_size, text_colour):
|
|
|
56
59
|
|
|
57
60
|
class RecordingScreen(object):
|
|
58
61
|
|
|
59
|
-
def __init__(self, window_size,
|
|
62
|
+
def __init__(self, window_size,
|
|
63
|
+
txt_top_left: List[str],
|
|
64
|
+
txt_top_center:str,
|
|
65
|
+
txt_top_right:str,
|
|
66
|
+
text_colour,
|
|
60
67
|
no_pause_option:bool = False):
|
|
61
68
|
# NOTE: Expyriment has to be intialized
|
|
62
69
|
margin = 30
|
|
@@ -67,12 +74,14 @@ class RecordingScreen(object):
|
|
|
67
74
|
|
|
68
75
|
self.text_colour = text_colour
|
|
69
76
|
self.elements = []
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
|
|
78
|
+
txt_list = copy(txt_top_left)
|
|
79
|
+
txt_list.insert(0, f"Version {forceDAQVersion}")
|
|
80
|
+
for cnt, txt in enumerate(txt_list):
|
|
81
|
+
self.add_text_line_left(
|
|
82
|
+
txt,
|
|
83
|
+
[self.left, self.top - cnt * 20],
|
|
84
|
+
text_size=15,text_colour=None)
|
|
76
85
|
col = expy_constants.C_GREY
|
|
77
86
|
if not no_pause_option:
|
|
78
87
|
self.add_text_line_left("P: pause/unpause saving", [self.left, self.bottom + 20], text_colour=col)
|
|
@@ -88,8 +97,8 @@ class RecordingScreen(object):
|
|
|
88
97
|
)
|
|
89
98
|
self.add_text_line_right("Q: quit recording", [self.right, self.bottom], text_colour=col)
|
|
90
99
|
|
|
91
|
-
self.add_text_line_right(
|
|
92
|
-
self.add_text_line_centered(
|
|
100
|
+
self.add_text_line_right(txt_top_right, [self.right, self.top], text_size=15)
|
|
101
|
+
self.add_text_line_centered(txt_top_center, [0, self.top], text_size=15)
|
|
93
102
|
|
|
94
103
|
def add_text_line_centered(
|
|
95
104
|
self, text, position, text_size=12, text_colour=None
|
|
@@ -19,7 +19,7 @@ from .._lib.clock import wait_ms
|
|
|
19
19
|
from .._lib.data_recorder import DataRecorder
|
|
20
20
|
from .._lib.sensor_process import SensorProcess
|
|
21
21
|
from .._lib.settings import AppSettings, GUISettings, SensorSettings
|
|
22
|
-
from ..constants import DEFAULT_OUTPUT_FILENAME
|
|
22
|
+
from ..constants import DEFAULT_OUTPUT_FILENAME
|
|
23
23
|
from ._gui_status import GUIStatus
|
|
24
24
|
from ._layout import colours, get_pygame_rect, logo_text_line, make_text_line
|
|
25
25
|
from ._level_indicator import level_indicator
|
|
@@ -33,7 +33,7 @@ CHANGED_LEVEL = COMMAND_STR + b"xCL1"
|
|
|
33
33
|
CHANGED_LEVEL2 = COMMAND_STR + b"xCL2"
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
36
|
+
def _main_loop(exp, recorder: DataRecorder, gs: GUISettings, info_strings: List[str]):
|
|
37
37
|
"""udp command:
|
|
38
38
|
"start", "pause", "stop"
|
|
39
39
|
"thresholds = [x,...]" : start level detection for Fz parameter and set threshold
|
|
@@ -44,7 +44,8 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
|
44
44
|
plotter_width = 900
|
|
45
45
|
plotter_position = (0, -30)
|
|
46
46
|
|
|
47
|
-
s = GUIStatus(gui_settings=gs, recorder=recorder, screen_size=exp.screen.size
|
|
47
|
+
s = GUIStatus(gui_settings=gs, recorder=recorder, screen_size=exp.screen.size,
|
|
48
|
+
top_left_info=info_strings)
|
|
48
49
|
|
|
49
50
|
# plotter
|
|
50
51
|
plotter_thread = None
|
|
@@ -295,14 +296,15 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
|
295
296
|
update_rects.append(get_pygame_rect(txt, exp.screen.size))
|
|
296
297
|
|
|
297
298
|
# counter
|
|
298
|
-
pos = (-
|
|
299
|
+
pos = (-270, 240)
|
|
300
|
+
|
|
299
301
|
stimuli.Canvas(
|
|
300
|
-
position=pos, size=(400,
|
|
302
|
+
position=pos, size=(400, 20), colour=misc.constants.C_BLACK
|
|
301
303
|
).present(update=False, clear=False)
|
|
302
304
|
|
|
303
305
|
txt = stimuli.TextBox(
|
|
304
306
|
position=pos,
|
|
305
|
-
size=(400,
|
|
307
|
+
size=(400, 20),
|
|
306
308
|
# background_colour=(30,30,30),
|
|
307
309
|
text_size=15,
|
|
308
310
|
text="n samples (total): {0}".format(
|
|
@@ -314,7 +316,9 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
|
314
316
|
txt.present(update=False, clear=False)
|
|
315
317
|
update_rects.append(get_pygame_rect(txt, exp.screen.size))
|
|
316
318
|
|
|
317
|
-
#
|
|
319
|
+
#FIXME Threshold levels down work
|
|
320
|
+
|
|
321
|
+
# Sensor info
|
|
318
322
|
pos = (200, 250)
|
|
319
323
|
tmp = stimuli.Canvas(
|
|
320
324
|
position=pos, size=(400, 50), colour=misc.constants.C_BLACK
|
|
@@ -329,6 +333,7 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
|
329
333
|
]
|
|
330
334
|
else:
|
|
331
335
|
tmp = s.thresholds.get_level(s.level_detection_parameter_average(0))
|
|
336
|
+
|
|
332
337
|
txt = stimuli.TextBox(
|
|
333
338
|
position=pos,
|
|
334
339
|
size=(400, 50),
|
|
@@ -387,11 +392,6 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
|
|
|
387
392
|
|
|
388
393
|
|
|
389
394
|
def run_settings_file(settings_file: str | Path = ""):
|
|
390
|
-
|
|
391
|
-
if isinstance(settings_file, str) and len(settings_file) < 2:
|
|
392
|
-
# load default settings file if not specified
|
|
393
|
-
settings_file = DEFAULT_SETTINGS_FILE
|
|
394
|
-
|
|
395
395
|
return run(AppSettings(settings_file))
|
|
396
396
|
|
|
397
397
|
|
|
@@ -456,7 +456,8 @@ def run(settings: AppSettings):
|
|
|
456
456
|
|
|
457
457
|
sleep(show_logo_time)
|
|
458
458
|
|
|
459
|
-
_main_loop(exp, recorder=recorder, gs=settings.gui
|
|
459
|
+
_main_loop(exp, recorder=recorder, gs=settings.gui,
|
|
460
|
+
info_strings=[f"{settings.filepath.name}"])
|
|
460
461
|
|
|
461
462
|
recorder.quit()
|
|
462
463
|
control.end()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import glob
|
|
1
2
|
from os import path
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from typing import List
|
|
@@ -139,7 +140,13 @@ def load_settings_file(settings_file: str | Path) -> AppSettings:
|
|
|
139
140
|
|
|
140
141
|
def run_launcher():
|
|
141
142
|
_sg.theme("DarkBlue14") # please make your windows colorful
|
|
142
|
-
|
|
143
|
+
|
|
144
|
+
toml_files = glob.glob("*.toml")
|
|
145
|
+
if len(toml_files) == 0:
|
|
146
|
+
settings_file = constants.DEFAULT_SETTINGS_FILE
|
|
147
|
+
else:
|
|
148
|
+
settings_file = toml_files[0]
|
|
149
|
+
settings = load_settings_file(settings_file)
|
|
143
150
|
|
|
144
151
|
while True:
|
|
145
152
|
event, values, settings = _windows_run(settings)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.5.dev4}/src/pyforcedaq/_lib/process_priority_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|