29
29
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
30
# POSSIBILITY OF SUCH DAMAGE.
31
31
32
- # NOTE: This module depends on Daheng's proprietary 'gxipy' SDK.
33
- # To use this camera class, 'gxipy' must be installed manually.
34
- # See the ImportError message below for installation instructions.
32
+ # ################################################################################
33
+ # WARNING:
34
+ # This camera class has not been internally tested by our team.
35
+ # Users are advised to exercise caution when using it.
36
+ # NOTE:
37
+ # This module depends on Daheng's proprietary 'gxipy' SDK.
38
+ # To use this camera class, 'gxipy' must be installed manually.
39
+ # See the ImportError message below for installation instructions.
40
+ # ################################################################################
35
41
36
42
# Standard Library Imports
37
43
import logging
38
44
from typing import Union , Any , List
39
45
40
46
# Third Party Imports
41
47
try :
42
- from gxipy import DeviceManager , Device
48
+ import gxipy as gx
43
49
except ImportError :
44
50
raise ImportError (
45
51
"Missing required module 'gxipy'.\n "
56
62
# Local Imports
57
63
from navigate .model .utils .exceptions import UserVisibleException
58
64
from navigate .model .devices .camera .base import CameraBase
59
- from navigate .model .devices .device_types import SequenceDevice
60
65
from navigate .tools .decorators import log_initialization
61
66
62
67
63
- logger = logging .getLogger (__name__ )
68
+ # Logger Setup
69
+ p = __name__ .split ("." )[1 ]
70
+ logger = logging .getLogger (p )
64
71
65
72
66
73
@log_initialization
67
- class DahengCamera (SequenceDevice ):
74
+ class DahengCamera (CameraBase ):
68
75
"""
69
76
Daheng camera implementation for the MER2-1220-32U3C model.
70
77
@@ -86,6 +93,8 @@ def __init__(self, microscope_name, device_connection, configuration):
86
93
configuration : dict
87
94
Device configuration settings (e.g. resolution, exposure).
88
95
"""
96
+ super ().__init__ (microscope_name , device_connection , configuration )
97
+
89
98
self .microscope_name = microscope_name
90
99
self .device_connection = device_connection # Store raw connection for compatibility
91
100
self .configuration = configuration
@@ -122,6 +131,8 @@ def __init__(self, microscope_name, device_connection, configuration):
122
131
# Finish hardware setup (initialize feature_control etc.)
123
132
self .initialize_sdk_state ()
124
133
134
+ self .camera_parameters ["supported_readout_directions" ] = ["Top-to-Bottom" ]
135
+
125
136
def __str__ (self ) -> str :
126
137
"""
127
138
Return a human-readable string representation of the camera status.
@@ -157,10 +168,10 @@ def get_connect_params(cls) -> list:
157
168
list
158
169
An empty list since no parameters are required for Daheng connection.
159
170
"""
160
- return []
171
+ return ["serial_number" ]
161
172
162
173
@classmethod
163
- def connect (cls , serial_number : str = None ) -> Device :
174
+ def connect (cls , serial_number : str = None ) -> gx . Device :
164
175
"""
165
176
Connect to a Daheng camera using the gxipy SDK.
166
177
@@ -181,7 +192,7 @@ def connect(cls, serial_number: str = None) -> Device:
181
192
If no camera is found, or if the specified serial number does not match any camera.
182
193
"""
183
194
# Discover and list available devices using the Daheng SDK
184
- device_manager = DeviceManager ()
195
+ device_manager = gx . DeviceManager ()
185
196
device_manager .update_device_list ()
186
197
dev_info_list = device_manager .get_device_list ()
187
198
@@ -228,8 +239,14 @@ def initialize_sdk_state(self) -> None:
228
239
self .device_serial_number = self .feature_control .get_string_feature ("DeviceSerialNumber" ).get ()
229
240
self .payload_size = self .feature_control .get_int_feature ("PayloadSize" ).get ()
230
241
231
- # Set default acquisition mode
232
- self .feature_control .get_enum_feature ("AcquisitionMode" ).set ("Continuous" )
242
+ # Set trigger source (GPIO line 2) for external triggering
243
+ self .device .TriggerSource .set (gx .GxTriggerSourceEntry .LINE2 )
244
+ # Set trigger active
245
+ self .device .TriggerActivation .set (gx .GxTriggerActivationEntry .RISINGEDGE )
246
+ # Set trigger mode to on
247
+ self .device .TriggerMode .set (gx .GxSwitchEntry .ON )
248
+ # Set acquisition mode to single frame
249
+ self .device .AcquisitionMode .set (gx .GxAcquisitionModeEntry .SINGLEFRAME )
233
250
234
251
# Get current image dimensions from hardware
235
252
width = self .feature_control .get_int_feature ("Width" ).get ()
@@ -290,6 +307,7 @@ def report_settings(self) -> None:
290
307
291
308
try :
292
309
# Retrieve current settings from camera hardware
310
+ sensor_mode = self .device .SensorShutterMode .get ()
293
311
sensor_width = self .feature_control .get_int_feature ("Width" ).get ()
294
312
sensor_height = self .feature_control .get_int_feature ("Height" ).get ()
295
313
bin_x = self .feature_control .get_int_feature ("BinningHorizontal" ).get ()
@@ -300,7 +318,7 @@ def report_settings(self) -> None:
300
318
301
319
# Log all settings
302
320
logger .info ("Camera Settings:" )
303
- logger .info (" sensor_mode: N/A (fixed to Continuous )" )
321
+ logger .info (f " sensor_mode: { sensor_mode } (0: Normal, 1: Light-Sheet )" )
304
322
logger .info (f" binning: { bin_x } x{ bin_y } " )
305
323
logger .info (" readout_speed: N/A" )
306
324
logger .info (" trigger_active: N/A" )
@@ -322,6 +340,13 @@ def disconnect(self) -> None:
322
340
This method safely closes the device connection and clears
323
341
all associated resources, even if errors occur during shutdown.
324
342
"""
343
+ # Reset associated handles and status flags
344
+ self .feature_control = None # release device handler
345
+ self .data_stream = None
346
+ self .device_serial_number = None
347
+ self .payload_size = None
348
+ self .is_connected = False
349
+
325
350
if self .device is not None :
326
351
try :
327
352
# Attempt to close the hardware connection
@@ -331,13 +356,6 @@ def disconnect(self) -> None:
331
356
finally :
332
357
self .device = None
333
358
334
- # Reset associated handles and status flags
335
- self .feature_control = None
336
- self .data_stream = None
337
- self .device_serial_number = None
338
- self .payload_size = None
339
- self .is_connected = False
340
-
341
359
logger .info ("Daheng camera disconnected and internal state cleared." )
342
360
343
361
def set_sensor_mode (self , mode : str ) -> None :
@@ -350,8 +368,9 @@ def set_sensor_mode(self, mode: str) -> None:
350
368
Requested sensor mode (e.g., 'Normal', 'Light-Sheet').
351
369
This value is ignored as Daheng does not support sensor mode switching.
352
370
"""
353
- logger .warning (f"Sensor mode '{ mode } ' is not supported on Daheng cameras." )
354
-
371
+ modes_dict = {"Normal" : 0 , "Light-Sheet" : 1 }
372
+ self .device .SensorShutterMode .set (modes_dict .get (mode , 0 ))
373
+
355
374
# Default to scan mode 0 for compatibility
356
375
self ._scan_mode = 0
357
376
0 commit comments