ephys-link 2.0.0__py3-none-any.whl → 2.0.0b2__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.
- ephys_link/__about__.py +1 -1
- ephys_link/__main__.py +43 -51
- ephys_link/back_end/platform_handler.py +298 -315
- ephys_link/back_end/server.py +202 -274
- ephys_link/bindings/{fake_binding.py → fake_bindings.py} +54 -84
- ephys_link/bindings/ump_4_bindings.py +125 -0
- ephys_link/front_end/cli.py +98 -104
- ephys_link/front_end/gui.py +215 -204
- ephys_link/resources/CP210xManufacturing.dll +0 -0
- ephys_link/resources/NstMotorCtrl.dll +0 -0
- ephys_link/resources/SiUSBXp.dll +0 -0
- ephys_link/{utils/base_binding.py → util/base_bindings.py} +133 -176
- ephys_link/util/common.py +120 -0
- ephys_link/{utils → util}/console.py +133 -127
- ephys_link-2.0.0b2.dist-info/METADATA +167 -0
- ephys_link-2.0.0b2.dist-info/RECORD +25 -0
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/WHEEL +1 -1
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/licenses/LICENSE +674 -674
- ephys_link/bindings/mpm_binding.py +0 -315
- ephys_link/bindings/ump_4_binding.py +0 -157
- ephys_link/utils/constants.py +0 -23
- ephys_link/utils/converters.py +0 -86
- ephys_link/utils/startup.py +0 -65
- ephys_link-2.0.0.dist-info/METADATA +0 -91
- ephys_link-2.0.0.dist-info/RECORD +0 -25
- /ephys_link/{utils → util}/__init__.py +0 -0
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/entry_points.txt +0 -0
ephys_link/front_end/gui.py
CHANGED
|
@@ -1,204 +1,215 @@
|
|
|
1
|
-
"""Graphical User Interface for Ephys Link.
|
|
2
|
-
|
|
3
|
-
Usage:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
from
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
self.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
ttk.Label(server_serving_settings, text=
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
ttk.
|
|
120
|
-
column=
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
ttk.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
variable=self.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
ttk.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
""
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
1
|
+
"""Graphical User Interface for Ephys Link.
|
|
2
|
+
|
|
3
|
+
Usage: create a GUI instance and call get_options() to get the options.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from json import load
|
|
7
|
+
from os import makedirs
|
|
8
|
+
from os.path import exists, join
|
|
9
|
+
from socket import gethostbyname, gethostname
|
|
10
|
+
from sys import exit
|
|
11
|
+
from tkinter import CENTER, RIGHT, BooleanVar, E, IntVar, StringVar, Tk, ttk
|
|
12
|
+
|
|
13
|
+
from platformdirs import user_config_dir
|
|
14
|
+
from vbl_aquarium.models.ephys_link import EphysLinkOptions
|
|
15
|
+
|
|
16
|
+
from ephys_link.__about__ import __version__ as version
|
|
17
|
+
|
|
18
|
+
# Define options path.
|
|
19
|
+
OPTIONS_DIR = join(user_config_dir(), "VBL", "Ephys Link")
|
|
20
|
+
OPTIONS_FILENAME = "options.json"
|
|
21
|
+
OPTIONS_PATH = join(OPTIONS_DIR, OPTIONS_FILENAME)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GUI:
|
|
25
|
+
"""Graphical User Interface for Ephys Link.
|
|
26
|
+
|
|
27
|
+
Gathers options from the user and saves them to a file.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
"""Setup GUI properties."""
|
|
32
|
+
|
|
33
|
+
self._root = Tk()
|
|
34
|
+
|
|
35
|
+
# Create default options.
|
|
36
|
+
options = EphysLinkOptions()
|
|
37
|
+
|
|
38
|
+
# Read options.
|
|
39
|
+
if exists(OPTIONS_PATH):
|
|
40
|
+
with open(OPTIONS_PATH) as options_file:
|
|
41
|
+
options = EphysLinkOptions(**load(options_file))
|
|
42
|
+
|
|
43
|
+
# Load options into GUI variables.
|
|
44
|
+
self._ignore_updates = BooleanVar(value=options.ignore_updates)
|
|
45
|
+
self._type = StringVar(value=options.type)
|
|
46
|
+
self._debug = BooleanVar(value=options.debug)
|
|
47
|
+
self._use_proxy = BooleanVar(value=options.use_proxy)
|
|
48
|
+
self._proxy_address = StringVar(value=options.proxy_address)
|
|
49
|
+
self._mpm_port = IntVar(value=options.mpm_port)
|
|
50
|
+
self._serial = StringVar(value=options.serial)
|
|
51
|
+
|
|
52
|
+
# Submit flag.
|
|
53
|
+
self._submit = False
|
|
54
|
+
|
|
55
|
+
def get_options(self) -> EphysLinkOptions:
|
|
56
|
+
"""Get options from GUI."""
|
|
57
|
+
|
|
58
|
+
# Launch GUI.
|
|
59
|
+
self._build_gui()
|
|
60
|
+
self._root.mainloop()
|
|
61
|
+
|
|
62
|
+
# Exit if the user did not submit options.
|
|
63
|
+
if not self._submit:
|
|
64
|
+
exit(1)
|
|
65
|
+
|
|
66
|
+
# Extract options from GUI.
|
|
67
|
+
options = EphysLinkOptions(
|
|
68
|
+
ignore_updates=self._ignore_updates.get(),
|
|
69
|
+
type=self._type.get(),
|
|
70
|
+
debug=self._debug.get(),
|
|
71
|
+
use_proxy=self._use_proxy.get(),
|
|
72
|
+
proxy_address=self._proxy_address.get(),
|
|
73
|
+
mpm_port=self._mpm_port.get(),
|
|
74
|
+
serial=self._serial.get(),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Save options.
|
|
78
|
+
makedirs(OPTIONS_DIR, exist_ok=True)
|
|
79
|
+
with open(OPTIONS_PATH, "w+") as options_file:
|
|
80
|
+
options_file.write(options.model_dump_json())
|
|
81
|
+
|
|
82
|
+
# Return options
|
|
83
|
+
return options
|
|
84
|
+
|
|
85
|
+
def _build_gui(self) -> None:
|
|
86
|
+
"""Build GUI."""
|
|
87
|
+
|
|
88
|
+
self._root.title(f"Ephys Link v{version}")
|
|
89
|
+
|
|
90
|
+
mainframe = ttk.Frame(self._root, padding=3)
|
|
91
|
+
mainframe.grid(column=0, row=0, sticky="news")
|
|
92
|
+
self._root.columnconfigure(0, weight=1)
|
|
93
|
+
self._root.rowconfigure(0, weight=1)
|
|
94
|
+
mainframe.columnconfigure(0, weight=1)
|
|
95
|
+
mainframe.rowconfigure(0, weight=1)
|
|
96
|
+
|
|
97
|
+
# Server serving settings.
|
|
98
|
+
|
|
99
|
+
server_serving_settings = ttk.LabelFrame(mainframe, text="Serving Settings", padding=3)
|
|
100
|
+
server_serving_settings.grid(column=0, row=0, sticky="news")
|
|
101
|
+
|
|
102
|
+
# Local IP.
|
|
103
|
+
ttk.Label(server_serving_settings, text="Local IP:", anchor=E, justify=RIGHT).grid(column=0, row=0, sticky="we")
|
|
104
|
+
ttk.Label(server_serving_settings, text=gethostbyname(gethostname())).grid(column=1, row=0, sticky="we")
|
|
105
|
+
|
|
106
|
+
# Proxy.
|
|
107
|
+
ttk.Label(server_serving_settings, text="Use Proxy:", anchor=E, justify=RIGHT).grid(
|
|
108
|
+
column=0, row=1, sticky="we"
|
|
109
|
+
)
|
|
110
|
+
ttk.Checkbutton(
|
|
111
|
+
server_serving_settings,
|
|
112
|
+
variable=self._use_proxy,
|
|
113
|
+
).grid(column=1, row=1, sticky="we")
|
|
114
|
+
|
|
115
|
+
# Proxy address.
|
|
116
|
+
ttk.Label(server_serving_settings, text="Proxy Address:", anchor=E, justify=RIGHT).grid(
|
|
117
|
+
column=0, row=2, sticky="we"
|
|
118
|
+
)
|
|
119
|
+
ttk.Entry(server_serving_settings, textvariable=self._proxy_address, justify=CENTER).grid(
|
|
120
|
+
column=1, row=2, sticky="we"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Ignore updates.
|
|
124
|
+
ttk.Label(server_serving_settings, text="Ignore Updates:", anchor=E, justify=RIGHT).grid(
|
|
125
|
+
column=0, row=4, sticky="we"
|
|
126
|
+
)
|
|
127
|
+
ttk.Checkbutton(
|
|
128
|
+
server_serving_settings,
|
|
129
|
+
variable=self._ignore_updates,
|
|
130
|
+
).grid(column=1, row=4, sticky="we")
|
|
131
|
+
|
|
132
|
+
# Debug mode.
|
|
133
|
+
ttk.Label(server_serving_settings, text="Debug mode:", anchor=E, justify=RIGHT).grid(
|
|
134
|
+
column=0, row=5, sticky="we"
|
|
135
|
+
)
|
|
136
|
+
ttk.Checkbutton(
|
|
137
|
+
server_serving_settings,
|
|
138
|
+
variable=self._debug,
|
|
139
|
+
).grid(column=1, row=5, sticky="we")
|
|
140
|
+
|
|
141
|
+
# ---
|
|
142
|
+
|
|
143
|
+
# Platform type.
|
|
144
|
+
platform_type_settings = ttk.LabelFrame(mainframe, text="Platform Type", padding=3)
|
|
145
|
+
platform_type_settings.grid(column=0, row=1, sticky="news")
|
|
146
|
+
|
|
147
|
+
ttk.Radiobutton(
|
|
148
|
+
platform_type_settings,
|
|
149
|
+
text="Sensapex uMp-4",
|
|
150
|
+
variable=self._type,
|
|
151
|
+
value="ump-4",
|
|
152
|
+
).grid(column=0, row=0, sticky="we")
|
|
153
|
+
ttk.Radiobutton(
|
|
154
|
+
platform_type_settings,
|
|
155
|
+
text="Sensapex uMp-3",
|
|
156
|
+
variable=self._type,
|
|
157
|
+
value="ump-3",
|
|
158
|
+
).grid(column=0, row=1, sticky="we")
|
|
159
|
+
ttk.Radiobutton(
|
|
160
|
+
platform_type_settings,
|
|
161
|
+
text="Pathfinder MPM Control v2.8.8+",
|
|
162
|
+
variable=self._type,
|
|
163
|
+
value="pathfinder-mpm",
|
|
164
|
+
).grid(column=0, row=2, sticky="we")
|
|
165
|
+
ttk.Radiobutton(
|
|
166
|
+
platform_type_settings,
|
|
167
|
+
text="New Scale M3-USB-3:1-EP",
|
|
168
|
+
variable=self._type,
|
|
169
|
+
value="new-scale",
|
|
170
|
+
).grid(column=0, row=3, sticky="we")
|
|
171
|
+
ttk.Radiobutton(
|
|
172
|
+
platform_type_settings,
|
|
173
|
+
text="Fake Platform",
|
|
174
|
+
variable=self._type,
|
|
175
|
+
value="fake",
|
|
176
|
+
).grid(column=0, row=4, sticky="we")
|
|
177
|
+
|
|
178
|
+
# ---
|
|
179
|
+
|
|
180
|
+
# New Scale Settings.
|
|
181
|
+
new_scale_settings = ttk.LabelFrame(mainframe, text="Pathfinder MPM Settings", padding=3)
|
|
182
|
+
new_scale_settings.grid(column=0, row=2, sticky="news")
|
|
183
|
+
|
|
184
|
+
# Port
|
|
185
|
+
ttk.Label(new_scale_settings, text="HTTP Server Port:", anchor=E, justify=RIGHT).grid(
|
|
186
|
+
column=0, row=1, sticky="we"
|
|
187
|
+
)
|
|
188
|
+
ttk.Entry(new_scale_settings, textvariable=self._mpm_port, width=5, justify=CENTER).grid(
|
|
189
|
+
column=1, row=1, sticky="we"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# ---
|
|
193
|
+
|
|
194
|
+
# Emergency Stop serial port.
|
|
195
|
+
e_stop_settings = ttk.LabelFrame(mainframe, text="Emergency Stop Settings", padding=3)
|
|
196
|
+
e_stop_settings.grid(column=0, row=3, sticky="news")
|
|
197
|
+
|
|
198
|
+
# Serial Port
|
|
199
|
+
ttk.Label(e_stop_settings, text="Serial Port:", anchor=E, justify=RIGHT).grid(column=0, row=1, sticky="we")
|
|
200
|
+
ttk.Entry(e_stop_settings, textvariable=self._serial, justify=CENTER).grid(column=1, row=1, sticky="we")
|
|
201
|
+
|
|
202
|
+
# Server launch button.
|
|
203
|
+
ttk.Button(
|
|
204
|
+
mainframe,
|
|
205
|
+
text="Launch Server",
|
|
206
|
+
command=self._launch_server,
|
|
207
|
+
).grid(column=0, row=4, columnspan=2, sticky="we")
|
|
208
|
+
|
|
209
|
+
def _launch_server(self) -> None:
|
|
210
|
+
"""Close GUI and return to the server.
|
|
211
|
+
|
|
212
|
+
Options are saved in fields.
|
|
213
|
+
"""
|
|
214
|
+
self._submit = True
|
|
215
|
+
self._root.destroy()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|