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
|
@@ -1,148 +1,176 @@
|
|
|
1
|
-
"""Binding methods for Ephys Link manipulator platforms.
|
|
2
|
-
|
|
3
|
-
Definition of the methods a platform binding class must implement to be used by Ephys Link.
|
|
4
|
-
|
|
5
|
-
Usage:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
54
|
-
:
|
|
55
|
-
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
@abstractmethod
|
|
59
|
-
async def
|
|
60
|
-
"""Get
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
1
|
+
"""Binding methods for Ephys Link manipulator platforms.
|
|
2
|
+
|
|
3
|
+
Definition of the methods a platform binding class must implement to be used by Ephys Link.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
Implement the BaseBindings class when defining a platform binding to ensure it supports the necessary methods.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
|
|
11
|
+
from vbl_aquarium.models.unity import Vector3, Vector4
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseBinding(ABC):
|
|
15
|
+
"""Base class to enforce bindings manipulator platforms will support.
|
|
16
|
+
|
|
17
|
+
No need to catch exceptions as the [Platform Handler][ephys_link.back_end.platform_handler] will catch them.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def get_display_name() -> str:
|
|
23
|
+
"""Get the full display name of the platform.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Full display name of the platform.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def get_cli_name() -> str:
|
|
32
|
+
"""Get the name of the platform for CLI usage.
|
|
33
|
+
|
|
34
|
+
This is the value used to identify the platform when using the `-t` flag in the CLI.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Name of the platform to use on the CLI.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def get_axes_count(self) -> int:
|
|
42
|
+
"""Get the number of axes for the current platform.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Number of axes.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def get_dimensions(self) -> Vector4:
|
|
50
|
+
"""Get the dimensions of the manipulators on the current platform (mm).
|
|
51
|
+
|
|
52
|
+
For 3-axis manipulators, copy the dimension of the axis parallel to the probe into w.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Dimensions of the manipulators.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
async def get_manipulators(self) -> list[str]:
|
|
60
|
+
"""Get a list of available manipulators on the current platform.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
List of manipulator IDs.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
async def get_position(self, manipulator_id: str) -> Vector4:
|
|
68
|
+
"""Get the current position of a manipulator.
|
|
69
|
+
|
|
70
|
+
These will be the translation values of the manipulator (mm), so they may need to be rotated to unified space.
|
|
71
|
+
For 3-axis manipulators, copy the position of the axis parallel to the probe into w.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
manipulator_id: Manipulator ID.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Current position of the manipulator in platform space (mm).
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
@abstractmethod
|
|
81
|
+
async def get_angles(self, manipulator_id: str) -> Vector3:
|
|
82
|
+
"""Get the current rotation angles of a manipulator in Yaw, Pitch, Roll (degrees).
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
manipulator_id: Manipulator ID.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Current angles of the manipulator.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
@abstractmethod
|
|
92
|
+
async def get_shank_count(self, manipulator_id: str) -> int:
|
|
93
|
+
"""Get the number of shanks on a manipulator.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
manipulator_id: Manipulator ID.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Number of shanks on the manipulator.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
@abstractmethod
|
|
103
|
+
def get_movement_tolerance(self) -> float:
|
|
104
|
+
"""Get the tolerance for how close the final position must be to the target position in a movement (mm).
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Movement tolerance (mm).
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
@abstractmethod
|
|
111
|
+
async def set_position(self, manipulator_id: str, position: Vector4, speed: float) -> Vector4:
|
|
112
|
+
"""Set the position of a manipulator.
|
|
113
|
+
|
|
114
|
+
This will directly set the position in the original platform space.
|
|
115
|
+
For 3-axis manipulators, the first 3 values of the position will be used.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
manipulator_id: Manipulator ID.
|
|
119
|
+
position: Platform space position to set the manipulator to (mm).
|
|
120
|
+
speed: Speed to move the manipulator to the position (mm/s).
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Final position of the manipulator in platform space (mm).
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
@abstractmethod
|
|
127
|
+
async def set_depth(self, manipulator_id: str, depth: float, speed: float) -> float:
|
|
128
|
+
"""Set the depth of a manipulator.
|
|
129
|
+
|
|
130
|
+
This will directly set the depth stage in the original platform space.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
manipulator_id: Manipulator ID.
|
|
134
|
+
depth: Depth to set the manipulator to (mm).
|
|
135
|
+
speed: Speed to move the manipulator to the depth (mm/s).
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Final depth of the manipulator in platform space (mm).
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
async def stop(self, manipulator_id: str) -> None:
|
|
143
|
+
"""Stop a manipulator.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
manipulator_id: Manipulator ID.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
@abstractmethod
|
|
150
|
+
def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
|
|
151
|
+
"""Convert platform space coordinates to unified space coordinates.
|
|
152
|
+
|
|
153
|
+
This is an axes-swapping transformation.
|
|
154
|
+
|
|
155
|
+
Unified coordinate space is the standard left-handed cartesian coordinate system
|
|
156
|
+
with an additional depth axis pointing from the base of the probe to the tip.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
platform_space: Platform space coordinates.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Unified space coordinates.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
@abstractmethod
|
|
166
|
+
def unified_space_to_platform_space(self, unified_space: Vector4) -> Vector4:
|
|
167
|
+
"""Convert unified space coordinates to platform space coordinates.
|
|
168
|
+
|
|
169
|
+
This is an axes-swapping transformation.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
unified_space: Unified space coordinates.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Platform space coordinates.
|
|
176
|
+
"""
|
|
@@ -1,130 +1,127 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from rich.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
"""
|
|
56
|
-
self._repeatable_log(INFO, f"[b blue]{label}", msg)
|
|
57
|
-
|
|
58
|
-
def error_print(self, label: str, msg: str) -> None:
|
|
59
|
-
"""Print an error message to the console.
|
|
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
|
-
return f"{type(exception).__name__}: {exception}"
|
|
86
|
-
|
|
87
|
-
def exception_error_print(self, label: str, exception: Exception) -> None:
|
|
88
|
-
"""Print an error message with exception details to the console.
|
|
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
|
-
self._repeat_counter
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# Log new message.
|
|
129
|
-
self._log.log(log_type, f"{label}:[/] {message}")
|
|
130
|
-
self._last_message = message_set
|
|
1
|
+
"""Console class for printing messages to the console.
|
|
2
|
+
|
|
3
|
+
Configure the console to print error and debug messages.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
Create a Console object and call the appropriate method to print messages.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
|
|
10
|
+
from typing import final
|
|
11
|
+
|
|
12
|
+
from rich.logging import RichHandler
|
|
13
|
+
from rich.traceback import install
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@final
|
|
17
|
+
class Console:
|
|
18
|
+
def __init__(self, *, enable_debug: bool) -> None:
|
|
19
|
+
"""Initialize console properties.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
enable_debug: Enable debug mode.
|
|
23
|
+
"""
|
|
24
|
+
# Repeat message fields.
|
|
25
|
+
self._last_message = (0, "", "")
|
|
26
|
+
self._repeat_counter = 0
|
|
27
|
+
|
|
28
|
+
# Config logger.
|
|
29
|
+
basicConfig(
|
|
30
|
+
format="%(message)s",
|
|
31
|
+
datefmt="[%I:%M:%S %p]",
|
|
32
|
+
handlers=[RichHandler(rich_tracebacks=True, markup=True)],
|
|
33
|
+
)
|
|
34
|
+
self._log = getLogger("rich")
|
|
35
|
+
self._log.setLevel(DEBUG if enable_debug else INFO)
|
|
36
|
+
|
|
37
|
+
# Install Rich traceback.
|
|
38
|
+
_ = install()
|
|
39
|
+
|
|
40
|
+
def debug_print(self, label: str, msg: str) -> None:
|
|
41
|
+
"""Print a debug message to the console.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
label: Label for the debug message.
|
|
45
|
+
msg: Debug message to print.
|
|
46
|
+
"""
|
|
47
|
+
self._repeatable_log(DEBUG, f"[b green]{label}", f"[green]{msg}")
|
|
48
|
+
|
|
49
|
+
def info_print(self, label: str, msg: str) -> None:
|
|
50
|
+
"""Print info to console.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
label: Label for the message.
|
|
54
|
+
msg: Message to print.
|
|
55
|
+
"""
|
|
56
|
+
self._repeatable_log(INFO, f"[b blue]{label}", msg)
|
|
57
|
+
|
|
58
|
+
def error_print(self, label: str, msg: str) -> None:
|
|
59
|
+
"""Print an error message to the console.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
label: Label for the error message.
|
|
63
|
+
msg: Error message to print.
|
|
64
|
+
"""
|
|
65
|
+
self._repeatable_log(ERROR, f"[b red]{label}", f"[red]{msg}")
|
|
66
|
+
|
|
67
|
+
def critical_print(self, msg: str) -> None:
|
|
68
|
+
"""Print a critical message to the console.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
msg: Critical message to print.
|
|
72
|
+
"""
|
|
73
|
+
self._log.critical(f"[b i red]{msg}")
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def pretty_exception(exception: Exception) -> str:
|
|
77
|
+
"""Pretty print an exception.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
exception: Exception to pretty print.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Pretty printed exception.
|
|
84
|
+
"""
|
|
85
|
+
return f"{type(exception).__name__}: {exception}"
|
|
86
|
+
|
|
87
|
+
def exception_error_print(self, label: str, exception: Exception) -> None:
|
|
88
|
+
"""Print an error message with exception details to the console.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
label: Label for the error message.
|
|
92
|
+
exception: Exception to print.
|
|
93
|
+
"""
|
|
94
|
+
self._log.exception(f"[b magenta]{label}:[/] [magenta]{Console.pretty_exception(exception)}")
|
|
95
|
+
|
|
96
|
+
# Helper methods.
|
|
97
|
+
def _repeatable_log(self, log_type: int, label: str, message: str) -> None:
|
|
98
|
+
"""Add a row to the output table.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
log_type: Type of log.
|
|
102
|
+
label: Label for the message.
|
|
103
|
+
message: Message.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
# Compute if this is a repeated message.
|
|
107
|
+
message_set = (log_type, label, message)
|
|
108
|
+
if message_set == self._last_message:
|
|
109
|
+
# Handle repeat.
|
|
110
|
+
self._repeat_counter += 1
|
|
111
|
+
|
|
112
|
+
# Add an ellipsis row for first repeat.
|
|
113
|
+
if self._repeat_counter == 1:
|
|
114
|
+
self._log.log(log_type, "...")
|
|
115
|
+
else:
|
|
116
|
+
# Handle novel message.
|
|
117
|
+
if self._repeat_counter > 0:
|
|
118
|
+
# Complete previous repeat.
|
|
119
|
+
self._log.log(
|
|
120
|
+
self._last_message[0],
|
|
121
|
+
f"{self._last_message[1]}:[/] {self._last_message[2]}[/] x {self._repeat_counter}",
|
|
122
|
+
)
|
|
123
|
+
self._repeat_counter = 0
|
|
124
|
+
|
|
125
|
+
# Log new message.
|
|
126
|
+
self._log.log(log_type, f"{label}:[/] {message}")
|
|
127
|
+
self._last_message = message_set
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Globally accessible constants"""
|
|
2
|
+
|
|
3
|
+
from os.path import abspath, dirname, join
|
|
4
|
+
|
|
5
|
+
# Ephys Link ASCII.
|
|
6
|
+
ASCII = r"""
|
|
7
|
+
______ _ _ _ _
|
|
8
|
+
| ____| | | | | (_) | |
|
|
9
|
+
| |__ _ __ | |__ _ _ ___ | | _ _ __ | | __
|
|
10
|
+
| __| | '_ \| '_ \| | | / __| | | | | '_ \| |/ /
|
|
11
|
+
| |____| |_) | | | | |_| \__ \ | |____| | | | | <
|
|
12
|
+
|______| .__/|_| |_|\__, |___/ |______|_|_| |_|_|\_\
|
|
13
|
+
| | __/ |
|
|
14
|
+
|_| |___/
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Absolute path to the resource folder.
|
|
18
|
+
PACKAGE_DIRECTORY = dirname(dirname(abspath(__file__)))
|
|
19
|
+
RESOURCES_DIRECTORY = join(PACKAGE_DIRECTORY, "resources")
|
|
20
|
+
BINDINGS_DIRECTORY = join(PACKAGE_DIRECTORY, "bindings")
|
|
21
|
+
|
|
22
|
+
# Ephys Link Port
|
|
23
|
+
PORT = 3000
|