genicam / harvesters

Image Acquisition Library for GenICam-based Machine Vision System
Apache License 2.0
500 stars 86 forks source link

Callback Event on Camera Disconnection #431

Open simondegheselle opened 9 months ago

simondegheselle commented 9 months ago

I am using Harvester to interface with a GiGE camera and would like a callback feature that triggers when the camera gets disconnected due to a networking issue.

Currently, Harvester provides callback events, such as NEW_BUFFER_AVAILABLE, but there seems to be no event indicating when the connection to the camera is lost due to network outages. TURNED_OBSOLUTE does not seem to be fired when a disconnect happens

Here's a snippet of how I use the Harvester:

import harvesters.core as harvcore
from pathlib import Path
from threading import Event, Thread
from loguru import logger
import time

harvester = harvcore.Harvester()

file_path = "./Galaxy_Linux_Python_2.0.2106.9041/api/Galaxy_Linux-armhf_Gige-U3_32bits-64bits_1.3.2107.9261/Galaxy_camera/lib/armv8/GxGVTL.cti"
if not Path(file_path).exists():
    raise ValueError(f"{file_path} is not found")
harvester.add_file(file_path)
harvester.update()

camera = harvester.create()

class CallbackOnNewBuffer(harvcore.Callback):
    def __init__(self, ia: harvcore.ImageAcquirer):
        super().__init__()
        self._ia = ia

    def emit(self, context=None):
        with self._ia.fetch() as buffer:
            image_data = buffer.payload.components[0]
            img = image_data.data.reshape(image_data.height, image_data.width)
            # logger.info(f"Received data with shape {img.shape}")

camera.add_callback(
    harvcore.ImageAcquirer.Events.NEW_BUFFER_AVAILABLE,
    CallbackOnNewBuffer(ia=camera)
)

# I would like to add a callback when the camera is disconnected due to network outage
# No events seem to indicate when connection is lost to the harvester remote device
camera.start(run_as_thread=True)

# *** _gentl.TimeoutException: GenTL exception: Operation timed out before completion. (Message from the source: {-1011}{ReadRegList:line[223]}{TLError: Timeout !}) (ID: -1011)
# camera.remote_device.node_map.ExposureTime.value = 20000

# Event().wait()

def _check_health_monitor():
    try: 
        camera.remote_device.node_map.ExposureTime.value = 2000
        return True
    except:
        return False # not connected, got a Timeout

while True:
    time.sleep(1)
    logger.info(f"Access status {camera.remote_device.module._get_access_status()}") # always prints 3
    logger.info(f"Is open {camera.remote_device.module.is_open()}") # always True      
    logger.info(f"Is open healthCheck {_check_health_monitor()}") # return correct result  

# Sample output when unplugging
# 2023-09-29 15:57:30.880 | INFO     | __main__:<module>:53 - Access status 3
# 2023-09-29 15:57:30.887 | INFO     | __main__:<module>:54 - Is open True
# 2023-09-29 15:57:30.892 | INFO     | __main__:<module>:55 - Is open healthCheck True
# 2023-09-29 15:57:31.902 | INFO     | __main__:<module>:53 - Access status 3
# 2023-09-29 15:57:31.909 | INFO     | __main__:<module>:54 - Is open True
# 2023-09-29 15:57:31.913 | INFO     | __main__:<module>:55 - Is open healthCheck True
## UNPLUGGED THE GiGE Camera
# 2023-09-29 15:57:32.921 | INFO     | __main__:<module>:53 - Access status 3
# 2023-09-29 15:57:32.928 | INFO     | __main__:<module>:54 - Is open True
# 2023-09-29 15:57:32.933 | INFO     | __main__:<module>:55 - Is open healthCheck False
# 2023-09-29 15:57:33.942 | INFO     | __main__:<module>:53 - Access status 3
# 2023-09-29 15:57:33.949 | INFO     | __main__:<module>:54 - Is open True
# 2023-09-29 15:57:33.954 | INFO     | __main__:<module>:55 - Is open healthCheck False

camera.stop()
camera.destroy()

logger.info("Destroyed camera")

Additionally, I have tried using the is_open method and the access_status property of the remote_device, but they don't seem to detect or reflect the actual loss of the camera due to a network disconnection. Even when the camera is unplugged, is_open returns True and access_status returns 3.

logger.info(f"Access status {camera.remote_device.module._get_access_status()}") # always prints 3
logger.info(f"Is open {camera.remote_device.module.is_open()}") # always True

To work around this, I have attempted to monitor the connection health by checking the camera.remote_device.node_map..value, but this approach feels more like a workaround than a direct event-based solution:

def _check_health_monitor():
    try: 
        camera.remote_device.node_map.ExposureTime.value = 2000
        return True
    except:
        return False # not connected, got a Timeout

Is there a callback event or a more accurate method to determine the loss of the camera due to network issues. I want to find a solution that can handle such disconnections gracefully.

eli-osherovich commented 3 weeks ago

Also was looking for a solution… My approach was based on the fetch timeout. To the best of my understanding UDP cannot detect disconnects