pyForceDAQ 2.0.0.dev0__py3-none-any.whl → 2.0.1.dev1__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.
pyforcedaq/__init__.py CHANGED
@@ -7,7 +7,7 @@ launch the GUI force from your Python program:
7
7
  ``
8
8
  from pyforcedaq import gui
9
9
 
10
- gui.run_with_options(remote_control=False,
10
+ gui.run(remote_control=False,
11
11
  ask_filename=True,
12
12
  calibration_file="FT_sensor1.cal")
13
13
  ``
pyforcedaq/__main__.py CHANGED
@@ -34,9 +34,9 @@ def cli():
34
34
  from .gui import launcher
35
35
  return launcher.run()
36
36
  else:
37
- gui.run(args.SETTINGS_FILE)
37
+ gui.run_settings(args.SETTINGS_FILE)
38
38
 
39
39
 
40
40
 
41
41
  if __name__ == "__main__": # required because of threading
42
- cli() # gui.run(), gui.run_with_options()
42
+ cli()
pyforcedaq/_lib/misc.py CHANGED
@@ -39,20 +39,31 @@ class MinMaxDetector(object):
39
39
  return (self._level_change_time is not None) and \
40
40
  (get_time_ms() - self._level_change_time) < self._duration
41
41
 
42
- def find_calibration_file(calibration_folder, sensor_name,
43
- calibration_suffix=".cal"):
44
-
45
- needle = 'Serial="{0}"'.format(sensor_name)
46
- for x in listdir(path.abspath(calibration_folder)):
47
- filename = path.join(calibration_folder, x)
48
- if path.isfile(filename) and filename.endswith(calibration_suffix):
49
- with open(filename, "r") as fl:
50
- for l in fl:
51
- if l.find(needle)>0:
52
- return filename
53
- raise RuntimeError("Can't find calibration file for sensor '{0}' : {1}.".format(
54
- sensor_name, filename))
55
-
42
+ # def find_calibration_file(calibration_folder: str, sensor_name: str,
43
+ # calibration_suffix=".cal") -> str:
44
+
45
+ # needle = 'Serial="{0}"'.format(sensor_name)
46
+ # calibration_files = []
47
+ # for x in listdir(path.abspath(calibration_folder)):
48
+ # filename = path.join(calibration_folder, x)
49
+ # if path.isfile(filename) and filename.endswith(calibration_suffix):
50
+ # with open(filename, "r") as fl:
51
+ # for l in fl:
52
+ # if l.find(needle)>0:
53
+ # print("Found calibration file for sensor '{0}' : {1}.".format(
54
+ # sensor_name, filename))
55
+ # calibration_files.append(filename)
56
+
57
+ # if len(calibration_files) == 1:
58
+ # return calibration_files[0]
59
+ # elif len(calibration_files) > 1:
60
+ # print("Multiple calibration files found for sensor '{0}'".format(sensor_name))
61
+ # for f in calibration_files:
62
+ # print(" - {0}".format(f))
63
+ # print("Please ensure that only one calibration file exists for each sensor")
64
+ # else:
65
+ # print("No calibration file found for sensor '{0}'.".format(sensor_name))
66
+ # exit()
56
67
 
57
68
  #Sensor History with moving average filtering and distance, velocity
58
69
  class SensorHistory(object):
pyforcedaq/_lib/types.py CHANGED
@@ -13,7 +13,7 @@ TAG_UDPDATA = TAG_COMMENTS + "UDP"
13
13
  CTYPE_FORCES = ct.c_float * 600
14
14
  CTYPE_TRIGGER = ct.c_float * 2
15
15
 
16
- class PollingPriority(object):
16
+ class PollingPriority(object): # TODO needed?
17
17
 
18
18
  NORMAL = 'normal'
19
19
  HIGH = 'high'
@@ -1,5 +1,5 @@
1
1
  __author__ = "Oliver Lindemann"
2
- __version__ = "0.4"
2
+ __version__ = "0.5"
3
3
 
4
4
  from .. import USE_MOCK_SENSOR
5
5
  from ._pyATIDAQ import ATI_CDLL
@@ -11,9 +11,10 @@ if USE_MOCK_SENSOR:
11
11
  else:
12
12
  #### change import here if you want to use nidaqmx instead of pydaymx ####
13
13
  try:
14
- from ._daq_read_analog_pydaqmx import DAQReadAnalog
15
- #from ._daq_read_analog_nidaqmx import DAQReadAnalog
16
- except (ImportError, ModuleNotFoundError):
14
+ from ._use_pydaqmx import DAQReadAnalog
15
+ #from ._use_nidaqmx import DAQReadAnalog
16
+ except (ImportError, ModuleNotFoundError, NotImplementedError) as e:
17
+ print("Error importing DAQReadAnalog: {0}".format(e))
17
18
  print("Warning: PyDAQmx or nidaqmx not found. Using mock sensor instead.")
18
19
  from ._mock_sensor import DAQReadAnalog
19
20
 
@@ -12,8 +12,6 @@ __author__ = "Oliver Lindemann"
12
12
  from ctypes import *
13
13
  from sys import platform
14
14
 
15
- from .._lib.misc import find_calibration_file
16
-
17
15
  # ### DATA TYPES ####
18
16
  VOLTAGE_SAMPLE_TYPE = c_float * 7
19
17
  FT_SAMPLE_TYPE = c_float * 6
@@ -292,7 +290,7 @@ if __name__ == "__main__":
292
290
  # -0.065867 0.123803 111.156731 0.039974 0.040417 0.079049
293
291
 
294
292
  #filename = raw_input("Calibration file: ")
295
- filename = find_calibration_file("calibration", "FT30436")
293
+ filename = "calibration/FT30436.cal"
296
294
  atidaq = ATI_CDLL()
297
295
  # get calibration
298
296
  index = c_short(1)
@@ -7,8 +7,7 @@ __author__ = "Oliver Lindemann"
7
7
  import atexit
8
8
  import gzip
9
9
  import logging
10
- import os
11
- import sys
10
+ from pathlib import Path
12
11
  from time import asctime, localtime, strftime
13
12
 
14
13
  from pyforcedaq._lib import timer
@@ -38,7 +37,7 @@ class DataRecorder(object):
38
37
  def __init__(self, force_sensor_settings:SensorSettings | list,
39
38
  poll_udp_connection=False,
40
39
  write_deviceid = False,
41
- polling_priority=None):
40
+ polling_priority:str | None = None):
42
41
 
43
42
 
44
43
  """queue_data will be saved
@@ -82,18 +81,18 @@ class DataRecorder(object):
82
81
  self._proc_manager.add_subprocess(self.udp)
83
82
  self._proc_manager.add_subprocess(self._force_sensor_processes)
84
83
  if polling_priority is not None:
85
- self._proc_manager.set_subprocess_priorities(
86
- level=PollingPriority.get_priority(polling_priority),
87
- disable_gc=False)
84
+ level = PollingPriority.NORMAL
85
+ else:
86
+ level = PollingPriority.get_priority(polling_priority)
87
+ self._proc_manager.set_subprocess_priorities(level=level, disable_gc=False)
88
88
 
89
- logging.info("Main process priority: {}".format(
90
- self._proc_manager.get_main_priority()))
89
+ logging.info("Main process priority: %s", self._proc_manager.get_main_priority())
91
90
  #logging.info("Subprocess priorities: {}".format(self._proc_manager.get_subprocess_priorities()))
92
91
 
93
92
  self._is_recording = False
94
93
  self._file = None
95
94
  self._daq_event = []
96
- self.filename = None
95
+ self.filename: str | None = None
97
96
  atexit.register(self.quit)
98
97
 
99
98
 
@@ -102,7 +101,7 @@ class DataRecorder(object):
102
101
  """Property indicates whether the recording processes are alive"""
103
102
  try:
104
103
  return self._force_sensor_processes[0].is_alive()
105
- except:
104
+ except Exception:
106
105
  return False
107
106
 
108
107
  @property
@@ -119,7 +118,7 @@ class DataRecorder(object):
119
118
  return list(map(lambda x:x.sensor_settings,
120
119
  self._force_sensor_processes))
121
120
 
122
- def quit(self):
121
+ def quit(self) -> list | None:
123
122
  """Stop all recording processes, close data file and quit recording
124
123
 
125
124
  Notes
@@ -145,7 +144,7 @@ class DataRecorder(object):
145
144
 
146
145
  return buffer
147
146
 
148
- def process_and_write_udp_events(self):
147
+ def process_and_write_udp_events(self) -> list:
149
148
  """process udp events and return them"""
150
149
  buffer = []
151
150
  while True:
@@ -159,9 +158,9 @@ class DataRecorder(object):
159
158
  self._save_data(buffer)
160
159
  return buffer
161
160
 
162
- def _save_data(self, data_buffer,
161
+ def _save_data(self, data_buffer: list,
163
162
  recording_screen=None,
164
- float_decimal_places=4):
163
+ float_decimal_places: int = 4) -> None:
165
164
  """ writes data to disk and set counters
166
165
 
167
166
  ignores UDP remote control commands
@@ -199,10 +198,10 @@ class DataRecorder(object):
199
198
  "Writing {0} of {1} blocks".format(c//BLOCKSIZE,
200
199
  buffer_len//BLOCKSIZE)).present()
201
200
 
202
- def _file_write(self, str):
203
- self._file.write(str.encode())
201
+ def _file_write(self, s: str) -> None:
202
+ self._file.write(s.encode())
204
203
 
205
- def save_daq_event(self, code, time=None):
204
+ def save_daq_event(self, code, time: float | None = None) -> None:
206
205
  """Set marker code in file
207
206
 
208
207
  DAQEvent will be timestamps and occur in the data output
@@ -213,7 +212,7 @@ class DataRecorder(object):
213
212
  self._daq_event.append(DAQEvents(time = time, code = code))
214
213
 
215
214
 
216
- def start_recording(self, determine_bias=False):
215
+ def start_recording(self, determine_bias: bool = False) -> None:
217
216
  """Start polling process and record
218
217
 
219
218
  See Also
@@ -233,7 +232,7 @@ class DataRecorder(object):
233
232
  list(map(lambda x:x.start_polling(), self._force_sensor_processes))
234
233
  self._is_recording = True
235
234
 
236
- def pause_recording(self, recording_screen=None):
235
+ def pause_recording(self, recording_screen=None) -> list:
237
236
  """Pauses all polling processes and process data
238
237
 
239
238
  returns
@@ -268,7 +267,7 @@ class DataRecorder(object):
268
267
  self._daq_event = []
269
268
  return data
270
269
 
271
- def determine_biases(self, n_samples):
270
+ def determine_biases(self, n_samples: int) -> None:
272
271
  """Record n data samples (n_samples) to determine bias.
273
272
  Afterwards recording is in pause mode
274
273
 
@@ -289,12 +288,12 @@ class DataRecorder(object):
289
288
  for x in self._force_sensor_processes:
290
289
  x.event_bias_is_available.wait()
291
290
 
292
- def open_data_file(self, filename,
293
- subdirectory="data",
294
- time_stamp_filename=False,
295
- varnames = True,
296
- comment_line="",
297
- zipped=False):
291
+ def open_data_file(self, filename: str,
292
+ subdirectory: str = "data",
293
+ time_stamp_filename: bool = False,
294
+ varnames: bool = True,
295
+ comment_line: str = "",
296
+ zipped: bool = False) -> Path:
298
297
  """Create a data file
299
298
 
300
299
  Only if data file has been opened, data will be saved!
@@ -322,11 +321,8 @@ class DataRecorder(object):
322
321
  full path the actually used file (incl. timestamp)
323
322
 
324
323
  """
325
-
326
- base_dir = os.path.split(sys.argv[0])[0]
327
- data_dir = os.path.join(base_dir, subdirectory)
328
- if not os.path.isdir(data_dir):
329
- os.mkdir(data_dir)
324
+ data_dir = Path.cwd() / subdirectory
325
+ data_dir.mkdir(exist_ok=True)
330
326
  self.close_data_file()
331
327
 
332
328
  if filename is None or len(filename) == 0:
@@ -352,8 +348,8 @@ class DataRecorder(object):
352
348
  else:
353
349
  self.filename = flname + suffix
354
350
 
355
- full_path_file = os.path.join(data_dir, self.filename)
356
- if os.path.isfile(full_path_file):
351
+ full_path_file = data_dir / self.filename
352
+ if full_path_file.is_file():
357
353
  # print "data file already exists, adding counter"
358
354
  cnt += 1
359
355
  else:
@@ -388,7 +384,7 @@ class DataRecorder(object):
388
384
 
389
385
  return full_path_file
390
386
 
391
- def close_data_file(self):
387
+ def close_data_file(self) -> None:
392
388
  """Close the data file
393
389
 
394
390
  Afterwards data will not be saved anymore.
@@ -7,11 +7,12 @@ __author__ = 'Oliver Lindemann'
7
7
 
8
8
  import ctypes as ct
9
9
  from copy import copy
10
+ from pathlib import Path
10
11
 
11
12
  import numpy as np
13
+ from icecream import ic
12
14
 
13
15
  #from .._lib import lsl
14
- from .._lib.misc import find_calibration_file
15
16
  from .._lib.timer import Timer, app_clock
16
17
  from .._lib.types import ForceSensorData
17
18
  from ..daq import ATI_CDLL, DAQConfiguration, DAQReadAnalog
@@ -22,7 +23,7 @@ class SensorSettings(DAQConfiguration):
22
23
  def __init__(self,
23
24
  device_id:int,
24
25
  sensor_name:str,
25
- calibration_folder:str,
26
+ calibration_file:str | Path,
26
27
  channels="ai0:7",
27
28
  device_name_prefix = "Dev",
28
29
  rate:int=1000,
@@ -62,13 +63,7 @@ class SensorSettings(DAQConfiguration):
62
63
  self.write_Tz = write_Tz
63
64
  self.write_trigger1 = write_trigger1
64
65
  self.write_trigger2 = write_trigger2
65
-
66
- if self.convert_to_FT:
67
- self.calibration_file = find_calibration_file(
68
- calibration_folder=calibration_folder,
69
- sensor_name=sensor_name)
70
- else:
71
- self.calibration_file = None
66
+ self.calibration_file = calibration_file
72
67
 
73
68
  self.reverse_parameters = []
74
69
  if not isinstance(reverse_parameter_names, (tuple, list)):
@@ -105,7 +100,8 @@ class Sensor(DAQReadAnalog):
105
100
  self.name = settings.sensor_name
106
101
  self.convert_to_FT = settings.convert_to_FT
107
102
  self.timer = Timer(sync_timer=app_clock) # own timer, because this class is used in own process
108
- if self.DAQ_TYPE == "mock":
103
+ ic(self.DAQ_TYPE)
104
+ if self.DAQ_TYPE == "mock_sensor":
109
105
  self._atidaq = None
110
106
  self.convert_to_FT = False
111
107
  else:
@@ -1,6 +1,6 @@
1
1
  from ._run import (
2
- run,
3
- run_with_options, # for running with options from Python script
2
+ run, # for running with options from Python script
3
+ run_settings,
4
4
  )
5
5
  from ._settings import settings ## read settings
6
6
 
pyforcedaq/gui/_run.py CHANGED
@@ -5,7 +5,9 @@ See COPYING file distributed along with the pyForceDAQ copyright and license ter
5
5
  __author__ = "Oliver Lindemann"
6
6
 
7
7
  import logging
8
+ from os import path
8
9
  from pickle import dumps
10
+ from typing import List
9
11
 
10
12
  import numpy as np
11
13
  import pygame
@@ -342,16 +344,16 @@ def _main_loop(exp, recorder, remote_control=False):
342
344
  plotter_thread.join()
343
345
  recorder.pause_recording(s.background)
344
346
 
345
- def run(settings_file: str | None = None):
347
+ def run_settings(settings_file: str | None = None):
346
348
 
347
349
  if settings_file is not None and len(settings_file) > 0:
348
350
  # load different settings file if specified
349
351
  settings.load(settings_file)
350
352
 
351
- return run_with_options(remote_control = settings.recording.remote_control,
353
+ return run(remote_control = settings.recording.remote_control,
352
354
  ask_filename = settings.recording.ask_filename,
353
355
  device_ids = settings.recording.device_ids,
354
- sensor_names = settings.recording.sensor_names,
356
+ calibration_files = settings.recording.calibration_files,
355
357
  calibration_folder = settings.recording.calibration_folder,
356
358
  device_name_prefix = settings.recording.device_name_prefix,
357
359
  write_Fx = settings.recording.write_Fx,
@@ -368,25 +370,25 @@ def run(settings_file: str | None = None):
368
370
  has_lsl_stream=settings.recording.has_lsl_stream,
369
371
  polling_priority=settings.recording.priority)
370
372
 
371
- def run_with_options(remote_control,
373
+ def run(remote_control,
372
374
  ask_filename,
373
- device_ids,
374
- sensor_names,
375
- calibration_folder,
376
- device_name_prefix="Dev",
377
- write_Fx = True,
378
- write_Fy = True,
379
- write_Fz = True,
380
- write_Tx = False,
381
- write_Ty = False,
382
- write_Tz = False,
383
- write_trigger1 = True,
384
- write_trigger2 = False,
385
- zip_data=False,
386
- reverse_scaling = None,
387
- convert_to_forces = True,
388
- has_lsl_stream = False,
389
- polling_priority = None):
375
+ device_ids : int | List[int],
376
+ calibration_files : str | List[str],
377
+ calibration_folder: str,
378
+ device_name_prefix: str="Dev",
379
+ write_Fx: bool = True,
380
+ write_Fy: bool = True,
381
+ write_Fz: bool = True,
382
+ write_Tx: bool = False,
383
+ write_Ty: bool = False,
384
+ write_Tz: bool = False,
385
+ write_trigger1 : bool = True,
386
+ write_trigger2: bool = False,
387
+ zip_data: bool = False,
388
+ reverse_scaling: dict | None = None,
389
+ convert_to_forces: bool = True,
390
+ has_lsl_stream: bool = False,
391
+ polling_priority: str | None = None):
390
392
 
391
393
  """start gui
392
394
  remote_control should be None (ask) or True or False
@@ -401,27 +403,30 @@ def run_with_options(remote_control,
401
403
  """
402
404
  #
403
405
 
404
- logging.info("New Recording with forceDAQ {}".format(forceDAQVersion))
405
- logging.info("Sensors {}".format(sensor_names))
406
- logging.info("Settings " + settings.recording_as_json())
406
+ logging.info("New Recording with forceDAQ %s", forceDAQVersion)
407
+ logging.info("Sensors %s", calibration_files)
408
+ logging.info("Settings %s", settings.recording_as_json())
407
409
 
408
410
 
409
411
  if not isinstance(device_ids, (list, tuple)):
410
412
  device_ids = [device_ids]
411
- if not isinstance(sensor_names, (list, tuple)):
412
- sensor_names = [sensor_names]
413
+ if not isinstance(calibration_files, (list, tuple)):
414
+ calibration_files = [calibration_files]
413
415
 
414
416
  sensors = []
415
- for d_id, sn in zip(device_ids, sensor_names):
416
- try:
417
- reverse_parameter_names = reverse_scaling[str(d_id)]
418
- except:
417
+ for d_id, cal_file in zip(device_ids, calibration_files):
418
+ if reverse_scaling is None:
419
419
  reverse_parameter_names = []
420
+ else:
421
+ try:
422
+ reverse_parameter_names = reverse_scaling[str(d_id)]
423
+ except KeyError:
424
+ reverse_parameter_names = []
420
425
 
421
426
  ss = SensorSettings(device_id = d_id,
422
427
  device_name_prefix=device_name_prefix,
423
- sensor_name = sn,
424
- calibration_folder=calibration_folder,
428
+ sensor_name = cal_file.split(".")[0],
429
+ calibration_file=path.join(calibration_folder, cal_file),
425
430
  reverse_parameter_names=reverse_parameter_names,
426
431
  rate = settings.gui.sampling_rate,
427
432
  convert_to_FT=convert_to_forces,
@@ -436,11 +441,8 @@ def run_with_options(remote_control,
436
441
  write_trigger2= write_trigger2)
437
442
  sensors.append(ss)
438
443
 
439
-
440
-
441
444
  # expyriment
442
- control.defaults.initialize_delay = 0
443
- control.defaults.pause_key = None
445
+ control.defaults.initialise_delay = 0
444
446
  control.defaults.window_mode = True
445
447
  control.defaults.window_size = (1000, 700)
446
448
  control.defaults.fast_quit = True
@@ -1,65 +1,80 @@
1
- import collections
2
1
  import json
3
2
  import os
3
+ from copy import deepcopy
4
+ from dataclasses import dataclass, field
5
+ from typing import List
4
6
 
5
7
  import tomlkit
6
-
7
- _GUISettings = collections.namedtuple('GUISettings', 'sampling_rate '
8
- 'level_detection_parameter window_font moving_average_size '
9
- 'screen_refresh_interval_indicator gui_screen_refresh_interval_plotter '
10
- 'data_min_max plotter_pixel_min_max indicator_pixel_min_max plot_axis '
11
- 'plot_data_indicator_for_single_sensor plot_data_plotter_for_single_sensor '
12
- 'plot_data_indicator_for_two_sensors plot_data_plotter_for_two_sensors')
13
-
14
- _RecordingSetting = collections.namedtuple('RecordingSetting',
15
- 'device_name_prefix device_ids sensor_names remote_control '
16
- 'ask_filename calibration_folder '
17
- ' zip_data write_Fx write_Fy '
18
- 'write_Fz write_Tx write_Ty write_Tz write_trigger1 '
19
- 'write_trigger2 has_lsl_stream reverse_scaling convert_to_forces priority')
8
+ from icecream import ic
9
+
10
+
11
+ @dataclass
12
+ class _GUISettings:
13
+ sampling_rate: int = 1000
14
+ level_detection_parameter: str = "Fz"
15
+ window_font: str = "freemono"
16
+ moving_average_size: int = 5
17
+ screen_refresh_interval_indicator: int = 300
18
+ gui_screen_refresh_interval_plotter: int = 50
19
+ data_min_max: list = field(default_factory=lambda: [-5, 30])
20
+ plotter_pixel_min_max: list = field(default_factory=lambda: [-250, 250])
21
+ indicator_pixel_min_max: list = field(default_factory=lambda: [-150, 150])
22
+ plot_axis: bool = False
23
+ plot_data_indicator_for_single_sensor: list = field(
24
+ default_factory=lambda: [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5)])
25
+ plot_data_plotter_for_single_sensor: list = field(
26
+ default_factory=lambda: [(0, 0), (0, 1), (0, 2)])
27
+ plot_data_indicator_for_two_sensors: list = field(
28
+ default_factory=lambda: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)])
29
+ plot_data_plotter_for_two_sensors: list = field(
30
+ default_factory=lambda: [(0, 2), (1, 2)])
31
+
32
+ def update_from_dict(self, d):
33
+ for key, value in d.items():
34
+ setattr(self, key, value)
35
+
36
+ @dataclass
37
+ class _RecordingSetting:
38
+ device_name_prefix: str = "Dev"
39
+ device_ids: List[int] = field(default_factory=lambda: [1])
40
+ ask_filename: bool = False
41
+ remote_control: bool = False
42
+ calibration_folder: str = "calibration"
43
+ calibration_files: List[str] = field(default_factory=lambda: ["FT9334.cal"])
44
+ zip_data: bool = True
45
+ write_Fx: bool = True
46
+ write_Fy: bool = True
47
+ write_Fz: bool = True
48
+ write_Tx: bool = False
49
+ write_Ty: bool = False
50
+ write_Tz: bool = False
51
+ write_trigger1: bool = True
52
+ write_trigger2: bool = False
53
+ has_lsl_stream: bool = False
54
+ reverse_scaling: dict = field(default_factory=lambda: {"1": ["Fz"], "2": ["Fz"]})
55
+ convert_to_forces: bool = True
56
+ priority: str = "normal"
57
+
58
+ def __post_init__(self):
59
+ if isinstance(self.device_ids, int):
60
+ self.device_ids = [self.device_ids]
61
+ if isinstance(self.calibration_files, str):
62
+ self.calibration_files = [self.calibration_files]
63
+
64
+ def update_from_dict(self, d):
65
+ for key, value in d.items():
66
+ ic(key, value)
67
+ setattr(self, key, value)
20
68
 
21
69
 
22
70
  class GUISettings(object):
23
71
 
24
72
  def __init__(self, filename):
25
-
26
73
  # defaults
27
- self.gui = _GUISettings(
28
- sampling_rate = 1000,
29
- level_detection_parameter = "Fz",
30
- window_font = "freemono",
31
- moving_average_size = 5,
32
- screen_refresh_interval_indicator = 300,
33
- gui_screen_refresh_interval_plotter = 50,
34
- data_min_max = [-5, 30],
35
- plotter_pixel_min_max = [-250, 250],
36
- indicator_pixel_min_max = [-150, 150],
37
- plot_axis = False,
38
- plot_data_indicator_for_single_sensor = [(0, 0), (0, 1), (0, 2), (0, 3),
39
- (0, 4), (0, 5)], # sensor, parameter
40
- plot_data_plotter_for_single_sensor = [(0, 0), (0, 1), (0, 2)],
41
- # plotter can't plot torques # TODO
42
-
43
- plot_data_indicator_for_two_sensors = [(0, 0), (0, 1), (0, 2), (1, 0),
44
- (1, 1), (1, 2)], # sensor,
45
- # parameter
46
- plot_data_plotter_for_two_sensors = [(0, 2),
47
- (1, 2)],
48
- # plotter can't plot torques
49
- )
74
+ self.gui = _GUISettings()
50
75
  self.gui_section = "GUI"
51
76
 
52
- self.recording = _RecordingSetting(device_name_prefix="Dev",
53
- device_ids = [1],
54
- sensor_names = ["FT9334"],
55
- calibration_folder="calibration",
56
- reverse_scaling = {"1": ["Fz"], "2":["Fz"]}, # key: device_id, parameter. E.g.:if x & z dimension of sensor 1 and z dimension of sensor 2 has to be flipped use {1: ["Fx", "Fz"], 2: ["Fz"]}
57
- remote_control=False, ask_filename= False, write_Fx=True,
58
- write_Fy=True, write_Fz=True, write_Tx=False, write_Ty=False,
59
- write_Tz=False, write_trigger1=True, write_trigger2=False,
60
- has_lsl_stream=False,
61
- zip_data=True, convert_to_forces=True,
62
- priority='normal') # default recording settings
77
+ self.recording = _RecordingSetting()
63
78
  self.recording_section = "Recording"
64
79
 
65
80
  self.filename = filename
@@ -69,30 +84,28 @@ class GUISettings(object):
69
84
  self.save() # defaults
70
85
 
71
86
  def _asdict(self):
72
- return {self.recording_section: self.recording._asdict(),
73
- self.gui_section: self.gui._asdict()}
87
+ return {self.recording_section: self.recording.__dict__,
88
+ self.gui_section: self.gui.__dict__}
74
89
 
75
90
  def set_gui_settings(self, gui_setting_dict):
76
91
  self.gui = _GUISettings(**gui_setting_dict)
77
92
 
78
- def set_recoding_setting(self, recording_setting_dict):
93
+ def set_recording_setting(self, recording_setting_dict):
79
94
  self.recording = _RecordingSetting(**recording_setting_dict)
80
95
 
81
96
  def load(self, filename=None):
82
97
  if filename is not None:
83
98
  self.filename = filename
84
- with open(self.filename, 'r') as fl:
99
+ with open(self.filename, 'r', encoding='utf-8') as fl:
85
100
  d = tomlkit.load(fl)
86
101
  self.set_gui_settings(d[self.gui_section])
87
- self.set_recoding_setting(d[self.recording_section])
88
-
102
+ self.set_recording_setting(d[self.recording_section])
89
103
 
90
104
  def save(self):
91
- with open(self.filename, 'w') as fl:
105
+ with open(self.filename, 'w', encoding='utf-8') as fl:
92
106
  tomlkit.dump(self._asdict(), fl)
93
107
 
94
-
95
108
  def recording_as_json(self):
96
- return json.dumps(self.recording._asdict())
109
+ return json.dumps(self.recording.__dict__)
97
110
 
98
- settings = GUISettings(filename="pyForceDAQ.defaults.settings.toml")
111
+ settings = GUISettings(filename="pyForceDAQ.defaults.settings.toml")
@@ -1,13 +1,13 @@
1
1
  import sys
2
2
  from os import path
3
+ from typing import List
3
4
 
4
5
  import FreeSimpleGUI as _sg
5
6
 
6
7
  from .. import USE_MOCK_SENSOR, __version__
7
- from .._lib.misc import find_calibration_file
8
8
  from .._lib.types import PollingPriority
9
9
  from .._lib.udp_connection import UDPConnection
10
- from ._run import run as _gui_run
10
+ from ._run import run_settings as _gui_run
11
11
  from ._settings import settings
12
12
 
13
13
 
@@ -37,23 +37,25 @@ def _s2l(csv_string, is_integer=False, is_float=False): # convert csv string to
37
37
  return rtn
38
38
 
39
39
 
40
- def _check_sensor_calibration_settings(device_ids, sensor_names,
41
- calibration_folder):
40
+ def _check_sensor_calibration_settings(device_ids: List[int],
41
+ calibrations_files : List[str],
42
+ calibration_folder :str):
42
43
  rtn = []
43
44
  for x, d_id in enumerate(device_ids):
44
45
  error = False
45
46
  try:
46
- sensor_name = sensor_names[x]
47
- except:
48
- sensor_name = "??"
49
- error = True
50
- try:
51
- cal = find_calibration_file(calibration_folder=calibration_folder,
52
- sensor_name=sensor_name)
53
- except:
54
- cal = "NO CALIBRATION"
47
+ cal_file = calibrations_files[x]
48
+ except KeyError:
49
+ cal_file = "??"
55
50
  error = True
56
- rtn.append([d_id, sensor_name, cal, error])
51
+
52
+ if not error:
53
+ cal = path.join(calibration_folder, cal_file)
54
+ if not path.isfile(cal):
55
+ cal = "NOT FOUND"
56
+ error = True
57
+
58
+ rtn.append([d_id, cal_file, cal, error])
57
59
 
58
60
  return rtn
59
61
 
@@ -68,7 +70,7 @@ def _windows_run():
68
70
 
69
71
  for d_id, name, cal, error in _check_sensor_calibration_settings(
70
72
  s.device_ids,
71
- s.sensor_names,
73
+ s.calibration_files,
72
74
  s.calibration_folder):
73
75
  if error:
74
76
  col = "red"
@@ -135,8 +137,8 @@ def _window_settings():
135
137
  [[_sg.Text("Folder:", size=(5, 1)), _sg.InputText(
136
138
  s.calibration_folder, size=(23, 1), key="cal_dir"),
137
139
  _sg.FolderBrowse(size=(6, 1))],
138
- _input_text_list("Sensor Names:", s.sensor_names,
139
- key="sensor_names")
140
+ _input_text_list("Cal-files:", s.calibration_files,
141
+ key="calibration_files")
140
142
  ])])
141
143
 
