Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Naive GigE implementation #198

Draft
wants to merge 69 commits into
base: main
Choose a base branch
from

Conversation

WhiteBlackGoose
Copy link

@WhiteBlackGoose WhiteBlackGoose commented Nov 20, 2024

Notes

  • It is only a partial implementation of GigE. Actually, a tiny bit of it, because only the following features are supported:
    • Single link mode
    • Single interface mode
    • One streaming channel
    • Image as payload
    • No H264 or multi-zone support
    • No request of the lost packets

It is however enough for the camera I need, and maybe I'll extend it if I get another camera which needs something beyond that.

  • The purpose of this PR is to share my work, in case someone's use case is exactly the same as mine (simple GigE cameras)

  • This PR is based on Y-Nak's work (and in fact, by far most of the work belongs to this person, I just finished the streaming part for my use case)

  • I didn't name my commits properly because if I'm actually to finish this PR so we could merge it, I'd imagine I'd need to squash and rewrite them many times because I expect quite a fair bit of feedback/change requests from the maintainer

  • GigE Example App

  • Check test_all.sh is passed. Answer: It doesn't, but it's not my fault

  • Add fix #{ISSUE_NUMBER} if the corresponding issue exists.

  • Fill out ## Changelog section. If the change is for only internal use, please write None to the section.

Changelog

  • gige::enumerate_cameras requires an IP address of the host to listen to cameras from
  • Very naive GigE implemented

@romainreignier
Copy link

Hi @WhiteBlackGoose
Thanks for this work. I have tested your sample app on an Imperx C4110C GigE camera and it works!

@romainreignier
Copy link

romainreignier commented Jan 24, 2025

Hi @WhiteBlackGoose
I have tested a simple application where I do Software Triggers in a loop and retrieve the image, based on the stream.rs example of this repo:

use std::{net::Ipv4Addr, str::FromStr};

fn main() {
    let local_ip_addr = Ipv4Addr::from_str("192.168.12.1").unwrap();
    let mut cameras = cameleon::gige::enumerate_cameras(local_ip_addr).unwrap();
    if cameras.is_empty() {
        println!("no camera found!");
        return;
    }
    println!("Found {} cameras", cameras.len());

    let mut camera = cameras.pop().unwrap();
    camera.open().unwrap();
    camera.load_context().unwrap();
    {
        let mut ctxt = camera.params_ctxt().unwrap();
        ctxt.node("PixelFormat")
            .unwrap()
            .as_enumeration(&ctxt)
            .unwrap()
            .set_entry_by_symbolic(&mut ctxt, "BayerRG8")
            .unwrap();
        ctxt.node("TriggerActivation")
            .unwrap()
            .as_enumeration(&ctxt)
            .unwrap()
            .set_entry_by_symbolic(&mut ctxt, "RisingEdge")
            .unwrap();
        ctxt.node("TriggerSource")
            .unwrap()
            .as_enumeration(&ctxt)
            .unwrap()
            .set_entry_by_symbolic(&mut ctxt, "Software")
            .unwrap();
        ctxt.node("TriggerMode")
            .unwrap()
            .as_enumeration(&ctxt)
            .unwrap()
            .set_entry_by_symbolic(&mut ctxt, "On")
            .unwrap();
    }
    let payload_rx = camera.start_streaming(3).unwrap();

    std::thread::sleep(std::time::Duration::from_millis(500));
    for i in 0..10 {
        {
            println!("TriggerSoftware {}", i + 1);
            let mut ctxt = camera.params_ctxt().unwrap();
            ctxt.node("TriggerSoftware")
                .unwrap()
                .as_command(&ctxt)
                .unwrap()
                .execute(&mut ctxt)
                .unwrap();
        }
        let payload = match payload_rx.recv_blocking() {
            Ok(payload) => payload,
            Err(e) => {
                println!("payload receive error: {e}");
                continue;
            }
        };
        println!(
            "payload received! block_id: {:?}, timestamp: {:?}",
            payload.id(),
            payload.timestamp()
        );
        if let Some(image_info) = payload.image_info() {
            println!("{:?}\n", image_info);
        }

        payload_rx.send_back(payload);

        std::thread::sleep(std::time::Duration::from_millis(500));
    }

    println!("Capture Loop Finished");
    camera.close().unwrap();
    println!("End of main");
}

But I have 2 issues:

  1. The main never exits. The code is stuck in camera.close().
  2. Most of the time, the code stay blocked on the payload_rx.recv_blocking() line on a given iteration, not always the same, between 1 and 10.

Edit: I have tried the stream.rs example (by replacing the enumerate_cameras) and the 2 issues are gone. But I see that the block_id often ends with the value 11 instead of 10 because one of the block is missing.
Example with missing block 2:

payload received! block_id: 1, timestamp: 25.131709855s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 3, timestamp: 25.152710121s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 4, timestamp: 25.163210255s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 5, timestamp: 25.173710389s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 6, timestamp: 25.184210521s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 7, timestamp: 25.194710655s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 8, timestamp: 25.205210789s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 9, timestamp: 25.215710921s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 10, timestamp: 25.226211055s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

payload received! block_id: 11, timestamp: 25.236711189s
ImageInfo { width: 4112, height: 3008, x_offset: 0, y_offset: 0, pixel_format: BayerRG8, image_size: 12368896 }

@WhiteBlackGoose
Copy link
Author

Hey @romainreignier

Edit: I have tried the stream.rs example (by replacing the enumerate_cameras) and the 2 issues are gone

What did you replace it with? I'm not sure I understand.

But I see that the block_id often ends with the value 11 instead of 10 because one of the block is missing.

Turn on warning level in your logger and see if you're getting lost packet warnings (packets are build here. As per GigE, one could implement retrieving lost packets (of course, the camera should support it) or interpolate the missing information, but I haven't done any of it.

I don't have another camera right now that I can test with, but soon I'll get my hands on more GigE cameras and will be able to fix some issues as they arise. Can't guarantee yours will be fixed sadly. GigE is a huge protocol.

@romainreignier
Copy link

Thanks for your reply.

What did you replace it with? I'm not sure I understand.

I have replaced the u3v enumerate with:

let local_ip_addr = Ipv4Addr::from_str("192.168.12.1").unwrap();
    let mut cameras = cameleon::gige::enumerate_cameras(local_ip_addr).unwrap();

As per GigE, one could implement retrieving lost packets.

That might help, indeed. I have tried the same Genicam commands with aravis and I had all the frames. I might compare the two wireshark captures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants