ephys-link 1.2.5__tar.gz → 1.2.8__tar.gz
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-1.2.5 → ephys_link-1.2.8}/PKG-INFO +8 -1
- {ephys_link-1.2.5 → ephys_link-1.2.8}/README.md +6 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/pyproject.toml +2 -0
- ephys_link-1.2.8/src/ephys_link/__about__.py +1 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/__main__.py +13 -11
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/common.py +12 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/server.py +77 -38
- ephys_link-1.2.5/src/ephys_link/__about__.py +0 -1
- {ephys_link-1.2.5 → ephys_link-1.2.8}/.gitignore +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/LICENSE +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/assets/icon.ico +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/ephys_link.spec +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/scripts/__init__.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/scripts/move_tester.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/__init__.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/emergency_stop.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/gui.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platform_handler.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platform_manipulator.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/__init__.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/new_scale_handler.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/new_scale_manipulator.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/new_scale_pathfinder_handler.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/sensapex_handler.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/sensapex_manipulator.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/ump3_handler.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/ump3_manipulator.py +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/resources/CP210xManufacturing.dll +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/resources/NstMotorCtrl.dll +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/resources/SiUSBXp.dll +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/resources/libum.dll +0 -0
- {ephys_link-1.2.5 → ephys_link-1.2.8}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ephys-link
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments.
|
|
5
5
|
Project-URL: Documentation, https://virtualbrainlab.org/ephys_link/installation_and_use.html
|
|
6
6
|
Project-URL: Issues, https://github.com/VirtualBrainLab/ephys-link/issues
|
|
@@ -31,6 +31,7 @@ Requires-Dist: platformdirs==4.2.0
|
|
|
31
31
|
Requires-Dist: pyserial==3.5
|
|
32
32
|
Requires-Dist: python-socketio==5.11.1
|
|
33
33
|
Requires-Dist: pythonnet==3.0.3
|
|
34
|
+
Requires-Dist: requests==2.31.0
|
|
34
35
|
Requires-Dist: sensapex==1.400.0
|
|
35
36
|
Requires-Dist: wheel==0.42.0
|
|
36
37
|
Description-Content-Type: text/markdown
|
|
@@ -86,6 +87,12 @@ the [API reference](https://virtualbrainlab.org/api_reference_ephys_link.html).
|
|
|
86
87
|
is currently designed to interface with local/desktop instances of Pinpoint. It
|
|
87
88
|
will not work with the web browser versions of Pinpoint at this time.
|
|
88
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
|
+
|
|
89
96
|
## Install as Standalone Executable
|
|
90
97
|
|
|
91
98
|
1. Download the latest executable from
|
|
@@ -49,6 +49,12 @@ the [API reference](https://virtualbrainlab.org/api_reference_ephys_link.html).
|
|
|
49
49
|
is currently designed to interface with local/desktop instances of Pinpoint. It
|
|
50
50
|
will not work with the web browser versions of Pinpoint at this time.
|
|
51
51
|
|
|
52
|
+
## Launch from Pinpoint (Recommended)
|
|
53
|
+
|
|
54
|
+
Pinpoint comes bundled with the correct version of Ephys Link. If you are using Pinpoint on the same computer your
|
|
55
|
+
manipulators are connected to, you can launch the server from within Pinpoint. Follow the instructions in
|
|
56
|
+
the [Pinpoint documentation](https://virtualbrainlab.org/pinpoint/tutorials/tutorial_ephys_link.html#configure-and-launch-ephys-link).
|
|
57
|
+
|
|
52
58
|
## Install as Standalone Executable
|
|
53
59
|
|
|
54
60
|
1. Download the latest executable from
|
|
@@ -35,6 +35,7 @@ dependencies = [
|
|
|
35
35
|
"pyserial==3.5",
|
|
36
36
|
"python-socketio==5.11.1",
|
|
37
37
|
"pythonnet==3.0.3",
|
|
38
|
+
"requests==2.31.0",
|
|
38
39
|
"wheel==0.42.0",
|
|
39
40
|
"sensapex==1.400.0",
|
|
40
41
|
]
|
|
@@ -91,6 +92,7 @@ dependencies = [
|
|
|
91
92
|
]
|
|
92
93
|
[tool.hatch.envs.exe.scripts]
|
|
93
94
|
build = "pyinstaller.exe ephys_link.spec -y"
|
|
95
|
+
build_clean = "pyinstaller.exe ephys_link.spec -y --clean"
|
|
94
96
|
|
|
95
97
|
[tool.coverage.run]
|
|
96
98
|
source_pkgs = ["ephys_link", "tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.8"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from argparse import ArgumentParser
|
|
2
|
+
from sys import argv
|
|
2
3
|
|
|
3
4
|
from ephys_link import common as com
|
|
4
5
|
from ephys_link.__about__ import __version__ as version
|
|
@@ -9,11 +10,12 @@ from ephys_link.server import Server
|
|
|
9
10
|
# Setup argument parser.
|
|
10
11
|
parser = ArgumentParser(
|
|
11
12
|
description="Electrophysiology Manipulator Link: a websocket interface for"
|
|
12
|
-
" manipulators in electrophysiology experiments",
|
|
13
|
+
" manipulators in electrophysiology experiments.",
|
|
13
14
|
prog="python -m ephys-link",
|
|
14
15
|
)
|
|
16
|
+
parser.add_argument("-b", "--background", dest="background", action="store_true", help="Skip configuration window.")
|
|
15
17
|
parser.add_argument(
|
|
16
|
-
"-
|
|
18
|
+
"-i", "--ignore-updates", dest="ignore_updates", action="store_true", help="Skip (ignore) checking for updates."
|
|
17
19
|
)
|
|
18
20
|
parser.add_argument(
|
|
19
21
|
"-t",
|
|
@@ -21,23 +23,23 @@ parser.add_argument(
|
|
|
21
23
|
type=str,
|
|
22
24
|
dest="type",
|
|
23
25
|
default="sensapex",
|
|
24
|
-
help='Manipulator type (i.e. "sensapex", "new_scale", or "new_scale_pathfinder").
|
|
26
|
+
help='Manipulator type (i.e. "sensapex", "new_scale", or "new_scale_pathfinder"). Default: "sensapex".',
|
|
25
27
|
)
|
|
26
|
-
parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Enable debug mode")
|
|
28
|
+
parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Enable debug mode.")
|
|
27
29
|
parser.add_argument(
|
|
28
30
|
"-p",
|
|
29
31
|
"--port",
|
|
30
32
|
type=int,
|
|
31
33
|
default=8081,
|
|
32
34
|
dest="port",
|
|
33
|
-
help="Port to serve on. Default: 8081 (avoids conflict with other HTTP servers)",
|
|
35
|
+
help="Port to serve on. Default: 8081 (avoids conflict with other HTTP servers).",
|
|
34
36
|
)
|
|
35
37
|
parser.add_argument(
|
|
36
38
|
"--pathfinder_port",
|
|
37
39
|
type=int,
|
|
38
40
|
default=8080,
|
|
39
41
|
dest="pathfinder_port",
|
|
40
|
-
help="Port New Scale Pathfinder's server is on. Default: 8080",
|
|
42
|
+
help="Port New Scale Pathfinder's server is on. Default: 8080.",
|
|
41
43
|
)
|
|
42
44
|
parser.add_argument(
|
|
43
45
|
"-s",
|
|
@@ -46,14 +48,14 @@ parser.add_argument(
|
|
|
46
48
|
default="no-e-stop",
|
|
47
49
|
dest="serial",
|
|
48
50
|
nargs="?",
|
|
49
|
-
help="Emergency stop serial port (i.e. COM3). Default: disables emergency stop",
|
|
51
|
+
help="Emergency stop serial port (i.e. COM3). Default: disables emergency stop.",
|
|
50
52
|
)
|
|
51
53
|
parser.add_argument(
|
|
52
54
|
"-v",
|
|
53
55
|
"--version",
|
|
54
56
|
action="version",
|
|
55
57
|
version=f"Electrophysiology Manipulator Link v{version}",
|
|
56
|
-
help="Print version and exit",
|
|
58
|
+
help="Print version and exit.",
|
|
57
59
|
)
|
|
58
60
|
|
|
59
61
|
|
|
@@ -63,8 +65,8 @@ def main() -> None:
|
|
|
63
65
|
# Parse arguments.
|
|
64
66
|
args = parser.parse_args()
|
|
65
67
|
|
|
66
|
-
# Launch GUI if
|
|
67
|
-
if
|
|
68
|
+
# Launch GUI if there are no CLI arguments.
|
|
69
|
+
if len(argv) == 1:
|
|
68
70
|
gui = GUI()
|
|
69
71
|
gui.launch()
|
|
70
72
|
return None
|
|
@@ -81,7 +83,7 @@ def main() -> None:
|
|
|
81
83
|
e_stop.watch()
|
|
82
84
|
|
|
83
85
|
# Launch with parsed arguments on main thread.
|
|
84
|
-
server.launch(args.type, args.port, args.pathfinder_port)
|
|
86
|
+
server.launch(args.type, args.port, args.pathfinder_port, args.ignore_updates)
|
|
85
87
|
|
|
86
88
|
|
|
87
89
|
if __name__ == "__main__":
|
|
@@ -12,6 +12,18 @@ from typing import TypedDict
|
|
|
12
12
|
# Debugging flag
|
|
13
13
|
DEBUG = False
|
|
14
14
|
|
|
15
|
+
# Ephys Link ASCII
|
|
16
|
+
ASCII = r"""
|
|
17
|
+
______ _ _ _ _
|
|
18
|
+
| ____| | | | | (_) | |
|
|
19
|
+
| |__ _ __ | |__ _ _ ___ | | _ _ __ | | __
|
|
20
|
+
| __| | '_ \| '_ \| | | / __| | | | | '_ \| |/ /
|
|
21
|
+
| |____| |_) | | | | |_| \__ \ | |____| | | | | <
|
|
22
|
+
|______| .__/|_| |_|\__, |___/ |______|_|_| |_|_|\_\
|
|
23
|
+
| | __/ |
|
|
24
|
+
|_| |___/
|
|
25
|
+
"""
|
|
26
|
+
|
|
15
27
|
|
|
16
28
|
def dprint(message: str) -> None:
|
|
17
29
|
"""Print message if debug is enabled.
|
|
@@ -11,17 +11,30 @@ every event, the server does the following:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
import sys
|
|
14
|
+
from json import loads
|
|
16
15
|
from signal import SIGINT, SIGTERM, signal
|
|
16
|
+
from sys import exit
|
|
17
17
|
from typing import TYPE_CHECKING, Any
|
|
18
18
|
|
|
19
|
-
import socketio
|
|
20
19
|
from aiohttp import web
|
|
21
20
|
from aiohttp.web_runner import GracefulExit
|
|
22
|
-
|
|
23
|
-
from
|
|
24
|
-
from
|
|
21
|
+
from packaging import version
|
|
22
|
+
from requests import get
|
|
23
|
+
from requests.exceptions import ConnectionError
|
|
24
|
+
from socketio import AsyncServer
|
|
25
|
+
|
|
26
|
+
from ephys_link.__about__ import __version__
|
|
27
|
+
from ephys_link.common import (
|
|
28
|
+
ASCII,
|
|
29
|
+
CanWriteInputDataFormat,
|
|
30
|
+
DriveToDepthInputDataFormat,
|
|
31
|
+
DriveToDepthOutputData,
|
|
32
|
+
GotoPositionInputDataFormat,
|
|
33
|
+
InsideBrainInputDataFormat,
|
|
34
|
+
PositionalOutputData,
|
|
35
|
+
StateOutputData,
|
|
36
|
+
dprint,
|
|
37
|
+
)
|
|
25
38
|
from ephys_link.platforms.new_scale_handler import NewScaleHandler
|
|
26
39
|
from ephys_link.platforms.new_scale_pathfinder_handler import NewScalePathfinderHandler
|
|
27
40
|
from ephys_link.platforms.sensapex_handler import SensapexHandler
|
|
@@ -34,7 +47,7 @@ if TYPE_CHECKING:
|
|
|
34
47
|
class Server:
|
|
35
48
|
def __init__(self):
|
|
36
49
|
# Server and Socketio
|
|
37
|
-
self.sio =
|
|
50
|
+
self.sio = AsyncServer()
|
|
38
51
|
self.app = web.Application()
|
|
39
52
|
|
|
40
53
|
# Is there a client connected?
|
|
@@ -117,7 +130,7 @@ class Server:
|
|
|
117
130
|
:return: Version number as defined in :mod:`ephys_link.__about__`.
|
|
118
131
|
:rtype: str
|
|
119
132
|
"""
|
|
120
|
-
return
|
|
133
|
+
return __version__
|
|
121
134
|
|
|
122
135
|
async def get_manipulators(self, _) -> str:
|
|
123
136
|
"""Get the list of discoverable manipulators.
|
|
@@ -127,7 +140,7 @@ class Server:
|
|
|
127
140
|
:return: :class:`ephys_link.common.GetManipulatorsOutputData` as JSON formatted string.
|
|
128
141
|
:rtype: str
|
|
129
142
|
"""
|
|
130
|
-
|
|
143
|
+
dprint("[EVENT]\t\t Get discoverable manipulators")
|
|
131
144
|
|
|
132
145
|
return self.platform.get_manipulators().json()
|
|
133
146
|
|
|
@@ -141,7 +154,7 @@ class Server:
|
|
|
141
154
|
:return: Error message on error, empty string otherwise.
|
|
142
155
|
:rtype: str
|
|
143
156
|
"""
|
|
144
|
-
|
|
157
|
+
dprint(f"[EVENT]\t\t Register manipulator: {manipulator_id}")
|
|
145
158
|
|
|
146
159
|
return self.platform.register_manipulator(manipulator_id)
|
|
147
160
|
|
|
@@ -155,7 +168,7 @@ class Server:
|
|
|
155
168
|
:return: Error message on error, empty string otherwise.
|
|
156
169
|
:rtype: str
|
|
157
170
|
"""
|
|
158
|
-
|
|
171
|
+
dprint(f"[EVENT]\t\t Unregister manipulator: {manipulator_id}")
|
|
159
172
|
|
|
160
173
|
return self.platform.unregister_manipulator(manipulator_id)
|
|
161
174
|
|
|
@@ -169,7 +182,7 @@ class Server:
|
|
|
169
182
|
:return: :class:`ephys_link.common.PositionalOutputData` as JSON formatted string.
|
|
170
183
|
:rtype: str
|
|
171
184
|
"""
|
|
172
|
-
#
|
|
185
|
+
# dprint(f"[EVENT]\t\t Get position of manipulator" f" {manipulator_id}")
|
|
173
186
|
|
|
174
187
|
return self.platform.get_pos(manipulator_id).json()
|
|
175
188
|
|
|
@@ -210,18 +223,18 @@ class Server:
|
|
|
210
223
|
:rtype: str
|
|
211
224
|
"""
|
|
212
225
|
try:
|
|
213
|
-
parsed_data:
|
|
226
|
+
parsed_data: GotoPositionInputDataFormat = loads(data)
|
|
214
227
|
manipulator_id = parsed_data["manipulator_id"]
|
|
215
228
|
pos = parsed_data["pos"]
|
|
216
229
|
speed = parsed_data["speed"]
|
|
217
230
|
except KeyError:
|
|
218
231
|
print(f"[ERROR]\t\t Invalid goto_pos data: {data}\n")
|
|
219
|
-
return
|
|
232
|
+
return PositionalOutputData([], "Invalid data format").json()
|
|
220
233
|
except Exception as e:
|
|
221
234
|
print(f"[ERROR]\t\t Error in goto_pos: {e}\n")
|
|
222
|
-
return
|
|
235
|
+
return PositionalOutputData([], "Error in goto_pos").json()
|
|
223
236
|
else:
|
|
224
|
-
|
|
237
|
+
dprint(f"[EVENT]\t\t Move manipulator {manipulator_id} " f"to position {pos}")
|
|
225
238
|
goto_result = await self.platform.goto_pos(manipulator_id, pos, speed)
|
|
226
239
|
return goto_result.json()
|
|
227
240
|
|
|
@@ -236,18 +249,18 @@ class Server:
|
|
|
236
249
|
:rtype: str
|
|
237
250
|
"""
|
|
238
251
|
try:
|
|
239
|
-
parsed_data:
|
|
252
|
+
parsed_data: DriveToDepthInputDataFormat = loads(data)
|
|
240
253
|
manipulator_id = parsed_data["manipulator_id"]
|
|
241
254
|
depth = parsed_data["depth"]
|
|
242
255
|
speed = parsed_data["speed"]
|
|
243
256
|
except KeyError:
|
|
244
257
|
print(f"[ERROR]\t\t Invalid drive_to_depth data: {data}\n")
|
|
245
|
-
return
|
|
258
|
+
return DriveToDepthOutputData(-1, "Invalid data " "format").json()
|
|
246
259
|
except Exception as e:
|
|
247
260
|
print(f"[ERROR]\t\t Error in drive_to_depth: {e}\n")
|
|
248
|
-
return
|
|
261
|
+
return DriveToDepthOutputData(-1, "Error in drive_to_depth").json()
|
|
249
262
|
else:
|
|
250
|
-
|
|
263
|
+
dprint(f"[EVENT]\t\t Drive manipulator {manipulator_id} to depth {depth}")
|
|
251
264
|
drive_result = await self.platform.drive_to_depth(manipulator_id, depth, speed)
|
|
252
265
|
return drive_result.json()
|
|
253
266
|
|
|
@@ -262,17 +275,17 @@ class Server:
|
|
|
262
275
|
:rtype: str
|
|
263
276
|
"""
|
|
264
277
|
try:
|
|
265
|
-
parsed_data:
|
|
278
|
+
parsed_data: InsideBrainInputDataFormat = loads(data)
|
|
266
279
|
manipulator_id = parsed_data["manipulator_id"]
|
|
267
280
|
inside = parsed_data["inside"]
|
|
268
281
|
except KeyError:
|
|
269
282
|
print(f"[ERROR]\t\t Invalid set_inside_brain data: {data}\n")
|
|
270
|
-
return
|
|
283
|
+
return StateOutputData(False, "Invalid data format").json()
|
|
271
284
|
except Exception as e:
|
|
272
285
|
print(f"[ERROR]\t\t Error in inside_brain: {e}\n")
|
|
273
|
-
return
|
|
286
|
+
return StateOutputData(False, "Error in set_inside_brain").json()
|
|
274
287
|
else:
|
|
275
|
-
|
|
288
|
+
dprint(f"[EVENT]\t\t Set manipulator {manipulator_id} inside brain to {inside}")
|
|
276
289
|
return self.platform.set_inside_brain(manipulator_id, inside).json()
|
|
277
290
|
|
|
278
291
|
async def calibrate(self, _, manipulator_id: str) -> str:
|
|
@@ -285,7 +298,7 @@ class Server:
|
|
|
285
298
|
:return: Error message on error, empty string otherwise.
|
|
286
299
|
:rtype: str
|
|
287
300
|
"""
|
|
288
|
-
|
|
301
|
+
dprint(f"[EVENT]\t\t Calibrate manipulator" f" {manipulator_id}")
|
|
289
302
|
|
|
290
303
|
return await self.platform.calibrate(manipulator_id, self.sio)
|
|
291
304
|
|
|
@@ -299,7 +312,7 @@ class Server:
|
|
|
299
312
|
:return: Error message on error, empty string otherwise.
|
|
300
313
|
:rtype: str
|
|
301
314
|
"""
|
|
302
|
-
|
|
315
|
+
dprint(f"[EVENT]\t\t Bypass calibration of manipulator" f" {manipulator_id}")
|
|
303
316
|
|
|
304
317
|
return self.platform.bypass_calibration(manipulator_id)
|
|
305
318
|
|
|
@@ -314,18 +327,18 @@ class Server:
|
|
|
314
327
|
:rtype: str
|
|
315
328
|
"""
|
|
316
329
|
try:
|
|
317
|
-
parsed_data:
|
|
330
|
+
parsed_data: CanWriteInputDataFormat = loads(data)
|
|
318
331
|
manipulator_id = parsed_data["manipulator_id"]
|
|
319
332
|
can_write = parsed_data["can_write"]
|
|
320
333
|
hours = parsed_data["hours"]
|
|
321
334
|
except KeyError:
|
|
322
335
|
print(f"[ERROR]\t\t Invalid set_can_write data: {data}\n")
|
|
323
|
-
return
|
|
336
|
+
return StateOutputData(False, "Invalid data " "format").json()
|
|
324
337
|
except Exception as e:
|
|
325
338
|
print(f"[ERROR]\t\t Error in inside_brain: {e}\n")
|
|
326
|
-
return
|
|
339
|
+
return StateOutputData(False, "Error in set_can_write").json()
|
|
327
340
|
else:
|
|
328
|
-
|
|
341
|
+
dprint(f"[EVENT]\t\t Set manipulator {manipulator_id} can_write state to {can_write}")
|
|
329
342
|
return self.platform.set_can_write(manipulator_id, can_write, hours, self.sio).json()
|
|
330
343
|
|
|
331
344
|
def stop(self, _) -> bool:
|
|
@@ -336,7 +349,7 @@ class Server:
|
|
|
336
349
|
:return: True if successful, False otherwise.
|
|
337
350
|
:rtype: bool
|
|
338
351
|
"""
|
|
339
|
-
|
|
352
|
+
dprint("[EVENT]\t\t Stop all manipulators")
|
|
340
353
|
|
|
341
354
|
return self.platform.stop()
|
|
342
355
|
|
|
@@ -356,7 +369,13 @@ class Server:
|
|
|
356
369
|
print(f"[UNKNOWN EVENT]:\t {data}")
|
|
357
370
|
return "UNKNOWN_EVENT"
|
|
358
371
|
|
|
359
|
-
def launch(
|
|
372
|
+
def launch(
|
|
373
|
+
self,
|
|
374
|
+
platform_type: str,
|
|
375
|
+
server_port: int,
|
|
376
|
+
pathfinder_port: int | None = None,
|
|
377
|
+
ignore_updates: bool = False, # noqa: FBT002
|
|
378
|
+
) -> None:
|
|
360
379
|
"""Launch the server.
|
|
361
380
|
|
|
362
381
|
:param platform_type: Parsed argument for platform type.
|
|
@@ -365,6 +384,8 @@ class Server:
|
|
|
365
384
|
:type server_port: int
|
|
366
385
|
:param pathfinder_port: Port New Scale Pathfinder's server is on.
|
|
367
386
|
:type pathfinder_port: int
|
|
387
|
+
:param ignore_updates: Flag to ignore checking for updates.
|
|
388
|
+
:type ignore_updates: bool
|
|
368
389
|
:return: None
|
|
369
390
|
"""
|
|
370
391
|
|
|
@@ -379,16 +400,34 @@ class Server:
|
|
|
379
400
|
elif platform_type == "new_scale_pathfinder":
|
|
380
401
|
self.platform = NewScalePathfinderHandler(pathfinder_port)
|
|
381
402
|
else:
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
# Preamble
|
|
385
|
-
print(
|
|
403
|
+
exit(f"[ERROR]\t\t Invalid manipulator type: {platform_type}")
|
|
404
|
+
|
|
405
|
+
# Preamble.
|
|
406
|
+
print(ASCII)
|
|
407
|
+
print(f"v{__version__}")
|
|
408
|
+
|
|
409
|
+
# Check for newer version.
|
|
410
|
+
if not ignore_updates:
|
|
411
|
+
try:
|
|
412
|
+
version_request = get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags", timeout=10)
|
|
413
|
+
latest_version = version_request.json()[0]["name"]
|
|
414
|
+
if version.parse(latest_version) > version.parse(__version__):
|
|
415
|
+
print(f"New version available: {latest_version}")
|
|
416
|
+
print("Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
|
|
417
|
+
except ConnectionError:
|
|
418
|
+
pass
|
|
419
|
+
|
|
420
|
+
# Explain window.
|
|
421
|
+
print()
|
|
422
|
+
print("This is the Ephys Link server window.")
|
|
423
|
+
print("You may safely leave it running in the background.")
|
|
424
|
+
print("To stop the it, close this window or press CTRL + Pause/Break.")
|
|
425
|
+
print()
|
|
386
426
|
|
|
387
427
|
# List available manipulators
|
|
388
428
|
print("Available Manipulators:")
|
|
389
429
|
print(self.platform.get_manipulators()["manipulators"])
|
|
390
|
-
|
|
391
|
-
print("\n(Shutdown server with CTRL+Pause/Break)\n")
|
|
430
|
+
print()
|
|
392
431
|
|
|
393
432
|
# Mark that server is running
|
|
394
433
|
self.is_running = True
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.5"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ephys_link-1.2.5 → ephys_link-1.2.8}/src/ephys_link/platforms/new_scale_pathfinder_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|