System designExplainer

How to migrate a legacy camera SDK to GenICam acquisition

Migrate a legacy IIDC/DCAM camera SDK to GenICam without a rewrite: the API differences, a 2-4 week port plan, bandwidth arithmetic and a parity checklist.

LumaSpec Vision12 min read Share on LinkedIn

On this page 10 sections
  1. 01What actually changes when you move from IIDC 1394 to GenICam?
  2. 02How different are the two APIs, line for line?
  3. 03How long should the port take, realistically?
  4. 04How do you structure the code so the port stays small?
  5. 05What breaks first: pixel formats, buffers and exposure units?
  6. 06Will the new interface carry your data rate?
  7. 07What do you verify one by one before cutover?
  8. 08When should you not port at all?
  9. 09Which replacement hardware fits a GenICam port?
  10. 10Questions

The SDK behind your IIDC 1394 cameras has finished development. No new camera models and no further fixes are coming, while the cameras sold for new builds speak GenICam over GigE Vision, USB3 Vision or CoaXPress. If you maintain an inspection station built on that old stack, the camera and the code that drives it change together — and the code change is smaller than it looks. The plan below treats the move as an API port, not a rewrite: where the two API models actually differ, a 2-4 week budget for a modest codebase, the bandwidth arithmetic that picks the replacement interface, and the six bench checks that separate a clean cutover from a slow failure in production.

What actually changes when you move from IIDC 1394 to GenICam?

Exactly one layer of your software changes: the camera-control API. A legacy IIDC/DCAM SDK writes to fixed register addresses baked into the library; a GenICam SDK reads an XML description from the camera itself and exposes every feature as a named node, identically across GigE Vision, USB3 Vision and CoaXPress.

Both standards solve the same problem — moving images and control between camera and PC. IIDC, the DCAM specification, did it over the IEEE 1394 bus. GigE Vision does the same job over Ethernet, which is why engineers read them as direct analogues. The real difference is where the feature list lives. In the legacy model the list was compiled into your SDK: every setter was a fixed register write, fixed when the library shipped.

A GenICam camera carries its own XML description file. The runtime parses that file into a node map, and your code reads and writes features by name — so a new camera's new features appear without waiting for a new SDK. GigE Vision cameras are required to implement GenICam, and USB3 Vision, CoaXPress and Camera Link cameras use the same layer over their own transports. The area scan cameras category spans all four interfaces, and the node map reads the same on each.

Development status matters too. The legacy SDK is complete and frozen; GenICam runtimes continue to pick up new sensor generations. A port buys a supported path, not just a working one.

How different are the two APIs, line for line?

The APIs differ completely in shape but touch only a narrow surface. A typical application makes 10 to 20 distinct camera calls — open, configure, start, grab, stop, close — so wrapping that surface is days of work, not weeks.

Task Legacy IIDC/DCAM SDK GenICam-based SDK
Find cameras Walk the 1394 bus, match camera GUID Transport discovery: subnet broadcast on GigE, device list on USB3
Set a feature One fixed setter per feature Set a named node; read Min, Max and Inc first
Pixel format DCAM format codes PixelFormat node, SFNC-style names
External trigger Register write to a trigger register TriggerMode and TriggerSource nodes
Store settings File or registry keyed by register address User set banks saved in the camera

Two gotchas dominate the first week. Discovery first: a GigE camera is enumerated only when it sits on the same subnet as the network card that asks, so a legacy habit of one flat network can leave cameras invisible while the link light shines green. Access state second: GenICam allows one writer at a time, and a vendor utility left open makes your application's node writes fail — check the access state before blaming your code (see GenICam node not writable: check camera access state).

Enumerations carry a third wrinkle: setting them by integer value works, but the numeric-to-symbolic mapping belongs to each camera, so read the symbolic entries before you set (see Set a GenICam enumeration by integer value: map numeric to symbolic).

How long should the port take, realistically?

Budget 2 to 4 weeks of one engineer for a modest port: a single camera type, one acquisition thread and up to about 15 distinct camera calls in the application. Each additional camera family adds roughly a week, because its pixel formats and trigger settings need their own parity checks.

  • Wrapper and discovery — 2-3 days. Define the seam from the next section and get frames flowing from one camera.
  • Buffers and pixel formats — 3-5 days. The hidden cost of most ports; the details are in the section below.
  • Parity checks — 3-4 days. Run all six bench checks from the cutover checklist below.
  • Integration and soak — the remainder. Run the ported application against the new camera for one full production shift before anyone cuts over.

A codebase far outside these assumptions — dozens of cameras per cell, custom drivers, multiple PCs — is a different project. Scope it against the same six checks before quoting dates to anyone.

How do you structure the code so the port stays small?

Write one thin wrapper class with about six virtual methods and port only that class to the new SDK. The GenICam-specific code stays under a few hundred lines, while acquisition policy, image processing and HMI above the wrapper compile unchanged.

Keep the six methods boring: open, close, configure, start, grab, stop.

// Illustrative seam - your names, not any SDK's
class CameraLink {
public:
    virtual bool Open(const std::string& serial) = 0;  // match by serial, never by index
    virtual bool Configure(double exposure_us) = 0;    // maps to the ExposureTime node
    virtual bool Start() = 0;
    virtual bool GetFrame(uint8_t* dst, size_t bytes, int timeout_ms) = 0;
    virtual bool Stop() = 0;
    virtual bool Close() = 0;
};

Prove each method with a read-back test, not by trusting a return code. For the exposure method: set 5,000 µs, read the ExposureTime node back, and fail the test when the read-back differs from 5,000 µs by more than the node's Inc step — query Inc, because steps of 1 µs and 10 µs are both common. A setter that returns true while the camera holds a different value is the classic first-week bug.

What breaks first: pixel formats, buffers and exposure units?

Three things break in the first week of every port: pixel-format enumerations, buffer ownership and exposure units. Mono8 pixels arrive in the same memory layout as before, but the format names now live in the camera's enumeration, buffers arrive without a copy, and exposure moves from an index to microseconds.

Grab one frame in each format your application uses and check the pixel-data object's format before processing starts, not after the first false defect (see Converted image object pixel format: verify before processing). Depth is the second trap: a 10-bit sensor still delivers 8-bit pixels unless you select a deeper pixel format, which is exactly why 10-bit cameras ship 8-bit images by default (see ADC bit depth vs pixel format: why 10-bit sensors ship 8-bit images).

Legacy SDKs copied frames into your buffer; GenICam runtimes hand you theirs. Wrap the delivery buffer in your image type instead of copying — the pattern is in Wrap an SDK frame buffer in an OpenCV cv::Mat without copying — and respect its lifetime: the memory belongs to the SDK until the buffer is requeued.

A DCAM shutter call often took an index into the camera's timing table; the ExposureTime node takes microseconds and publishes Min, Max and Inc. Query all three and clamp, instead of assuming the legacy range still applies. The discovery pattern is in Discover the camera exposure feature before acquisition; a worked Python version is in Setting camera exposure time through a GenICam API in Python.

Will the new interface carry your data rate?

Compute it before ordering hardware: width × height × bytes per pixel × frame rate, against the link's sustained rate. One GigE link sustains about 110 MB/s with jumbo frames, an IEEE 1394a S400 bus about 40 MB/s, a 1394b S800 bus about 80 MB/s.

frame size (MB) = width × height × bytes per pixel / 1,000,000 max fps = sustained link rate (MB/s) / frame size (MB)

The sustained numbers assume an obvious setup: jumbo frames enabled end to end for the GigE figure, and bus arbitration for the 1394 figures. With default 1,500-byte packets the GigE rate lands well below 110 MB/s, so raise packet size first when a link measures short.

Worked example — a 1600 × 1200 Mono8 stream at 50 fps:

  • Frame size: 1600 × 1200 × 1 B = 1,920,000 B ≈ 1.92 MB
  • Demand: 1.92 MB × 50 fps = 96 MB/s
  • S400 capacity: 40 MB/s ÷ 1.92 MB ≈ 20.8 fps → fails
  • S800 capacity: 80 ÷ 1.92 ≈ 41.7 fps → fails
  • One GigE link: 110 ÷ 1.92 ≈ 57.3 fps → fits, with 110 − 96 = 14 MB/s (13%) headroom

A station that saturates an S800 bus at 50 fps therefore migrates to a single GigE link with room to spare. Past about 110 MB/s the decision flips: a 5 MP sensor at 2448 × 2048 Mono8 is 5.01 MB per frame, so 30 fps needs 150 MB/s — more than GigE carries. Step up to USB 3 (about 400 MB/s sustained, so 400 ÷ 5.01 ≈ 79.8 fps capability) or 10GigE, and treat that interface change as its own low-risk project (see Machine vision camera interface migration: plan a low-risk change).

What do you verify one by one before cutover?

Verify six behaviors on the bench, in this order, and sign off each before the cutover date: discovery, pixel format, frame rate, exposure, trigger and settings persistence. Each check takes under an hour. Skipping one is how a port that looked finished fails three weeks into production.

  1. Discovery. Enumerate on the bench PC, filter by serial number, and confirm the count matches the cameras connected. A camera missing from the list is a subnet problem, not a code problem.
  2. Pixel format. Grab 100 frames in each format the application uses; every frame's byte count must equal width × height × bytes per pixel, with the dropped-frame counter at zero.
  3. Frame rate. Acquire 1,000 frames using the camera's hardware timestamps; the measured rate must sit within a few percent of the configured value and the drop counter must stay at zero.
  4. Exposure. Sweep the ExposureTime node from Min to Max in Inc steps, read back at both ends, and confirm the strobe timing still matches the exposure window.
  5. Trigger. Fire 100 hardware trigger pulses and measure trigger-to-exposure latency plus the minimum rearm interval your line rate needs. If acquisition stops after one frame, the acquisition mode is the cause (see Hardware trigger stops after one frame: check acquisition mode); for the timing budget across the whole loop, see Image based control latency: budget the full feedback loop.
  6. Persistence. Write your settings, power-cycle the camera, read them back, then store the set in a user set bank so nothing depends on the PC's own files.

When should you not port at all?

Do not port when the station retires within a year, when the application is under about 500 lines — the wrapper alone runs a few hundred lines, so a small program is faster to rewrite — or when the legacy PC still runs the line and only future stations will use GenICam.

In the last case, run both worlds in parallel. Leave the IEEE 1394 card and the legacy SDK on the existing PC until that station retires, and build every new station on the GenICam stack from day one. The wrapper pattern is what lets a mixed fleet migrate later on your schedule; with no second station coming, the wrapper is pure cost.

Past 400 MB/s of sustained demand the interface, not the SDK, decides the design. Go straight to 10GigE or CoaXPress hardware on the new stack rather than porting onto GigE and re-porting a year later.

Which replacement hardware fits a GenICam port?

Match three things to the migration: interface against your bandwidth figure, mount against your existing lens, and PC ports against camera count. C-mount runs across the current lines, so a good legacy lens usually survives the camera change. At the 2.5 MP class, a like-for-like swap looks like this:

Area scan camerasHikrobot MV-CU020-90GC 2.5 MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
$309.00View partBuild a system with it

The MV-CU020-90GC is a 2.5 MP color camera with a 1/1.7" global-shutter sensor, C-mount and GigE — the same mount and interface class as the legacy station it replaces.

Where the application wants more pixels and the frame rate is modest, a 6 MP mono option on a 1/1.8" sensor with C-mount and GigE keeps the same interface class:

Area scan camerasHikrobot MV-CT0MG0060/R/NN/NN 6 MP Area Scan Camera, 3rd Gen., GigE, Mono, BASEMV-CT0MG0060/R/NN/NN
Sensor format
1/1.8"
Lens mount
C-mount
Interface
GigE
Resolution
6-10 MP
$909.00View partBuild a system with it

Run the frame-size arithmetic from the worked example against the frame rate you need, and the link decision follows from the same numbers.

The PC side changes shape as well: the frame grabber and its strobe outputs disappear, and the GenICam runtime wants ordinary Ethernet. A vision controller sized for a small cell carries cameras and lighting in one enclosure:

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$2,419.00View partBuild a system with it

The MV-VC3301H-128G66 pairs an Intel Core i3 with 8 GB of memory, 5+ LAN ports, 3-4 USB 3 ports and 4 built-in channels for driving lights, so the strobing that used to come from the frame grabber moves onto the controller. This model has no PoE, so put PoE-capable network hardware in front of it if you want to power the cameras over the data cable.

Bring the bandwidth arithmetic and the six checks to the decision: the camera finder filters by interface, resolution and shutter, the vision controllers page covers the PC side, and the configurator steps through camera, lens and light in order.

Build the whole station

The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.

Start with the camera

If the cutover date is fixed and the camera count is mixed, send us the frame-size table and the legacy camera list through the quote request page, and we will size the links and the controller with you.

Questions

Is GigE Vision the same thing as GenICam?

No. GigE Vision is the transport protocol that carries images and control over gigabit Ethernet; GenICam is the parameter language spoken on top of it. A GigE Vision camera must implement GenICam, and the same GenICam layer runs over USB3 Vision, CoaXPress and Camera Link, so the node map looks alike across all of them.

Can my old IEEE 1394 camera run under a GenICam SDK?

No. An IIDC 1394 camera does not carry the XML description file a GenICam runtime parses, so no node map exists and no GenICam SDK can control it. Recent SDK generations have dropped IEEE 1394 support entirely, which is why the camera replacement and the SDK port should share one project plan and one cutover date.

Where do my saved camera settings go after the port?

Settings files from the legacy SDK are keyed by register address, and the new cameras describe features by name instead, so nothing transfers directly. Re-teach each value once, write it to a user set bank on the camera, and have the application load that set at startup — the settings then survive power cycles and camera swaps.

Which interface should the replacement camera use?

Size it from the arithmetic: width × height × bytes per pixel × frame rate. One GigE link sustains about 110 MB/s, USB 3 about 400 MB/s, and 10GigE or CoaXPress beyond that. Compute your demand, add about 20% headroom, and take the first interface up the ladder that clears it.

Do the trigger pins and timing survive the port?

The physical trigger input stays on the camera; the software changes from a register write to TriggerMode, TriggerSource and edge-selection nodes. Bench-check two numbers before cutover: trigger-to-exposure latency, and the shortest interval between pulses your line rate requires — a trigger arriving faster than the camera can rearm silently drops frames.