142
144
  layout.append([_sg.Frame('Record Forces & Torques',
@@ -190,7 +192,7 @@ def _window_settings():
190
192
  except:
191
193
  event = "Error"
192
194
 
193
- key = "sensor_names"
195
+ key = "calibration_files"
194
196
  try:
195
197
  d[key] = _s2l(values[key])
196
198
  except:
@@ -207,7 +209,7 @@ def _window_settings():
207
209
  main_path = path.split(sys.modules['__main__'].__file__)[0] + path.sep
208
210
  d["calibration_folder"] = values["cal_dir"].replace(main_path, "")
209
211
 
210
- settings.set_recoding_setting(d)
212
+ settings.set_recording_setting(d)
211
213
  settings.save()
212
214
 
213
215
  window.close()
@@ -220,9 +222,8 @@ def run():
220
222
  s = settings.recording
221
223
  settings_error = False
222
224
  n_sensor = len(s.device_ids)
223
- if n_sensor != len(s.sensor_names):
224
- _sg.PopupError("Number of devices IDs and sensor names are "
225
- "not equal.")
225
+ if n_sensor != len(s.calibration_files):
226
+ _sg.PopupError("Number of devices IDs and calibration files are not equal.")
226
227
  settings_error = True
227
228
 
228
229
  if not path.isdir(s.calibration_folder):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyForceDAQ
3
- Version: 2.0.0.dev0
3
+ Version: 2.0.1.dev1
4
4
  Summary: A Python package for data acquisition and analysis in force-based experiments.
5
5
  Author: Oliver Lindemann
6
6
  Author-email: Oliver Lindemann <lindemann@essb.eur.nl>
@@ -1,18 +1,18 @@
1
- pyforcedaq/__init__.py,sha256=3HvOhmYl8G5Z6JTbI_N4HE00d6YF2HnzGclza4z0qUY,1164
2
- pyforcedaq/__main__.py,sha256=c6QAtgcrP231FssQXHoLSD5q23u-sSMDAEZU_ilUw8E,1029
1
+ pyforcedaq/__init__.py,sha256=esQLa14fkmOHX5vEjv9AGAB6x5ETZ-EbTSDSZNSSoEw,1151
2
+ pyforcedaq/__main__.py,sha256=TkcXcjMoypKTpi5cmG5yfJRaRHzpAGuMyRysl1bPLZ4,1002
3
3
  pyforcedaq/_lib/__init__.py,sha256=GBiextmC_Xz9iMQlLBnU1qsw7YFVQaiZ8nV5ln3B7Wk,32
4
4
  pyforcedaq/_lib/lsl.py,sha256=6bLniyIy2hWB36-uclrO-9WJZogV2PoY1Lt2qq5JaR4,1520
5
- pyforcedaq/_lib/misc.py,sha256=13XJePZPYEkTuDbtoM7rWC4Abih8Eils1Jsh6f_05hQ,4033
5
+ pyforcedaq/_lib/misc.py,sha256=YiG2fTac9YFYgWZac4iQ1j7BBhFo-y80-231xk1Gzds,4622
6
6
  pyforcedaq/_lib/polling_time_profile.py,sha256=5EHSWMVii-bEKk6dkuClH6OZnbSSJjrvW6hIfizS988,1487
7
7
  pyforcedaq/_lib/process_priority_manager.py,sha256=3povqR0hT54K9TRQtxk-rc8JPakT3K6PH4Np8pNgydo,4196
8
8
  pyforcedaq/_lib/timer.py,sha256=MN192NvqxezW-C5-znse9p-sv0DdoPV6jVN3X8d6CYY,1111
9
- pyforcedaq/_lib/types.py,sha256=TQMSeSy6xl0yYs_CM-QPHu398jnkYzNk_msNEWYDeLQ,11963
9
+ pyforcedaq/_lib/types.py,sha256=haJORth-LE38G2bUpZJ7oudd_UUjH6HVRANiAbBNABs,11978
10
10
  pyforcedaq/_lib/udp_connection.py,sha256=k6Ww8n9r7PdOzC0AJmzs-sC9eW8Jnij3EyUR0ASJHas,10254
11
- pyforcedaq/daq/__init__.py,sha256=xs5gwGrSuYTpQlHMin_x8xCZ9o1Z1FsYyStuNgVhNvc,652
12
- pyforcedaq/daq/_daq_read_Analog_pydaqmx.py,sha256=0jtLoY82CBq1UxoOQMaCylKAOs_AzpK6mL2UUIdkhsw,3568
13
- pyforcedaq/daq/_daq_read_analog_nidaqmx.py,sha256=MHUC83UnKbHYAlNWr5iuTFoGYJpSfB21cxkm41qS_Vg,2459
11
+ pyforcedaq/daq/__init__.py,sha256=ZrRK8xFcoi523Rk9I7DQcY-LyCm21hFcmQOXP7VwwYw,716
14
12
  pyforcedaq/daq/_mock_sensor.py,sha256=GsNKDz87lAUIF8eRyP18s9b3gQy6WzL1r3sbKa1fur8,2076
15
- pyforcedaq/daq/_pyATIDAQ.py,sha256=AT0RxNcWHp1qaeCL0Gd0UZ9CmegVrumoDzDk1CWJ9lA,11211
13
+ pyforcedaq/daq/_pyATIDAQ.py,sha256=IqTdz2nAxEC8ea_u9OQvvCmT-fbOwkP85FBHV3gyIfQ,11142
14
+ pyforcedaq/daq/_use_nidaqmx.py,sha256=MHUC83UnKbHYAlNWr5iuTFoGYJpSfB21cxkm41qS_Vg,2459
15
+ pyforcedaq/daq/_use_pydaqmx.py,sha256=0jtLoY82CBq1UxoOQMaCylKAOs_AzpK6mL2UUIdkhsw,3568
16
16
  pyforcedaq/daq/config.py,sha256=JinPGtz4WYBj8uLT9LZkzQq-fSe11st8A0acrjJ015o,481
17
17
  pyforcedaq/extras/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  pyforcedaq/extras/convert.py,sha256=N8r5gl0Te3GHafkggeC4btFD94nUwBzM9cctH1jiSEA,8601
@@ -22,21 +22,21 @@ pyforcedaq/extras/read_force_data.py,sha256=ZjrEHexz40OW8L8JlRFgAFxQuBAS8c66t2-j
22
22
  pyforcedaq/extras/remote_control.py,sha256=2Ka9Y6edTAnsIY-P46rzyLDj9ddOc51n4cJ2Mma_cKg,2204
23
23
  pyforcedaq/force/__init__.py,sha256=h9pQxFkwt_xOs1hrTYCiEPFr1Cg2XblxwyKEDuKH8rs,346
24
24
  pyforcedaq/force/_log.py,sha256=h2JbbLLJsrrh1U9HwEbY7iFdRW7FYxDbiZuIq5Z3sE0,541
25
- pyforcedaq/force/data_recorder.py,sha256=3JYhaNfewwKDNQxL70IJ5o0FKO49vcUH331K2udOrY8,12817
26
- pyforcedaq/force/sensor.py,sha256=-kvgXQJt524qVESKYzJhR9-il5NFzG0ybWNGA215Ouw,7010
25
+ pyforcedaq/force/data_recorder.py,sha256=7hWM7WKD94uEv57_R1RydJwf7HAQBRyNN3gDRcN9cRc,12939
26
+ pyforcedaq/force/sensor.py,sha256=ZdeK6pEedEosrk_4SlG3mEOji6zBRaopSg0oEV6ZBM8,6810
27
27
  pyforcedaq/force/sensor_process.py,sha256=gBZ4B3Z7CDz87QISUbMJ0tsSf-SBT1rbl3dxc0Eo-To,9319
28
- pyforcedaq/gui/__init__.py,sha256=4I96AJjZvVy3-HHl4XAhDLfwqHF5BzLWNxYjSr312L8,151
28
+ pyforcedaq/gui/__init__.py,sha256=bB1kI51Oi3fK-x_J7ncaN8yZpvai-5-3sp7UHqDr-GY,147
29
29
  pyforcedaq/gui/_gui_status.py,sha256=0YJcxVX2G8VtbgRn0H9avZi1wY4R-1A8re3cJjojkl0,13987
30
30
  pyforcedaq/gui/_layout.py,sha256=obptKZgw9CgygiqDCDgbXu4Esyfb8btOZgxxdNzgXiE,4616
31
31
  pyforcedaq/gui/_level_indicator.py,sha256=cBB-5DOlvdc95rQQ12Gt5dvhNxSYQTbaq19FSdz4YnQ,1905
32
32
  pyforcedaq/gui/_pg_surface.py,sha256=TD4rQJsBMMiKoQDZTon35LvsEmyayCWfklJbm0iRl6c,2902
33
33
  pyforcedaq/gui/_plotter.py,sha256=KvSxg3M3mDRj0_oNtn6mll8D2LBrBoboNoUs9hJJSUs,8451
34
- pyforcedaq/gui/_run.py,sha256=E8VZWBfocUnG7--OAU-mZLWmbswduoggL2NlpuaxgHU,23053
34
+ pyforcedaq/gui/_run.py,sha256=9IsWsnVVcRmk12aBxMPDVmNB0QcFLHVivpVIHBVQ8yg,23368
35
35
  pyforcedaq/gui/_scaling.py,sha256=XgdB7CXqzrBXNFT1Kul8t7mebqO9gojNxGzNIppj4Bg,1905
36
- pyforcedaq/gui/_settings.py,sha256=fFq8icXqQpT-LOCAqw2gkveWT_yVkg03tZvjFILRBaI,4173
36
+ pyforcedaq/gui/_settings.py,sha256=rSn3OgOx7mTkS7RCH_v7YPhugTKsDivmKqgzE1FvPOI,3772
37
37
  pyforcedaq/gui/forceDAQ_logo.png,sha256=-bn6ZQQjKf2Pxd9mJ4r-wulibtjuv_bEkhG567GR1vc,15624
38
- pyforcedaq/gui/launcher.py,sha256=pC7-NgEBscisb9HnebTSbT0Lerh4duFYcy98_Uv85YE,8732
39
- pyforcedaq-2.0.0.dev0.dist-info/WHEEL,sha256=i9aSRDivn5iP9LaR1BLQX2GNAuriQWPsFwbbWygTX2k,81
40
- pyforcedaq-2.0.0.dev0.dist-info/entry_points.txt,sha256=0VDGqAldPs3uUCun3y9v4ue8Uae8n-D6-R5YpamgJwQ,56
41
- pyforcedaq-2.0.0.dev0.dist-info/METADATA,sha256=rg5zp6zF47H8gqoar0qngPRgqjjPWrWnjWnulFyx-JU,601
42
- pyforcedaq-2.0.0.dev0.dist-info/RECORD,,
38
+ pyforcedaq/gui/launcher.py,sha256=5IjHTCU65bsoctr52k-w9L6MBTJOW4gN6Wm0PItUwX0,8753
39
+ pyforcedaq-2.0.1.dev1.dist-info/WHEEL,sha256=i9aSRDivn5iP9LaR1BLQX2GNAuriQWPsFwbbWygTX2k,81
40
+ pyforcedaq-2.0.1.dev1.dist-info/entry_points.txt,sha256=0VDGqAldPs3uUCun3y9v4ue8Uae8n-D6-R5YpamgJwQ,56
41
+ pyforcedaq-2.0.1.dev1.dist-info/METADATA,sha256=4RVrVMtGkSX5ibhek7BBHpWW4P25Qikz70QB2hk0VxQ,601
42
+ pyforcedaq-2.0.1.dev1.dist-info/RECORD,,