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