ephys-link 1.3.3__py3-none-any.whl → 2.0.0__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.
Files changed (42) hide show
  1. ephys_link/__about__.py +1 -1
  2. ephys_link/__main__.py +51 -105
  3. ephys_link/back_end/__init__.py +0 -0
  4. ephys_link/back_end/platform_handler.py +315 -0
  5. ephys_link/back_end/server.py +274 -0
  6. ephys_link/bindings/__init__.py +0 -0
  7. ephys_link/bindings/fake_binding.py +84 -0
  8. ephys_link/bindings/mpm_binding.py +315 -0
  9. ephys_link/bindings/ump_4_binding.py +157 -0
  10. ephys_link/front_end/__init__.py +0 -0
  11. ephys_link/front_end/cli.py +104 -0
  12. ephys_link/front_end/gui.py +204 -0
  13. ephys_link/utils/__init__.py +0 -0
  14. ephys_link/utils/base_binding.py +176 -0
  15. ephys_link/utils/console.py +127 -0
  16. ephys_link/utils/constants.py +23 -0
  17. ephys_link/utils/converters.py +86 -0
  18. ephys_link/utils/startup.py +65 -0
  19. ephys_link-2.0.0.dist-info/METADATA +91 -0
  20. ephys_link-2.0.0.dist-info/RECORD +25 -0
  21. {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/WHEEL +1 -1
  22. {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/licenses/LICENSE +674 -674
  23. ephys_link/common.py +0 -49
  24. ephys_link/emergency_stop.py +0 -67
  25. ephys_link/gui.py +0 -217
  26. ephys_link/platform_handler.py +0 -465
  27. ephys_link/platform_manipulator.py +0 -35
  28. ephys_link/platforms/__init__.py +0 -5
  29. ephys_link/platforms/new_scale_handler.py +0 -141
  30. ephys_link/platforms/new_scale_manipulator.py +0 -312
  31. ephys_link/platforms/new_scale_pathfinder_handler.py +0 -235
  32. ephys_link/platforms/sensapex_handler.py +0 -151
  33. ephys_link/platforms/sensapex_manipulator.py +0 -227
  34. ephys_link/platforms/ump3_handler.py +0 -57
  35. ephys_link/platforms/ump3_manipulator.py +0 -147
  36. ephys_link/resources/CP210xManufacturing.dll +0 -0
  37. ephys_link/resources/NstMotorCtrl.dll +0 -0
  38. ephys_link/resources/SiUSBXp.dll +0 -0
  39. ephys_link/server.py +0 -508
  40. ephys_link-1.3.3.dist-info/METADATA +0 -164
  41. ephys_link-1.3.3.dist-info/RECORD +0 -26
  42. {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/entry_points.txt +0 -0
ephys_link/common.py DELETED
@@ -1,49 +0,0 @@
1
- """Commonly used functions and dictionaries
2
-
3
- Contains globally used helper functions and typed dictionaries (to be used as
4
- callback parameters)
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from typing import TYPE_CHECKING
10
-
11
- if TYPE_CHECKING:
12
- from vbl_aquarium.models.unity import Vector4
13
-
14
- # Debugging flag
15
- DEBUG = False
16
-
17
- # Ephys Link ASCII
18
- ASCII = r"""
19
- ______ _ _ _ _
20
- | ____| | | | | (_) | |
21
- | |__ _ __ | |__ _ _ ___ | | _ _ __ | | __
22
- | __| | '_ \| '_ \| | | / __| | | | | '_ \| |/ /
23
- | |____| |_) | | | | |_| \__ \ | |____| | | | | <
24
- |______| .__/|_| |_|\__, |___/ |______|_|_| |_|_|\_\
25
- | | __/ |
26
- |_| |___/
27
- """
28
-
29
-
30
- def dprint(message: str) -> None:
31
- """Print message if debug is enabled.
32
-
33
- :param message: Message to print.
34
- :type message: str
35
- :return: None
36
- """
37
- if DEBUG:
38
- print(message)
39
-
40
-
41
- def vector4_to_array(vector4: Vector4) -> list[float]:
42
- """Convert a Vector4 to a list of floats.
43
-
44
- :param vector4: Vector4 to convert.
45
- :type vector4: :class:`vbl_aquarium.models.unity.Vector4`
46
- :return: List of floats.
47
- :rtype: list[float]
48
- """
49
- return [vector4.x, vector4.y, vector4.z, vector4.w]
@@ -1,67 +0,0 @@
1
- from signal import SIGINT, SIGTERM, signal
2
- from threading import Event, Thread
3
- from time import sleep
4
-
5
- from serial import Serial
6
- from serial.tools import list_ports
7
-
8
- from ephys_link.common import dprint
9
- from ephys_link.server import Server
10
-
11
-
12
- class EmergencyStop:
13
- """Serial system for emergency stop"""
14
-
15
- def __init__(self, server: Server, serial_port: str) -> None:
16
- """Setup serial port for emergency stop
17
-
18
- :param server: The Ephys Link server instance
19
- :type server: Server
20
- :param serial_port: The serial port to poll
21
- :type serial_port: str
22
- :return: None
23
- """
24
- self._server = server
25
- self._serial_port = serial_port
26
- self._poll_rate = 0.05
27
- self._kill_serial_event = Event()
28
- self._poll_serial_thread = Thread(target=self._poll_serial, daemon=True)
29
-
30
- # Register signals
31
- signal(SIGTERM, self._close_serial)
32
- signal(SIGINT, self._close_serial)
33
-
34
- def watch(self) -> None:
35
- """Start polling serial port for emergency stop"""
36
- self._poll_serial_thread.start()
37
-
38
- def _poll_serial(self) -> None:
39
- """Continuously poll serial port for data
40
-
41
- Close port on kill event
42
- """
43
- target_port = self._serial_port
44
- if self._serial_port is None:
45
- # Search for serial ports
46
- for port, desc, _ in list_ports.comports():
47
- if "Arduino" in desc or "USB Serial Device" in desc:
48
- target_port = port
49
- break
50
-
51
- serial = Serial(target_port, 9600, timeout=self._poll_rate)
52
- while not self._kill_serial_event.is_set():
53
- if serial.in_waiting > 0:
54
- serial.readline()
55
- # Cause a break
56
- dprint("[EMERGENCY STOP]\t\t Stopping all manipulators")
57
- self._server.platform.stop()
58
- serial.reset_input_buffer()
59
- sleep(self._poll_rate)
60
- print("Close poll")
61
- serial.close()
62
-
63
- def _close_serial(self, _, __) -> None:
64
- """Close the serial connection"""
65
- print("[INFO]\t\t Closing serial")
66
- self._kill_serial_event.set()
67
- self._poll_serial_thread.join()
ephys_link/gui.py DELETED
@@ -1,217 +0,0 @@
1
- from asyncio import run
2
- from json import dumps, load
3
- from os import makedirs
4
- from os.path import exists
5
- from socket import gethostbyname, gethostname
6
- from tkinter import CENTER, RIGHT, BooleanVar, E, IntVar, StringVar, Tk, ttk
7
-
8
- from platformdirs import user_config_dir
9
-
10
- import ephys_link.common as com
11
- from ephys_link.__about__ import __version__ as version
12
- from ephys_link.emergency_stop import EmergencyStop
13
- from ephys_link.server import Server
14
-
15
- SETTINGS_DIR = f"{user_config_dir()}\\VBL\\Ephys Link"
16
- SETTINGS_FILENAME = "settings.json"
17
-
18
-
19
- class GUI:
20
- """GUI definition for Ephys Link"""
21
-
22
- def __init__(self) -> None:
23
- """Setup and construction of the Tk GUI"""
24
-
25
- self._root = Tk()
26
-
27
- # Create default settings dictionary
28
- settings = {
29
- "ignore_updates": False,
30
- "type": "sensapex",
31
- "debug": False,
32
- "proxy": False,
33
- "proxy_address": "proxy2.virtualbrainlab.org",
34
- "port": 8081,
35
- "pathfinder_port": 8080,
36
- "serial": "no-e-stop",
37
- }
38
-
39
- # Read settings.
40
- if exists(f"{SETTINGS_DIR}\\{SETTINGS_FILENAME}"):
41
- with open(f"{SETTINGS_DIR}\\{SETTINGS_FILENAME}") as settings_file:
42
- settings = load(settings_file)
43
-
44
- self._ignore_updates = BooleanVar(value=settings["ignore_updates"])
45
- self._type = StringVar(value=settings["type"])
46
- self._debug = BooleanVar(value=settings["debug"])
47
- self._proxy = BooleanVar(value=settings["proxy"])
48
- self._proxy_address = StringVar(value=settings["proxy_address"])
49
- self._port = IntVar(value=settings["port"])
50
- self._pathfinder_port = IntVar(value=settings["pathfinder_port"])
51
- self._serial = StringVar(value=settings["serial"])
52
-
53
- def launch(self) -> None:
54
- """Build and launch GUI"""
55
-
56
- # Build and run GUI.
57
- self._build_gui()
58
- self._root.mainloop()
59
-
60
- def _build_gui(self):
61
- """Build GUI"""
62
-
63
- self._root.title(f"Ephys Link v{version}")
64
-
65
- mainframe = ttk.Frame(self._root, padding=3)
66
- mainframe.grid(column=0, row=0, sticky="news")
67
- self._root.columnconfigure(0, weight=1)
68
- self._root.rowconfigure(0, weight=1)
69
- mainframe.columnconfigure(0, weight=1)
70
- mainframe.rowconfigure(0, weight=1)
71
-
72
- # Server serving settings.
73
-
74
- server_serving_settings = ttk.LabelFrame(mainframe, text="Serving Settings", padding=3)
75
- server_serving_settings.grid(column=0, row=0, sticky="news")
76
-
77
- # Local IP.
78
- ttk.Label(server_serving_settings, text="Local IP:", anchor=E, justify=RIGHT).grid(column=0, row=0, sticky="we")
79
- ttk.Label(server_serving_settings, text=gethostbyname(gethostname())).grid(column=1, row=0, sticky="we")
80
-
81
- # Proxy.
82
- ttk.Label(server_serving_settings, text="Use Proxy:", anchor=E, justify=RIGHT).grid(
83
- column=0, row=1, sticky="we"
84
- )
85
- ttk.Checkbutton(
86
- server_serving_settings,
87
- variable=self._proxy,
88
- ).grid(column=1, row=1, sticky="we")
89
-
90
- # Proxy address.
91
- ttk.Label(server_serving_settings, text="Proxy Address:", anchor=E, justify=RIGHT).grid(
92
- column=0, row=2, sticky="we"
93
- )
94
- ttk.Entry(server_serving_settings, textvariable=self._proxy_address, justify=CENTER).grid(
95
- column=1, row=2, sticky="we"
96
- )
97
-
98
- # Port.
99
- ttk.Label(server_serving_settings, text="Port:", anchor=E, justify=RIGHT).grid(column=0, row=3, sticky="we")
100
- ttk.Entry(server_serving_settings, textvariable=self._port, width=5, justify=CENTER).grid(
101
- column=1, row=3, sticky="we"
102
- )
103
-
104
- # Ignore updates.
105
- ttk.Label(server_serving_settings, text="Ignore Updates:", anchor=E, justify=RIGHT).grid(
106
- column=0, row=4, sticky="we"
107
- )
108
- ttk.Checkbutton(
109
- server_serving_settings,
110
- variable=self._ignore_updates,
111
- ).grid(column=1, row=4, sticky="we")
112
-
113
- # ---
114
-
115
- # Platform type.
116
- platform_type_settings = ttk.LabelFrame(mainframe, text="Platform Type", padding=3)
117
- platform_type_settings.grid(column=0, row=1, sticky="news")
118
-
119
- ttk.Radiobutton(
120
- platform_type_settings,
121
- text="Sensapex uMp-4",
122
- variable=self._type,
123
- value="sensapex",
124
- ).grid(column=0, row=0, sticky="we")
125
- ttk.Radiobutton(
126
- platform_type_settings,
127
- text="Sensapex uMp-3",
128
- variable=self._type,
129
- value="ump3",
130
- ).grid(column=0, row=1, sticky="we")
131
- ttk.Radiobutton(
132
- platform_type_settings,
133
- text="Pathfinder MPM Control v2.8.8+",
134
- variable=self._type,
135
- value="new_scale_pathfinder",
136
- ).grid(column=0, row=2, sticky="we")
137
- ttk.Radiobutton(
138
- platform_type_settings,
139
- text="New Scale M3-USB-3:1-EP",
140
- variable=self._type,
141
- value="new_scale",
142
- ).grid(column=0, row=3, sticky="we")
143
-
144
- # ---
145
-
146
- # New Scale Settings.
147
- new_scale_settings = ttk.LabelFrame(mainframe, text="Pathfinder Settings", padding=3)
148
- new_scale_settings.grid(column=0, row=2, sticky="news")
149
-
150
- # Port
151
- ttk.Label(new_scale_settings, text="HTTP Server Port:", anchor=E, justify=RIGHT).grid(
152
- column=0, row=1, sticky="we"
153
- )
154
- ttk.Entry(new_scale_settings, textvariable=self._pathfinder_port, width=5, justify=CENTER).grid(
155
- column=1, row=1, sticky="we"
156
- )
157
-
158
- # ---
159
-
160
- # Emergency Stop serial port.
161
- e_stop_settings = ttk.LabelFrame(mainframe, text="Emergency Stop Settings", padding=3)
162
- e_stop_settings.grid(column=0, row=3, sticky="news")
163
-
164
- # Serial Port
165
- ttk.Label(e_stop_settings, text="Serial Port:", anchor=E, justify=RIGHT).grid(column=0, row=1, sticky="we")
166
- ttk.Entry(e_stop_settings, textvariable=self._serial, justify=CENTER).grid(column=1, row=1, sticky="we")
167
-
168
- # Server launch button.
169
- ttk.Button(
170
- mainframe,
171
- text="Launch Server",
172
- command=self._launch_server,
173
- ).grid(column=0, row=4, columnspan=2, sticky="we")
174
-
175
- def _launch_server(self) -> None:
176
- """Launch server based on GUI settings"""
177
-
178
- # Close GUI.
179
- self._root.destroy()
180
-
181
- # Save settings.
182
- settings = {
183
- "ignore_updates": self._ignore_updates.get(),
184
- "type": self._type.get(),
185
- "debug": self._debug.get(),
186
- "proxy": self._proxy.get(),
187
- "proxy_address": self._proxy_address.get(),
188
- "port": self._port.get(),
189
- "pathfinder_port": self._pathfinder_port.get(),
190
- "serial": self._serial.get(),
191
- }
192
- makedirs(SETTINGS_DIR, exist_ok=True)
193
- with open(f"{SETTINGS_DIR}\\{SETTINGS_FILENAME}", "w+") as f:
194
- f.write(dumps(settings))
195
-
196
- # Launch server.
197
- server = Server()
198
-
199
- com.DEBUG = self._debug.get()
200
-
201
- if self._serial.get() != "no-e-stop":
202
- e_stop = EmergencyStop(server, self._serial.get())
203
- e_stop.watch()
204
-
205
- # Launch with parsed arguments on main thread.
206
- if self._proxy.get():
207
- run(
208
- server.launch_for_proxy(
209
- self._proxy_address.get(),
210
- self._port.get(),
211
- self._type.get(),
212
- self._pathfinder_port.get(),
213
- self._ignore_updates.get(),
214
- )
215
- )
216
- else:
217
- server.launch(self._type.get(), self._port.get(), self._pathfinder_port.get(), self._ignore_updates.get())