ephys-link 1.3.3__py3-none-any.whl → 2.0.0b1__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 +28 -90
- ephys_link/back_end/__init__.py +0 -0
- ephys_link/back_end/platform_handler.py +298 -0
- ephys_link/back_end/server.py +200 -0
- ephys_link/bindings/__init__.py +0 -0
- ephys_link/bindings/fake_bindings.py +54 -0
- ephys_link/bindings/ump_4_bindings.py +127 -0
- ephys_link/front_end/__init__.py +0 -0
- ephys_link/front_end/cli.py +98 -0
- ephys_link/{gui.py → front_end/gui.py} +93 -95
- ephys_link/util/__init__.py +0 -0
- ephys_link/util/base_bindings.py +133 -0
- ephys_link/util/common.py +121 -0
- ephys_link/util/console.py +112 -0
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0b1.dist-info}/METADATA +6 -4
- ephys_link-2.0.0b1.dist-info/RECORD +25 -0
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0b1.dist-info}/WHEEL +1 -1
- ephys_link/common.py +0 -49
- ephys_link/emergency_stop.py +0 -67
- ephys_link/platform_handler.py +0 -465
- ephys_link/platform_manipulator.py +0 -35
- ephys_link/platforms/__init__.py +0 -5
- ephys_link/platforms/new_scale_handler.py +0 -141
- ephys_link/platforms/new_scale_manipulator.py +0 -312
- ephys_link/platforms/new_scale_pathfinder_handler.py +0 -235
- ephys_link/platforms/sensapex_handler.py +0 -151
- ephys_link/platforms/sensapex_manipulator.py +0 -227
- ephys_link/platforms/ump3_handler.py +0 -57
- ephys_link/platforms/ump3_manipulator.py +0 -147
- ephys_link/server.py +0 -508
- ephys_link-1.3.3.dist-info/RECORD +0 -26
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0b1.dist-info}/entry_points.txt +0 -0
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0b1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# ruff: noqa: T201
|
|
2
|
+
"""Commonly used utility functions and constants."""
|
|
3
|
+
|
|
4
|
+
from os.path import join
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from packaging.version import parse
|
|
8
|
+
from requests import get
|
|
9
|
+
from vbl_aquarium.models.unity import Vector4
|
|
10
|
+
|
|
11
|
+
from ephys_link.__about__ import __version__
|
|
12
|
+
from ephys_link.util.console import Console
|
|
13
|
+
|
|
14
|
+
# Ephys Link ASCII.
|
|
15
|
+
ASCII = r"""
|
|
16
|
+
______ _ _ _ _
|
|
17
|
+
| ____| | | | | (_) | |
|
|
18
|
+
| |__ _ __ | |__ _ _ ___ | | _ _ __ | | __
|
|
19
|
+
| __| | '_ \| '_ \| | | / __| | | | | '_ \| |/ /
|
|
20
|
+
| |____| |_) | | | | |_| \__ \ | |____| | | | | <
|
|
21
|
+
|______| .__/|_| |_|\__, |___/ |______|_|_| |_|_|\_\
|
|
22
|
+
| | __/ |
|
|
23
|
+
|_| |___/
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Absolute path to the resource folder.
|
|
27
|
+
RESOURCES_PATH = join(str(Path(__file__).parent.parent.absolute()), "resources")
|
|
28
|
+
|
|
29
|
+
# Ephys Link Port
|
|
30
|
+
PORT = 3000
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Server startup.
|
|
34
|
+
def server_preamble() -> None:
|
|
35
|
+
"""Print the server startup preamble."""
|
|
36
|
+
print(ASCII)
|
|
37
|
+
print(__version__)
|
|
38
|
+
print()
|
|
39
|
+
print("This is the Ephys Link server window.")
|
|
40
|
+
print("You may safely leave it running in the background.")
|
|
41
|
+
print("To stop it, close this window or press CTRL + Pause/Break.")
|
|
42
|
+
print()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def check_for_updates() -> None:
|
|
46
|
+
"""Check for updates to the Ephys Link."""
|
|
47
|
+
response = get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags", timeout=10)
|
|
48
|
+
latest_version = response.json()[0]["name"]
|
|
49
|
+
if parse(latest_version) > parse(__version__):
|
|
50
|
+
Console.info_print("Update available", latest_version)
|
|
51
|
+
Console.info_print("", "Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Unit conversions
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def mmps_to_umps(mmps: float) -> float:
|
|
58
|
+
"""Convert millimeters per second to micrometers per second.
|
|
59
|
+
|
|
60
|
+
:param mmps: Speed in millimeters per second.
|
|
61
|
+
:type mmps: float
|
|
62
|
+
:returns: Speed in micrometers per second.
|
|
63
|
+
:rtype: float
|
|
64
|
+
"""
|
|
65
|
+
return mmps * 1_000
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def mm_to_um(mm: Vector4) -> Vector4:
|
|
69
|
+
"""Convert millimeters to micrometers.
|
|
70
|
+
|
|
71
|
+
:param mm: Length in millimeters.
|
|
72
|
+
:type mm: Vector4
|
|
73
|
+
:returns: Length in micrometers.
|
|
74
|
+
:rtype: Vector4
|
|
75
|
+
"""
|
|
76
|
+
return mm * 1_000
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def um_to_mm(um: Vector4) -> Vector4:
|
|
80
|
+
"""Convert micrometers to millimeters.
|
|
81
|
+
|
|
82
|
+
:param um: Length in micrometers.
|
|
83
|
+
:type um: Vector4
|
|
84
|
+
:returns: Length in millimeters.
|
|
85
|
+
:rtype: Vector4
|
|
86
|
+
"""
|
|
87
|
+
return um / 1_000
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def vector4_to_array(vector4: Vector4) -> list[float]:
|
|
91
|
+
"""Convert a Vector4 to a list of floats.
|
|
92
|
+
|
|
93
|
+
:param vector4: Vector4 to convert.
|
|
94
|
+
:type vector4: :class:`vbl_aquarium.models.unity.Vector4`
|
|
95
|
+
:return: List of floats.
|
|
96
|
+
:rtype: list[float]
|
|
97
|
+
"""
|
|
98
|
+
return [vector4.x, vector4.y, vector4.z, vector4.w]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def array_to_vector4(array: list[float]) -> Vector4:
|
|
102
|
+
"""Convert a list of floats to a Vector4.
|
|
103
|
+
|
|
104
|
+
:param array: List of floats.
|
|
105
|
+
:type array: list[float]
|
|
106
|
+
:return: First four elements of the list as a Vector4 padded with zeros if necessary.
|
|
107
|
+
:rtype: :class:`vbl_aquarium.models.unity.Vector4`
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def get_element(this_array: list[float], index: int) -> float:
|
|
111
|
+
try:
|
|
112
|
+
return this_array[index]
|
|
113
|
+
except IndexError:
|
|
114
|
+
return 0.0
|
|
115
|
+
|
|
116
|
+
return Vector4(
|
|
117
|
+
x=get_element(array, 0),
|
|
118
|
+
y=get_element(array, 1),
|
|
119
|
+
z=get_element(array, 2),
|
|
120
|
+
w=get_element(array, 3),
|
|
121
|
+
)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# ruff: noqa: T201
|
|
2
|
+
"""Console class for printing messages to the console.
|
|
3
|
+
|
|
4
|
+
Configure the console to print error and debug messages.
|
|
5
|
+
|
|
6
|
+
Usage: Create a Console object and call the appropriate method to print messages.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from traceback import print_exc
|
|
10
|
+
|
|
11
|
+
from colorama import Back, Fore, Style, init
|
|
12
|
+
|
|
13
|
+
# Constants.
|
|
14
|
+
TAB_BLOCK = "\t\t"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Console:
|
|
18
|
+
def __init__(self, *, enable_debug: bool) -> None:
|
|
19
|
+
"""Initialize console properties.
|
|
20
|
+
|
|
21
|
+
:param enable_debug: Enable debug mode.
|
|
22
|
+
:type enable_debug: bool
|
|
23
|
+
"""
|
|
24
|
+
self._enable_debug = enable_debug
|
|
25
|
+
|
|
26
|
+
# Repeat message fields.
|
|
27
|
+
self._last_message = ""
|
|
28
|
+
self._repeat_counter = 1
|
|
29
|
+
|
|
30
|
+
# Initialize colorama.
|
|
31
|
+
init(autoreset=True)
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def error_print(msg: str) -> None:
|
|
35
|
+
"""Print an error message to the console.
|
|
36
|
+
|
|
37
|
+
:param msg: Error message to print.
|
|
38
|
+
:type msg: str
|
|
39
|
+
"""
|
|
40
|
+
print(f"\n{Back.RED}{Style.BRIGHT} ERROR {Style.RESET_ALL}{TAB_BLOCK}{Fore.RED}{msg}")
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def labeled_error_print(label: str, msg: str) -> None:
|
|
44
|
+
"""Print an error message with a label to the console.
|
|
45
|
+
|
|
46
|
+
:param label: Label for the error message.
|
|
47
|
+
:type label: str
|
|
48
|
+
:param msg: Error message to print.
|
|
49
|
+
:type msg: str
|
|
50
|
+
"""
|
|
51
|
+
print(f"\n{Back.RED}{Style.BRIGHT} ERROR {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.RED}{msg}")
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def pretty_exception(exception: Exception) -> str:
|
|
55
|
+
"""Pretty print an exception.
|
|
56
|
+
|
|
57
|
+
:param exception: Exception to pretty print.
|
|
58
|
+
:type exception: Exception
|
|
59
|
+
:return: Pretty printed exception.
|
|
60
|
+
:rtype: str
|
|
61
|
+
"""
|
|
62
|
+
return f"{type(exception).__name__}: {exception}"
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def exception_error_print(label: str, exception: Exception) -> None:
|
|
66
|
+
"""Print an error message with exception details to the console.
|
|
67
|
+
|
|
68
|
+
:param label: Label for the error message.
|
|
69
|
+
:type label: str
|
|
70
|
+
:param exception: Exception to print.
|
|
71
|
+
:type exception: Exception
|
|
72
|
+
"""
|
|
73
|
+
Console.labeled_error_print(label, Console.pretty_exception(exception))
|
|
74
|
+
print_exc()
|
|
75
|
+
|
|
76
|
+
def debug_print(self, label: str, msg: str) -> None:
|
|
77
|
+
"""Print a debug message to the console.
|
|
78
|
+
|
|
79
|
+
:param label: Label for the debug message.
|
|
80
|
+
:type label: str
|
|
81
|
+
:param msg: Debug message to print.
|
|
82
|
+
:type msg: str
|
|
83
|
+
"""
|
|
84
|
+
if self._enable_debug:
|
|
85
|
+
self._repeat_print(f"{Back.BLUE}{Style.BRIGHT} DEBUG {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.BLUE}{msg}")
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def info_print(label: str, msg: str) -> None:
|
|
89
|
+
"""Print info to console.
|
|
90
|
+
|
|
91
|
+
:param label: Label for the message.
|
|
92
|
+
:type label: str
|
|
93
|
+
:param msg: Message to print.
|
|
94
|
+
:type msg: str
|
|
95
|
+
"""
|
|
96
|
+
print(f"\n{Back.GREEN}{Style.BRIGHT} {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.GREEN}{msg}")
|
|
97
|
+
|
|
98
|
+
# Helper methods.
|
|
99
|
+
def _repeat_print(self, msg: str) -> None:
|
|
100
|
+
"""Print a message to the console with repeat counter.
|
|
101
|
+
|
|
102
|
+
:param msg: Message to print.
|
|
103
|
+
:type msg: str
|
|
104
|
+
"""
|
|
105
|
+
if msg == self._last_message:
|
|
106
|
+
self._repeat_counter += 1
|
|
107
|
+
else:
|
|
108
|
+
self._repeat_counter = 1
|
|
109
|
+
self._last_message = msg
|
|
110
|
+
print()
|
|
111
|
+
|
|
112
|
+
print(f"\r{msg}{f" (x{self._repeat_counter})" if self._repeat_counter > 1 else ""}", end="")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ephys-link
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0b1
|
|
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
|
|
@@ -27,12 +27,14 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
27
27
|
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
28
28
|
Requires-Python: <3.13,>=3.10
|
|
29
29
|
Requires-Dist: aiohttp==3.9.5
|
|
30
|
+
Requires-Dist: colorama==0.4.6
|
|
30
31
|
Requires-Dist: platformdirs==4.2.2
|
|
31
32
|
Requires-Dist: pyserial==3.5
|
|
32
|
-
Requires-Dist: python-socketio[asyncio-client]==5.11.
|
|
33
|
+
Requires-Dist: python-socketio[asyncio-client]==5.11.3
|
|
33
34
|
Requires-Dist: pythonnet==3.0.3
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist:
|
|
35
|
+
Requires-Dist: requests==2.32.3
|
|
36
|
+
Requires-Dist: sensapex==1.400.1
|
|
37
|
+
Requires-Dist: vbl-aquarium==0.0.19
|
|
36
38
|
Description-Content-Type: text/markdown
|
|
37
39
|
|
|
38
40
|
# Electrophysiology Manipulator Link
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
ephys_link/__about__.py,sha256=QUUi7DnZ0lfA8ZZUdMrPNiqXewCSfYtIqTvB6q6NnGQ,25
|
|
2
|
+
ephys_link/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
ephys_link/__main__.py,sha256=pu7QLmS_30qWpgzeibMVD5FsVhICiK0wi7QkzX6F0qU,1373
|
|
4
|
+
ephys_link/back_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
ephys_link/back_end/platform_handler.py,sha256=5GfyLz8rX8VYypuT9JJokV12mnyUksriFOzRgp6H4W8,12939
|
|
6
|
+
ephys_link/back_end/server.py,sha256=WP5NLJnIKtkVImdRgtZKxWEghd17FjsmpuczYpoFs3Q,7965
|
|
7
|
+
ephys_link/bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
ephys_link/bindings/fake_bindings.py,sha256=_ZpXx4whztbO5jNGNqwoJFdqhIIbZ0VMx4mHkMge1r0,1726
|
|
9
|
+
ephys_link/bindings/ump_4_bindings.py,sha256=1V_bQzq7xVX1qGxbK11nxX7X3L3cfh9RTdhbVJwBKg8,4651
|
|
10
|
+
ephys_link/front_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
ephys_link/front_end/cli.py,sha256=KJBSWqdz4T5z0Zor1tJSHTJKZeMcHAJf5gXXu38wQPU,3105
|
|
12
|
+
ephys_link/front_end/gui.py,sha256=_gE6zFhFnzHPSyYd9MBvfK5xmDZHsUXcETDHzH66QzU,7518
|
|
13
|
+
ephys_link/resources/CP210xManufacturing.dll,sha256=aM9k_XABjkq0TOMiIw8HeteB40zqEkUDNO8wo91EdYI,810232
|
|
14
|
+
ephys_link/resources/NstMotorCtrl.dll,sha256=Xtpr3vBcxhcsOUGvgVEwYtGPvKEqDctIUGCK36GfU2Q,155136
|
|
15
|
+
ephys_link/resources/SiUSBXp.dll,sha256=187zlclZNNezCkU1o1CbICRAmKWJxbh8ahP6L6wo-_Y,469752
|
|
16
|
+
ephys_link/resources/libum.dll,sha256=YaD4dwiSNohx-XxHjx2eQWPOBEVvUIXARvx37e_yqNw,316316
|
|
17
|
+
ephys_link/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
ephys_link/util/base_bindings.py,sha256=FNqhB7kJf2n9g4wYHEBbQ2wEiZscR5sKCnIEZ6yujgE,4808
|
|
19
|
+
ephys_link/util/common.py,sha256=IgmTpXRU2z7jfYV2zB4RGgjV34IaYa2s3TYpzKZkpao,3519
|
|
20
|
+
ephys_link/util/console.py,sha256=kD4LLehdA1xLiGwdvjt5KxImDSyDkcoC2CQVOxTv8T4,3560
|
|
21
|
+
ephys_link-2.0.0b1.dist-info/METADATA,sha256=j_XqMK_IK955IOE0ikj_JhqschZGCOKpgMiWdGzTrQQ,7975
|
|
22
|
+
ephys_link-2.0.0b1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
23
|
+
ephys_link-2.0.0b1.dist-info/entry_points.txt,sha256=o8wV3AdnJ9o47vg9ymKxPNVq9pMdPq8UZHE_iyAJx-k,124
|
|
24
|
+
ephys_link-2.0.0b1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
25
|
+
ephys_link-2.0.0b1.dist-info/RECORD,,
|
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]
|
ephys_link/emergency_stop.py
DELETED
|
@@ -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()
|