This commit is contained in:
edo-neo 2025-08-21 14:11:45 +02:00
parent 5e9e9e1664
commit 1ee186eb34
2 changed files with 153 additions and 3 deletions

View File

@ -238,6 +238,101 @@ class HikrobotSmartCamera(Component):
except Exception as e:
self.log.error(f"Error getting debug camera state: {e}")
def is_camera_busy(self, handle=None):
"""
Check if the camera is currently busy.
This method checks the camera's device status and acquisition status to determine
if it's currently busy with operations that would prevent scheme switching.
Args:
handle: Camera handle. If None, uses the first camera handle.
Returns:
bool: True if the camera is busy, False otherwise
"""
# Check if camera is connected
if not self.connected:
self.log.warning("Cannot check if camera is busy: Camera not connected")
return True # Assume busy if not connected
# Get camera handle if not provided
if handle is None:
if len(self.cam_list) == 0:
self.log.warning("Cannot check if camera is busy: No camera handles available")
return True # Assume busy if no handles
handle = self.cam_list[0]["handle"]
# Check if an operation is already in progress
if self.current_operation is not None:
self.log.info(f"Camera is busy with operation: {self.current_operation}")
return True
try:
self.log.info("Checking if camera is busy before scheme switching...")
# Try to get the device status
device_status = c_uint()
nRet = mv_lib.MV_VS_GetEnumValue(handle, b"DeviceStatus", byref(device_status))
# If we get the 0x80030100 error, the camera is busy
if nRet != MV_VS_OK:
error_code = nRet & 0xFFFFFFFF
if error_code == 0x80030100: # MV_VS_E_GC_GENERIC
self.log.warning("Camera is busy: Detected MV_VS_E_GC_GENERIC error (0x80030100) when checking device status")
self.log.info("This error indicates the camera is currently busy with another operation")
return True
else:
self.log.warning(f"Error checking device status, error code: 0x{error_code:x}")
else:
# Log device status value
self.log.info(f"Device status: {device_status.value}")
# Device status values (based on documentation and testing):
# 0: Device is idle
# 1: Device is busy with acquisition
# 2: Device is busy with processing
# 3: Device is busy with transfer
if device_status.value > 0:
self.log.warning(f"Camera appears busy: Device status is {device_status.value}")
return True
# Try to get the acquisition status
acquisition_status = c_uint()
nRet = mv_lib.MV_VS_GetEnumValue(handle, b"AcquisitionStatus", byref(acquisition_status))
# If we get the 0x80030100 error, the camera is busy
if nRet != MV_VS_OK:
error_code = nRet & 0xFFFFFFFF
if error_code == 0x80030100: # MV_VS_E_GC_GENERIC
self.log.warning("Camera is busy: Detected MV_VS_E_GC_GENERIC error (0x80030100) when checking acquisition status")
self.log.info("This error indicates the camera is currently busy with acquisition")
return True
else:
self.log.warning(f"Error checking acquisition status, error code: 0x{error_code:x}")
else:
# Log acquisition status value
self.log.info(f"Acquisition status: {acquisition_status.value}")
# Acquisition status values (based on documentation and testing):
# 0: Acquisition is idle
# 1: Acquisition is active
if acquisition_status.value > 0:
self.log.warning(f"Camera appears busy: Acquisition status is {acquisition_status.value}")
return True
# If we've reached this point, the camera is not busy
self.log.info("Camera is not busy, safe to proceed with scheme switching")
return False
except Exception as e:
self.log.error(f"Error checking if camera is busy: {e}")
# Log the full exception traceback for debugging
import traceback
self.log.error(f"Exception traceback: {traceback.format_exc()}")
return True # Assume busy if there's an error
def refresh_module_list(self):
"""
@ -282,7 +377,7 @@ class HikrobotSmartCamera(Component):
self.log.error(f"Exception traceback: {traceback.format_exc()}")
return False
def switch_scheme(self, solution_name, retry_count=0, max_retries=2):
def switch_scheme(self, solution_name, retry_count=0, max_retries=2, force=False):
"""
Switch to a different scheme/solution using the API as described in the documentation.
@ -290,6 +385,7 @@ class HikrobotSmartCamera(Component):
solution_name: The name of the solution to switch to
retry_count: Current retry attempt (used internally for recursion)
max_retries: Maximum number of retry attempts for error recovery
force: If True, attempt to switch scheme even if camera appears busy
Returns:
bool: True if the scheme switching process was successfully initiated, False otherwise
@ -314,6 +410,20 @@ class HikrobotSmartCamera(Component):
handle = self.cam_list[0]["handle"]
# Check if camera is busy before proceeding
if not force and self.is_camera_busy(handle):
self.log.warning(f"Cannot switch scheme to {solution_name}: Camera is busy")
self.log.info("Use force=True to override this check if necessary")
# If we're already retrying, wait and try again
if retry_count < max_retries:
wait_time = 3 # Wait longer when camera is busy
self.log.info(f"Waiting {wait_time} seconds before retry {retry_count+1}/{max_retries}")
time.sleep(wait_time)
return self.switch_scheme(solution_name, retry_count + 1, max_retries, force)
return False
# Get current camera state for debugging
self.log.info("Getting camera state before scheme switch:")
self._debug_camera_state(handle)

