ephys-link 2.2.1__tar.gz → 2.3.3__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.
Files changed (43) hide show
  1. {ephys_link-2.2.1 → ephys_link-2.3.3}/PKG-INFO +2 -2
  2. {ephys_link-2.2.1 → ephys_link-2.3.3}/pyproject.toml +1 -1
  3. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/jackhammer.py +9 -3
  4. ephys_link-2.3.3/scripts/test_jackhammer.py +14 -0
  5. ephys_link-2.3.3/src/ephys_link/__about__.py +1 -0
  6. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/platform_handler.py +39 -1
  7. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/server.py +18 -0
  8. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/mpm_binding.py +2 -1
  9. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/ump_binding.py +23 -0
  10. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/base_binding.py +25 -0
  11. ephys_link-2.2.1/src/ephys_link/__about__.py +0 -1
  12. {ephys_link-2.2.1 → ephys_link-2.3.3}/.gitignore +0 -0
  13. {ephys_link-2.2.1 → ephys_link-2.3.3}/LICENSE +0 -0
  14. {ephys_link-2.2.1 → ephys_link-2.3.3}/README.md +0 -0
  15. {ephys_link-2.2.1 → ephys_link-2.3.3}/ephys_link.spec +0 -0
  16. {ephys_link-2.2.1 → ephys_link-2.3.3}/mkdocs.yml +0 -0
  17. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/__init__.py +0 -0
  18. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/gen_ref_pages.py +0 -0
  19. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/logger_test.py +0 -0
  20. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/move_tester.py +0 -0
  21. {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/server_tester.py +0 -0
  22. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/__init__.py +0 -0
  23. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/__main__.py +0 -0
  24. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/__init__.py +0 -0
  25. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/__init__.py +0 -0
  26. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/fake_binding.py +0 -0
  27. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/parallax_binding.py +0 -0
  28. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/__init__.py +0 -0
  29. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/cli.py +0 -0
  30. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/console.py +0 -0
  31. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/gui.py +0 -0
  32. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/__init__.py +0 -0
  33. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/constants.py +0 -0
  34. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/converters.py +0 -0
  35. {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/startup.py +0 -0
  36. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/__init__.py +0 -0
  37. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/__init__.py +0 -0
  38. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/test_platform_handler.py +0 -0
  39. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/test_server.py +0 -0
  40. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/conftest.py +0 -0
  41. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/__init__.py +0 -0
  42. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/test_converters.py +0 -0
  43. {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ephys-link
3
- Version: 2.2.1
3
+ Version: 2.3.3
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,7 +27,7 @@ Requires-Dist: keyboard==0.13.5
27
27
  Requires-Dist: packaging==25.0
28
28
  Requires-Dist: platformdirs==4.5.1
29
29
  Requires-Dist: pyserial==3.5
30
- Requires-Dist: python-socketio==5.15.1
30
+ Requires-Dist: python-socketio==5.16.0
31
31
  Requires-Dist: requests==2.32.5
32
32
  Requires-Dist: rich==14.2.0
33
33
  Requires-Dist: sensapex==1.504.1
@@ -31,7 +31,7 @@ dependencies = [
31
31
  "packaging==25.0",
32
32
  "platformdirs==4.5.1",
33
33
  "pyserial==3.5",
34
- "python-socketio==5.15.1",
34
+ "python-socketio==5.16.0",
35
35
  "requests==2.32.5",
36
36
  "sensapex==1.504.1",
37
37
  "rich==14.2.0",
@@ -3,19 +3,25 @@ from ctypes import c_char, c_int
3
3
  from sensapex import UMP
4
4
 
5
5
  # Edit these parameters:
6
- DEVICE_ID = 3 # Manipulator ID.
6
+ DEVICE_ID = 6 # Manipulator ID.
7
7
  AXIS = 3 # Axis (0=X, 1=Y, 2=Z, 3=D).
8
8
 
9
- NUMBER_OF_CYCLES = 20 # Number of time the first and second stage are repeated.
9
+ NUMBER_OF_CYCLES = 120 # Number of time the first and second stage are repeated.
10
10
 
11
11
  NUMBER_OF_STEP_IN_FIRST_STAGE = 10
12
12
  FIRST_STAGE_THRUST_LENGTH = 15 # +/- 0 - 100
13
13
 
14
- NUMBER_OF_STEP_IN_SECOND_STAGE = 5
14
+ NUMBER_OF_STEP_IN_SECOND_STAGE = 10
15
15
  SECOND_STAGE_THRUST_LENGTH = -15 # +/- 0 - 100
16
16
 
17
17
  # Do not edit below this line.
18
18
  um = UMP.get_ump()
19
+ # test how much advancement is made after each iteration
20
+ # test if looping thru each iteration is much slower than 20 in one call
21
+ # Add delta variable and compare the advancement after each call until the manipulator either goes back or reaches the desired delta
22
+ # Add get_position calls to monitor the position in the um.call
23
+ # have a for loop or hard code number of iterations to compare the advancement after each call
24
+
19
25
 
20
26
  um.call(
21
27
  "um_take_jackhammer_step",
@@ -0,0 +1,14 @@
1
+ from socketio import SimpleClient
2
+
3
+ sio = SimpleClient()
4
+ sio.connect("http://localhost:3000")
5
+ result = sio.call("jackhammer", '''{
6
+ "manipulator_id": "6",
7
+ "iterations": 3,
8
+ "phase1_steps": 1,
9
+ "phase1_pulses": 80,
10
+ "phase2_steps": 1,
11
+ "phase2_pulses": -80
12
+ }''')
13
+ print(result)
14
+ sio.disconnect()
@@ -0,0 +1 @@
1
+ __version__ = "2.3.3"
@@ -6,7 +6,7 @@ Instantiates the appropriate bindings based on the platform type and uses them t
6
6
  Usage:
7
7
  Instantiate PlatformHandler with the platform type and call the desired command.
8
8
  """
9
-
9
+ import asyncio
10
10
  from typing import final
11
11
 
12
12
  from vbl_aquarium.models.ephys_link import (
@@ -229,6 +229,44 @@ class PlatformHandler:
229
229
  else:
230
230
  self._inside_brain.discard(request.manipulator_id)
231
231
  return BooleanStateResponse(state=request.inside)
232
+
233
+ async def jackhammer(
234
+ self,
235
+ manipulator_id: str,
236
+ axis: int,
237
+ iterations: int,
238
+ phase1_steps: int,
239
+ phase1_pulses: int,
240
+ phase2_steps: int,
241
+ phase2_pulses: int,
242
+ ) -> PositionalResponse:
243
+ """Perform jackhammer motion to break through dura.
244
+
245
+ Args:
246
+ manipulator_id: Manipulator ID.
247
+ axis: Axis to move (0=X, 1=Y, 2=Z, 3=W/Depth).
248
+ iterations: Number of jackhammer cycles.
249
+ phase1_steps: Number of steps in phase 1.
250
+ phase1_pulses: Pulse count for phase 1.
251
+ phase2_steps: Number of steps in phase 2.
252
+ phase2_pulses: Pulse count for phase 2.
253
+
254
+ Returns:
255
+ Final position of the manipulator after jackhammer and an error message if any.
256
+ """
257
+ try:
258
+ await self._bindings.jackhammer(
259
+ manipulator_id, axis, iterations, phase1_steps, phase1_pulses, phase2_steps, phase2_pulses
260
+ )
261
+ await asyncio.sleep(2) # wait for movement to settle
262
+ final_position = self._bindings.platform_space_to_unified_space(
263
+ await self._bindings.get_position(manipulator_id)
264
+ )
265
+ except Exception as e: # noqa: BLE001
266
+ self._console.exception_error_print("Jackhammer", e)
267
+ return PositionalResponse(error=self._console.pretty_exception(e))
268
+ else:
269
+ return PositionalResponse(position=final_position)
232
270
 
233
271
  async def stop(self, manipulator_id: str) -> str:
234
272
  """Stop a manipulator.
@@ -242,6 +242,24 @@ class Server:
242
242
  return await self._run_if_data_parses(
243
243
  self._platform_handler.set_inside_brain, SetInsideBrainRequest, event, data
244
244
  )
245
+ case "jackhammer":
246
+ if data:
247
+ try:
248
+ parsed = loads(str(data))
249
+ return (
250
+ await self._platform_handler.jackhammer(
251
+ manipulator_id=parsed.get("manipulator_id", parsed.get("ManipulatorId", "")),
252
+ axis=parsed.get("axis", parsed.get("Axis", 3)),
253
+ iterations=parsed.get("iterations", parsed.get("Iterations", 10)),
254
+ phase1_steps=parsed.get("phase1_steps", parsed.get("Phase1Steps", 10)),
255
+ phase1_pulses=parsed.get("phase1_pulses", parsed.get("Phase1Pulses", 15)),
256
+ phase2_steps=parsed.get("phase2_steps", parsed.get("Phase2Steps", 5)),
257
+ phase2_pulses=parsed.get("phase2_pulses", parsed.get("Phase2Pulses", -15)),
258
+ )
259
+ ).to_json_string()
260
+ except JSONDecodeError:
261
+ return self._malformed_request_response(event, data)
262
+ return self._malformed_request_response(event, data)
245
263
  case "stop":
246
264
  if data:
247
265
  return await self._platform_handler.stop(str(data)) # pyright: ignore[reportAny]
@@ -206,6 +206,7 @@ class MPMBinding(BaseBinding):
206
206
  # Keep track of the previous depth to check if the manipulator stopped advancing unexpectedly.
207
207
  current_depth = (await self.get_position(manipulator_id)).w
208
208
  previous_depth = current_depth
209
+ depth = self.get_dimensions().w - depth
209
210
  unchanged_counter = 0
210
211
 
211
212
  # Send move request.
@@ -244,7 +245,7 @@ class MPMBinding(BaseBinding):
244
245
  self._movement_stopped = False
245
246
 
246
247
  # Return the final depth.
247
- return float((await self.get_position(manipulator_id)).w)
248
+ return float(self.get_dimensions().w - (await self.get_position(manipulator_id)).w)
248
249
 
249
250
  @override
250
251
  async def stop(self, manipulator_id: str) -> None:
@@ -10,6 +10,7 @@ from sensapex import UMP, SensapexDevice # pyright: ignore [reportMissingTypeSt
10
10
  from vbl_aquarium.models.unity import Vector4
11
11
 
12
12
  from ephys_link.utils.base_binding import BaseBinding
13
+ from ctypes import c_char, c_int
13
14
  from ephys_link.utils.converters import (
14
15
  list_to_vector4,
15
16
  scalar_mm_to_um,
@@ -144,6 +145,28 @@ class UmpBinding(BaseBinding):
144
145
  async def stop(self, manipulator_id: str) -> None:
145
146
  self._get_device(manipulator_id).stop() # pyright: ignore [reportUnknownMemberType]
146
147
 
148
+ @override
149
+ async def jackhammer(
150
+ self,
151
+ manipulator_id: str,
152
+ axis: int,
153
+ iterations: int,
154
+ phase1_steps: int,
155
+ phase1_pulses: int,
156
+ phase2_steps: int,
157
+ phase2_pulses: int,
158
+ ) -> None:
159
+ self._ump.call(
160
+ "um_take_jackhammer_step",
161
+ c_int(int(manipulator_id)),
162
+ c_char(axis),
163
+ c_int(iterations),
164
+ c_int(phase1_steps),
165
+ c_int(phase1_pulses),
166
+ c_int(phase2_steps),
167
+ c_int(phase2_pulses),
168
+ )
169
+
147
170
  @override
148
171
  def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
149
172
  """
@@ -147,6 +147,31 @@ class BaseBinding(ABC):
147
147
  manipulator_id: Manipulator ID.
148
148
  """
149
149
 
150
+
151
+ async def jackhammer(
152
+ self,
153
+ manipulator_id: str,
154
+ axis: int,
155
+ iterations: int,
156
+ phase1_steps: int,
157
+ phase1_pulses: int,
158
+ phase2_steps: int,
159
+ phase2_pulses: int,
160
+ ) -> None:
161
+ """Perform jackhammer motion to break through dura.
162
+
163
+ Args:
164
+ manipulator_id: Manipulator ID.
165
+ axis: Axis to move (0=X, 1=Y, 2=Z, 3=W/Depth).
166
+ iterations: Number of jackhammer cycles.
167
+ phase1_steps: Number of steps in phase 1.
168
+ phase1_pulses: Pulse count for phase 1 (positive=forward).
169
+ phase2_steps: Number of steps in phase 2.
170
+ phase2_pulses: Pulse count for phase 2 (negative=backward).
171
+ """
172
+ error_message = f"{self.get_display_name()} does not support jackhammer mode"
173
+ raise NotImplementedError(error_message)
174
+
150
175
  @abstractmethod
151
176
  def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
152
177
  """Convert platform space coordinates to unified space coordinates.
@@ -1 +0,0 @@
1
- __version__ = "2.2.1"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes