ephys-link 1.3.0b2__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 -90
  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.0b2.dist-info → ephys_link-2.0.0.dist-info}/WHEEL +1 -1
  22. {ephys_link-1.3.0b2.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 -163
  26. ephys_link/platform_handler.py +0 -465
  27. ephys_link/platform_manipulator.py +0 -34
  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 -221
  34. ephys_link/platforms/ump3_handler.py +0 -57
  35. ephys_link/platforms/ump3_manipulator.py +0 -145
  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 -436
  40. ephys_link-1.3.0b2.dist-info/METADATA +0 -163
  41. ephys_link-1.3.0b2.dist-info/RECORD +0 -26
  42. {ephys_link-1.3.0b2.dist-info → ephys_link-2.0.0.dist-info}/entry_points.txt +0 -0
ephys_link/server.py DELETED
@@ -1,436 +0,0 @@
1
- """WebSocket server and communication handler
2
-
3
- Manages the WebSocket server and handles connections and events from the client. For
4
- every event, the server does the following:
5
-
6
- 1. Extract the arguments passed in the event
7
- 2. Log that the event was received
8
- 3. Call the appropriate function in :mod:`ephys_link.sensapex_handler` with arguments
9
- 4. Relay the response from :mod:`ephys_link.sensapex_handler` to the callback function
10
- """
11
-
12
- from __future__ import annotations
13
-
14
- from json import loads
15
- from signal import SIGINT, SIGTERM, signal
16
- from sys import exit
17
- from typing import TYPE_CHECKING, Any
18
-
19
- from aiohttp import web
20
- from aiohttp.web_runner import GracefulExit
21
- from packaging import version
22
- from pydantic import ValidationError
23
- from requests import get
24
- from requests.exceptions import ConnectionError
25
- from socketio import AsyncServer
26
- from vbl_aquarium.models.ephys_link import (
27
- BooleanStateResponse,
28
- CanWriteRequest,
29
- DriveToDepthRequest,
30
- DriveToDepthResponse,
31
- GotoPositionRequest,
32
- InsideBrainRequest,
33
- PositionalResponse,
34
- )
35
-
36
- from ephys_link.__about__ import __version__
37
- from ephys_link.common import (
38
- ASCII,
39
- dprint,
40
- )
41
- from ephys_link.platforms.new_scale_handler import NewScaleHandler
42
- from ephys_link.platforms.new_scale_pathfinder_handler import NewScalePathfinderHandler
43
- from ephys_link.platforms.sensapex_handler import SensapexHandler
44
- from ephys_link.platforms.ump3_handler import UMP3Handler
45
-
46
- if TYPE_CHECKING:
47
- from ephys_link.platform_handler import PlatformHandler
48
-
49
-
50
- class Server:
51
- def __init__(self):
52
- # Server and Socketio
53
- self.sio = AsyncServer()
54
- self.app = web.Application()
55
-
56
- # Is there a client connected?
57
- self.is_connected = False
58
-
59
- # Is the server running?
60
- self.is_running = False
61
-
62
- # Current platform handler (defaults to Sensapex).
63
- self.platform: PlatformHandler = SensapexHandler()
64
-
65
- # Register server exit handlers.
66
- signal(SIGTERM, self.close_server)
67
- signal(SIGINT, self.close_server)
68
-
69
- # Attach server to the web app.
70
- self.sio.attach(self.app)
71
-
72
- # Declare events and assign handlers.
73
- self.sio.on("connect", self.connect)
74
- self.sio.on("disconnect", self.disconnect)
75
- self.sio.on("get_version", self.get_version)
76
- self.sio.on("get_manipulators", self.get_manipulators)
77
- self.sio.on("register_manipulator", self.register_manipulator)
78
- self.sio.on("unregister_manipulator", self.unregister_manipulator)
79
- self.sio.on("get_pos", self.get_pos)
80
- self.sio.on("get_angles", self.get_angles)
81
- self.sio.on("get_shank_count", self.get_shank_count)
82
- self.sio.on("goto_pos", self.goto_pos)
83
- self.sio.on("drive_to_depth", self.drive_to_depth)
84
- self.sio.on("set_inside_brain", self.set_inside_brain)
85
- self.sio.on("calibrate", self.calibrate)
86
- self.sio.on("bypass_calibration", self.bypass_calibration)
87
- self.sio.on("set_can_write", self.set_can_write)
88
- self.sio.on("stop", self.stop)
89
- self.sio.on("*", self.catch_all)
90
-
91
- async def connect(self, sid, _, __) -> bool:
92
- """Acknowledge connection to the server.
93
-
94
- :param sid: Socket session ID.
95
- :type sid: str
96
- :param _: WSGI formatted dictionary with request info (unused).
97
- :type _: dict
98
- :param __: Authentication details (unused).
99
- :type __: dict
100
- :return: False on error to refuse connection. True otherwise.
101
- :rtype: bool
102
- """
103
- print(f"[CONNECTION REQUEST]:\t\t {sid}\n")
104
-
105
- if not self.is_connected:
106
- print(f"[CONNECTION GRANTED]:\t\t {sid}\n")
107
- self.is_connected = True
108
- return True
109
-
110
- print(f"[CONNECTION DENIED]:\t\t {sid}: another client is already connected\n")
111
- return False
112
-
113
- async def disconnect(self, sid) -> None:
114
- """Acknowledge disconnection from the server.
115
-
116
- :param sid: Socket session ID.
117
- :type sid: str
118
- :return: None
119
- """
120
- print(f"[DISCONNECTION]:\t {sid}\n")
121
-
122
- self.platform.reset()
123
- self.is_connected = False
124
-
125
- # Events
126
-
127
- @staticmethod
128
- async def get_version(_) -> str:
129
- """Get the version number of the server.
130
-
131
- :param _: Socket session ID (unused).
132
- :type _: str
133
- :return: Version number as defined in :mod:`ephys_link.__about__`.
134
- :rtype: str
135
- """
136
- return __version__
137
-
138
- async def get_manipulators(self, _) -> str:
139
- """Get the list of discoverable manipulators.
140
-
141
- :param _: Socket session ID (unused).
142
- :type _: str
143
- :return: :class:`vbl_aquarium.models.ephys_link.GetManipulatorsResponse` as JSON formatted string.
144
- :rtype: str
145
- """
146
- dprint("[EVENT]\t\t Get discoverable manipulators")
147
-
148
- return self.platform.get_manipulators().to_string()
149
-
150
- async def register_manipulator(self, _, manipulator_id: str) -> str:
151
- """Register a manipulator with the server.
152
-
153
- :param _: Socket session ID (unused).
154
- :type _: str
155
- :param manipulator_id: ID of the manipulator to register.
156
- :type manipulator_id: str
157
- :return: Error message on error, empty string otherwise.
158
- :rtype: str
159
- """
160
- dprint(f"[EVENT]\t\t Register manipulator: {manipulator_id}")
161
-
162
- return self.platform.register_manipulator(manipulator_id)
163
-
164
- async def unregister_manipulator(self, _, manipulator_id: str) -> str:
165
- """Unregister a manipulator from the server.
166
-
167
- :param _: Socket session ID (unused)
168
- :type _: str
169
- :param manipulator_id: ID of the manipulator to unregister.
170
- :type manipulator_id: str
171
- :return: Error message on error, empty string otherwise.
172
- :rtype: str
173
- """
174
- dprint(f"[EVENT]\t\t Unregister manipulator: {manipulator_id}")
175
-
176
- return self.platform.unregister_manipulator(manipulator_id)
177
-
178
- async def get_pos(self, _, manipulator_id: str) -> str:
179
- """Position of manipulator request.
180
-
181
- :param _: Socket session ID (unused).
182
- :type _: str
183
- :param manipulator_id: ID of manipulator to pull position from.
184
- :type manipulator_id: str
185
- :return: :class:`vbl_aquarium.models.ephys_link.PositionalResponse` as JSON formatted string.
186
- :rtype: str
187
- """
188
- # dprint(f"[EVENT]\t\t Get position of manipulator" f" {manipulator_id}")
189
-
190
- return self.platform.get_pos(manipulator_id).to_string()
191
-
192
- async def get_angles(self, _, manipulator_id: str) -> str:
193
- """Angles of manipulator request.
194
-
195
- :param _: Socket session ID (unused).
196
- :type _: str
197
- :param manipulator_id: ID of manipulator to pull angles from.
198
- :type manipulator_id: str
199
- :return: :class:`vbl_aquarium.models.ephys_link.AngularResponse` as JSON formatted string.
200
- :rtype: str
201
- """
202
-
203
- return self.platform.get_angles(manipulator_id).to_string()
204
-
205
- async def get_shank_count(self, _, manipulator_id: str) -> str:
206
- """Number of shanks of manipulator request.
207
-
208
- :param _: Socket session ID (unused).
209
- :type _: str
210
- :param manipulator_id: ID of manipulator to pull number of shanks from.
211
- :type manipulator_id: str
212
- :return: :class:`vbl_aquarium.models.ephys_link.ShankCountResponse` as JSON formatted string.
213
- :rtype: str
214
- """
215
-
216
- return self.platform.get_shank_count(manipulator_id).to_string()
217
-
218
- async def goto_pos(self, _, data: str) -> str:
219
- """Move manipulator to position.
220
-
221
- :param _: Socket session ID (unused).
222
- :type _: str
223
- :param data: :class:`vbl_aquarium.models.ephys_link.GotoPositionRequest` as JSON formatted string.
224
- :type data: str
225
- :return: :class:`vbl_aquarium.models.ephys_link.PositionalResponse` as JSON formatted string.
226
- :rtype: str
227
- """
228
- try:
229
- request = GotoPositionRequest(**loads(data))
230
- except ValidationError as ve:
231
- print(f"[ERROR]\t\t Invalid goto_pos data: {data}\n{ve}\n")
232
- return PositionalResponse(error="Invalid data format").to_string()
233
- except Exception as e:
234
- print(f"[ERROR]\t\t Error in goto_pos: {e}\n")
235
- return PositionalResponse(error="Error in goto_pos").to_string()
236
- else:
237
- dprint(f"[EVENT]\t\t Move manipulator {request.manipulator_id} to position {request.position}")
238
- goto_result = await self.platform.goto_pos(request)
239
- return goto_result.to_string()
240
-
241
- async def drive_to_depth(self, _, data: str) -> str:
242
- """Drive to depth.
243
-
244
- :param _: Socket session ID (unused).
245
- :type _: str
246
- :param data: :class:`vbl_aquarium.models.ephys_link.DriveToDepthRequest` as JSON formatted string.
247
- :type data: str
248
- :return: :class:`vbl_aquarium.models.ephys_link.DriveToDepthResponse` as JSON formatted string.
249
- :rtype: str
250
- """
251
- try:
252
- request = DriveToDepthRequest(**loads(data))
253
- except KeyError:
254
- print(f"[ERROR]\t\t Invalid drive_to_depth data: {data}\n")
255
- return DriveToDepthResponse(error="Invalid data " "format").to_string()
256
- except Exception as e:
257
- print(f"[ERROR]\t\t Error in drive_to_depth: {e}\n")
258
- return DriveToDepthResponse(error="Error in drive_to_depth").to_string()
259
- else:
260
- dprint(f"[EVENT]\t\t Drive manipulator {request.manipulator_id} to depth {request.depth}")
261
- drive_result = await self.platform.drive_to_depth(request)
262
- return drive_result.to_string()
263
-
264
- async def set_inside_brain(self, _, data: str) -> str:
265
- """Set the inside brain state.
266
-
267
- :param _: Socket session ID (unused).
268
- :type _: str
269
- :param data: :class:`vbl_aquarium.models.ephys_link.InsideBrainRequest` as JSON formatted string.
270
- :type data: str
271
- :return: :class:`vbl_aquarium.models.ephys_link.BooleanStateResponse` as JSON formatted string.
272
- :rtype: str
273
- """
274
- try:
275
- request = InsideBrainRequest(**loads(data))
276
- except KeyError:
277
- print(f"[ERROR]\t\t Invalid set_inside_brain data: {data}\n")
278
- return BooleanStateResponse(error="Invalid data format").to_string()
279
- except Exception as e:
280
- print(f"[ERROR]\t\t Error in inside_brain: {e}\n")
281
- return BooleanStateResponse(error="Error in set_inside_brain").to_string()
282
- else:
283
- dprint(f"[EVENT]\t\t Set manipulator {request.manipulator_id} inside brain to {request.inside}")
284
- return self.platform.set_inside_brain(request).to_string()
285
-
286
- async def calibrate(self, _, manipulator_id: str) -> str:
287
- """Calibrate manipulator.
288
-
289
- :param _: Socket session ID (unused).
290
- :type _: str
291
- :param manipulator_id: ID of manipulator to calibrate.
292
- :type manipulator_id: str
293
- :return: Error message on error, empty string otherwise.
294
- :rtype: str
295
- """
296
- dprint(f"[EVENT]\t\t Calibrate manipulator" f" {manipulator_id}")
297
-
298
- return await self.platform.calibrate(manipulator_id, self.sio)
299
-
300
- async def bypass_calibration(self, _, manipulator_id: str) -> str:
301
- """Bypass calibration of manipulator.
302
-
303
- :param _: Socket session ID (unused).
304
- :type _: str
305
- :param manipulator_id: ID of manipulator to bypass calibration.
306
- :type manipulator_id: str
307
- :return: Error message on error, empty string otherwise.
308
- :rtype: str
309
- """
310
- dprint(f"[EVENT]\t\t Bypass calibration of manipulator" f" {manipulator_id}")
311
-
312
- return self.platform.bypass_calibration(manipulator_id)
313
-
314
- async def set_can_write(self, _, data: str) -> str:
315
- """Set manipulator can_write state.
316
-
317
- :param _: Socket session ID (unused)
318
- :type _: str
319
- :param data: :class:`vbl_aquarium.models.ephys_link.CanWriteRequest` as JSON formatted string.
320
- :type data: str
321
- :return: :class:`vbl_aquarium.models.ephys_link.BooleanStateResponse` as JSON formatted string.
322
- :rtype: str
323
- """
324
- try:
325
- request = CanWriteRequest(**loads(data))
326
- except KeyError:
327
- print(f"[ERROR]\t\t Invalid set_can_write data: {data}\n")
328
- return BooleanStateResponse(error="Invalid data format").to_string()
329
- except Exception as e:
330
- print(f"[ERROR]\t\t Error in inside_brain: {e}\n")
331
- return BooleanStateResponse(error="Error in set_can_write").to_string()
332
- else:
333
- dprint(f"[EVENT]\t\t Set manipulator {request.manipulator_id} can_write state to {request.can_write}")
334
- return self.platform.set_can_write(request).to_string()
335
-
336
- def stop(self, _) -> bool:
337
- """Stop all manipulators.
338
-
339
- :param _: Socket session ID (unused).
340
- :type _: str
341
- :return: True if successful, False otherwise.
342
- :rtype: bool
343
- """
344
- dprint("[EVENT]\t\t Stop all manipulators")
345
-
346
- return self.platform.stop()
347
-
348
- @staticmethod
349
- async def catch_all(_, __, data: Any) -> str:
350
- """Catch all event.
351
-
352
- :param _: Socket session ID (unused).
353
- :type _: str
354
- :param __: Client ID (unused).
355
- :type __: str
356
- :param data: Data received from client.
357
- :type data: Any
358
- :return: "UNKNOWN_EVENT" response message.
359
- :rtype: str
360
- """
361
- print(f"[UNKNOWN EVENT]:\t {data}")
362
- return "UNKNOWN_EVENT"
363
-
364
- def launch(
365
- self,
366
- platform_type: str,
367
- server_port: int,
368
- pathfinder_port: int | None = None,
369
- ignore_updates: bool = False, # noqa: FBT002
370
- ) -> None:
371
- """Launch the server.
372
-
373
- :param platform_type: Parsed argument for platform type.
374
- :type platform_type: str
375
- :param server_port: HTTP port to serve the server.
376
- :type server_port: int
377
- :param pathfinder_port: Port New Scale Pathfinder's server is on.
378
- :type pathfinder_port: int
379
- :param ignore_updates: Flag to ignore checking for updates.
380
- :type ignore_updates: bool
381
- :return: None
382
- """
383
-
384
- # Import correct manipulator handler
385
- if platform_type == "sensapex":
386
- # Already assigned (was the default)
387
- pass
388
- elif platform_type == "ump3":
389
- self.platform = UMP3Handler()
390
- elif platform_type == "new_scale":
391
- self.platform = NewScaleHandler()
392
- elif platform_type == "new_scale_pathfinder":
393
- self.platform = NewScalePathfinderHandler(pathfinder_port)
394
- else:
395
- exit(f"[ERROR]\t\t Invalid manipulator type: {platform_type}")
396
-
397
- # Preamble.
398
- print(ASCII)
399
- print(f"v{__version__}")
400
-
401
- # Check for newer version.
402
- if not ignore_updates:
403
- try:
404
- version_request = get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags", timeout=10)
405
- latest_version = version_request.json()[0]["name"]
406
- if version.parse(latest_version) > version.parse(__version__):
407
- print(f"New version available: {latest_version}")
408
- print("Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
409
- except ConnectionError:
410
- pass
411
-
412
- # Explain window.
413
- print()
414
- print("This is the Ephys Link server window.")
415
- print("You may safely leave it running in the background.")
416
- print("To stop the it, close this window or press CTRL + Pause/Break.")
417
- print()
418
-
419
- # List available manipulators
420
- print("Available Manipulators:")
421
- print(self.platform.get_manipulators().manipulators)
422
- print()
423
-
424
- # Mark that server is running
425
- self.is_running = True
426
- web.run_app(self.app, port=server_port)
427
-
428
- def close_server(self, _, __) -> None:
429
- """Close the server."""
430
- print("[INFO]\t\t Closing server")
431
-
432
- # Stop movement
433
- self.platform.stop()
434
-
435
- # Exit
436
- raise GracefulExit
@@ -1,163 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: ephys-link
3
- Version: 1.3.0b2
4
- Summary: A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments.
5
- Project-URL: Documentation, https://virtualbrainlab.org/ephys_link/installation_and_use.html
6
- Project-URL: Issues, https://github.com/VirtualBrainLab/ephys-link/issues
7
- Project-URL: Source, https://github.com/VirtualBrainLab/ephys-link
8
- Author-email: Kenneth Yang <kjy5@uw.edu>
9
- Maintainer-email: Kenneth Yang <kjy5@uw.edu>
10
- License-Expression: GPL-3.0-only
11
- License-File: LICENSE
12
- Keywords: electrophysiology,ephys,manipulator,neuroscience,neurotech,new-scale,sensapex,socket-io,virtualbrainlab
13
- Classifier: Intended Audience :: End Users/Desktop
14
- Classifier: Intended Audience :: Healthcare Industry
15
- Classifier: Intended Audience :: Science/Research
16
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
17
- Classifier: Operating System :: Microsoft :: Windows
18
- Classifier: Programming Language :: Python
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.8
21
- Classifier: Programming Language :: Python :: 3.9
22
- Classifier: Programming Language :: Python :: 3.10
23
- Classifier: Programming Language :: Python :: 3.11
24
- Classifier: Programming Language :: Python :: 3.12
25
- Classifier: Programming Language :: Python :: Implementation :: CPython
26
- Classifier: Programming Language :: Python :: Implementation :: PyPy
27
- Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
28
- Requires-Python: <3.13,>=3.8
29
- Requires-Dist: aiohttp==3.9.4
30
- Requires-Dist: platformdirs==4.2.0
31
- Requires-Dist: pyserial==3.5
32
- Requires-Dist: python-socketio==5.11.2
33
- Requires-Dist: pythonnet==3.0.3
34
- Requires-Dist: requests==2.31.0
35
- Requires-Dist: sensapex==1.400.0
36
- Requires-Dist: vbl-aquarium==0.0.12
37
- Description-Content-Type: text/markdown
38
-
39
- # Electrophysiology Manipulator Link
40
-
41
- [![PyPI version](https://badge.fury.io/py/ephys-link.svg)](https://badge.fury.io/py/ephys-link)
42
- [![CodeQL](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/codeql-analysis.yml)
43
- [![Dependency Review](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/dependency-review.yml)
44
- [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
45
- [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
46
-
47
- <!-- [![Build](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/build.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/build.yml) -->
48
-
49
- <img width="100%" src="https://github.com/VirtualBrainLab/ephys-link/assets/82800265/0c7c60b1-0926-4697-a461-221554f82de1" alt="Manipulator and probe in pinpoint moving in sync">
50
-
51
- The [Electrophysiology Manipulator Link](https://github.com/VirtualBrainLab/ephys-link)
52
- (or Ephys Link for short) is a Python [Socket.IO](https://socket.io/docs/v4/#what-socketio-is) server that allows any
53
- Socket.IO-compliant application (such
54
- as [Pinpoint](https://github.com/VirtualBrainLab/Pinpoint))
55
- to communicate with manipulators used in electrophysiology experiments.
56
-
57
- **Supported Manipulators:**
58
-
59
- | Manufacturer | Model |
60
- |--------------|-------------------------------------------------------------------------|
61
- | Sensapex | <ul> <li>uMp-4</li> <li>uMp-3</li> </ul> |
62
- | New Scale | <ul> <li>Pathfinder MPM Control v2.8+</li> <li>M3-USB-3:1-EP</li> </ul> |
63
-
64
- Ephys Link is an open and extensible platform. It is designed to easily support integration with other manipulators.
65
-
66
- For more information regarding the server's implementation and how the code is organized, see
67
- the [package's development documentation](https://virtualbrainlab.org/ephys_link/development.html).
68
-
69
- For detailed descriptions of the server's API, see
70
- the [API reference](https://virtualbrainlab.org/api_reference_ephys_link.html).
71
-
72
- # Installation
73
-
74
- ## Prerequisites
75
-
76
- 1. An **x86 Windows PC is required** to run the server.
77
- 2. For Sensapex devices, the controller unit must be connected via an ethernet
78
- cable and powered. A USB-to-ethernet adapter is acceptable. For New Scale manipulators,
79
- the controller unit must be connected via USB and be powered by a 6V power
80
- supply.
81
- 3. To use the emergency stop feature, ensure an Arduino with
82
- the [StopSignal](https://github.com/VirtualBrainLab/StopSignal) sketch is
83
- connected to the computer. Follow the instructions on that repo for how to
84
- set up the Arduino.
85
-
86
- **NOTE:** Ephys Link is an HTTP server without cross-origin support. The server
87
- is currently designed to interface with local/desktop instances of Pinpoint. It
88
- will not work with the web browser versions of Pinpoint at this time.
89
-
90
- ## Launch from Pinpoint (Recommended)
91
-
92
- Pinpoint comes bundled with the correct version of Ephys Link. If you are using Pinpoint on the same computer your
93
- manipulators are connected to, you can launch the server from within Pinpoint. Follow the instructions in
94
- the [Pinpoint documentation](https://virtualbrainlab.org/pinpoint/tutorials/tutorial_ephys_link.html#configure-and-launch-ephys-link).
95
-
96
- ## Install as Standalone Executable
97
-
98
- 1. Download the latest executable from
99
- the [releases page](https://github.com/VirtualBrainLab/ephys-link/releases/latest).
100
- 2. Double-click the executable file to launch the configuration window.
101
- 1. Take note of the IP address and port. **Copy this information into Pinpoint to connect**.
102
- 3. Select the desired configuration and click "Launch Server".
103
-
104
- The configuration window will close and the server will launch. Your configurations will be saved for future use.
105
-
106
- To connect to the server from Pinpoint, provide the IP address and port. For example, if the server is running on the
107
- same computer that Pinpoint is, use
108
-
109
- - Server: `localhost`
110
- - Port: `8081`
111
-
112
- If the server is running on a different (local) computer, use the IP address of that computer as shown in the startup
113
- window instead of `localhost`.
114
-
115
- ## Install as a Python package
116
-
117
- ```bash
118
- pip install ephys-link
119
- ```
120
-
121
- Import the modules you need and launch the server.
122
-
123
- ```python
124
- from ephys_link.server import Server
125
-
126
- server = Server()
127
- server.launch("sensapex", 8081)
128
- ```
129
-
130
- ## Install for Development
131
-
132
- 1. Clone the repository.
133
- 2. Install [Hatch](https://hatch.pypa.io/latest/install/)
134
- 3. Install the latest Microsoft Visual C++ (MSVC v143+ x86/64) and the Windows SDK (10/11)
135
- via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
136
- 4. In a terminal, navigate to the repository's root directory and run
137
-
138
- ```bash
139
- hatch shell
140
- ```
141
-
142
- This will create a virtual environment, install Python 12 (if not found), and install the package in editable mode.
143
-
144
- # Documentation and More Information
145
-
146
- Complete documentation including API usage and development installation can be
147
- found on the [Virtual Brain Lab Documentation page][docs] for Ephys Link.
148
-
149
- # Citing
150
-
151
- If this project is used as part of a research project you should cite
152
- the [Pinpoint repository][Pinpoint]. Please email
153
- Dan ([dbirman@uw.edu](mailto:dbirman@uw.edu)) if you have questions.
154
-
155
- Please reach out to Kenneth ([kjy5@uw.edu](mailto:kjy5@uw.edu)) for questions
156
- about the Electrophysiology Manipulator Link server. Bugs may be reported
157
- through the issues tab.
158
-
159
- [Pinpoint]: https://github.com/VirtualBrainLab/Pinpoint
160
-
161
- [StopSignal]: https://github.com/VirtualBrainLab/StopSignal
162
-
163
- [docs]: https://virtualbrainlab.org/ephys_link/installation_and_use.html
@@ -1,26 +0,0 @@
1
- ephys_link/__about__.py,sha256=G2LXGwvaI_1j2mcOG-ROOoWXJfdi2T32W0u5v4FMAh4,25
2
- ephys_link/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- ephys_link/__main__.py,sha256=N-vdBEDSdAJw8f3Xz8Ncwk_ymimgoC1I60qh75-uDno,2556
4
- ephys_link/common.py,sha256=QJPKIXmFwsMVSeEkKSkXSpyidgXpWWW2YIBd2yM1Itk,1302
5
- ephys_link/emergency_stop.py,sha256=Ngq5pqgFR4LKxb5AKwbYhItSRq87AjEZNoRi_fqr_co,2278
6
- ephys_link/gui.py,sha256=zt-Mpag35CSxsEc8QbBIUB7oDzIuy0BAtZGW_WGciak,5924
7
- ephys_link/platform_handler.py,sha256=3jF9Wi4OMc861VkoBNACfgGsbrQPgJrRkKIMOiNr8So,19432
8
- ephys_link/platform_manipulator.py,sha256=AK9XTw1YzAUDhYXaZQxnfbuftBSXokeFkw-xq_n9q2Y,954
9
- ephys_link/server.py,sha256=RlxkjoHsLeaGlrW-NQ1VI1GFjPCKC_YhlFm7qwjvu5A,16641
10
- ephys_link/platforms/__init__.py,sha256=CbWkSRV0ERpUjcqNNslmf-YHSZpEyKJBDjOsV6_mhak,130
11
- ephys_link/platforms/new_scale_handler.py,sha256=x5ElQMYFi3SsK0cO0yoz2j5FRhGB0cnJ5JWCIDnQNMg,5205
12
- ephys_link/platforms/new_scale_manipulator.py,sha256=AZO00XqWS7saueWQYeCI7FOU8JsoL0BE89J9gdw_AYo,11877
13
- ephys_link/platforms/new_scale_pathfinder_handler.py,sha256=cNT753Ex55F8PuQDeH7MlFObziTji8sHZmtlVdzwqaI,7692
14
- ephys_link/platforms/sensapex_handler.py,sha256=pok81D1vVEpoYcaMhXrsC0KTpeKftRMXWVditgRA3yw,5843
15
- ephys_link/platforms/sensapex_manipulator.py,sha256=gUWz7T-ZEn78opIVzDZEV0YsKcbCdZX7DI5YwGjDw9E,8303
16
- ephys_link/platforms/ump3_handler.py,sha256=vzt2rFU-OMRQOoz887wW-J6phapCiuiSEjhQWRqk6uQ,1873
17
- ephys_link/platforms/ump3_manipulator.py,sha256=4It5pwMoyPRKIab0vraYanG5V2QJUrl8wHEpnca9JMg,5986
18
- ephys_link/resources/CP210xManufacturing.dll,sha256=aM9k_XABjkq0TOMiIw8HeteB40zqEkUDNO8wo91EdYI,810232
19
- ephys_link/resources/NstMotorCtrl.dll,sha256=Xtpr3vBcxhcsOUGvgVEwYtGPvKEqDctIUGCK36GfU2Q,155136
20
- ephys_link/resources/SiUSBXp.dll,sha256=187zlclZNNezCkU1o1CbICRAmKWJxbh8ahP6L6wo-_Y,469752
21
- ephys_link/resources/libum.dll,sha256=YaD4dwiSNohx-XxHjx2eQWPOBEVvUIXARvx37e_yqNw,316316
22
- ephys_link-1.3.0b2.dist-info/METADATA,sha256=utAv_I0FyEsU0O5pe-2Da_YrdnWxArFoc0uaDZ-P7Nk,7835
23
- ephys_link-1.3.0b2.dist-info/WHEEL,sha256=osohxoshIHTFJFVPhsi1UkZuLRGMHRXZzwEBW2ezjrc,87
24
- ephys_link-1.3.0b2.dist-info/entry_points.txt,sha256=o8wV3AdnJ9o47vg9ymKxPNVq9pMdPq8UZHE_iyAJx-k,124
25
- ephys_link-1.3.0b2.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
26
- ephys_link-1.3.0b2.dist-info/RECORD,,