View File

@ -4,7 +4,7 @@ import time
from PyQt5.QtCore import pyqtSignal, QTimer
from PyQt5.QtGui import QColor, QImage, QPalette, QPixmap
from PyQt5.QtWidgets import QHeaderView, QProgressBar, QTableWidgetItem, QDialog, QVBoxLayout, QLabel
from PyQt5.QtWidgets import QHeaderView, QProgressBar, QTableWidgetItem, QDialog, QVBoxLayout, QLabel, QApplication
from src.lib.helpers.blocking_dialog import BlockingDialog
from src.ui.helpers import calc_foreground_color
@ -171,7 +171,47 @@ class Test_Vision(Test_Test):
# If a scheme switch is not already in progress, start one
if self.components[cam_type].current_operation != "switch_scheme":
self.log.info(f"Initiating scheme switch to: {target_scheme}")
self.components[cam_type].switch_scheme(target_scheme)
# Check if camera is busy before attempting to switch scheme
if self.components[cam_type].is_camera_busy():
self.log.warning(f"Camera is busy. Waiting for it to become available before switching to scheme: {target_scheme}")
# Update the progress dialog to show waiting status
progress_dialog.status_label.setText("Status: Waiting for camera to become available...")
progress_dialog.debug_label.setText("Debug info: Camera is busy with another operation")
# Try up to 3 times with increasing delays
max_busy_retries = 3
for retry in range(max_busy_retries):
# Process events to keep UI responsive
QApplication.processEvents()
# Wait with increasing delay
wait_time = (retry + 1) * 2 # 2, 4, 6 seconds
self.log.info(f"Waiting {wait_time} seconds before retry {retry+1}/{max_busy_retries}")
# Update progress dialog
progress_dialog.debug_label.setText(f"Debug info: Waiting {wait_time} seconds before retry {retry+1}/{max_busy_retries}")
# Wait
time.sleep(wait_time)
# Check again if camera is still busy
if not self.components[cam_type].is_camera_busy():
self.log.info("Camera is now available")
break
if retry == max_busy_retries - 1:
self.log.warning("Camera still busy after maximum retries, attempting to force scheme switch")
progress_dialog.debug_label.setText("Debug info: Forcing scheme switch after maximum retries")
# Attempt to switch scheme, with force=True on the last retry if still busy
force_switch = self.components[cam_type].is_camera_busy()
if force_switch:
self.log.warning("Forcing scheme switch even though camera appears busy")
self.components[cam_type].switch_scheme(target_scheme, force=True)
else:
self.components[cam_type].switch_scheme(target_scheme)
# Show the dialog and wait for it to complete
result = progress_dialog.exec_()