Getting Started with C¶
The Spinnaker C API provides a handle-based interface for embedded systems and environments where C++ exceptions are not suitable.
Prerequisites¶
- Spinnaker SDK installed (download)
- C compiler (Visual Studio 2015+ on Windows, GCC on Linux, Clang on macOS)
- A supported Teledyne camera connected via USB3 or GigE
Basic Acquisition Example¶
The canonical example is located at src/Acquisition_C/Acquisition_C.c in the SDK.
Below is the essential workflow:
#include "SpinnakerC.h"
int main()
{
spinError err = SPINNAKER_ERR_SUCCESS;
// Get the system
spinSystem hSystem = NULL;
err = spinSystemGetInstance(&hSystem);
// Retrieve camera list
spinCameraList hCameraList = NULL;
err = spinCameraListCreateEmpty(&hCameraList);
err = spinSystemGetCameras(hSystem, hCameraList);
// Get the first camera
spinCamera hCam = NULL;
err = spinCameraListGet(hCameraList, 0, &hCam);
// Initialize
err = spinCameraInit(hCam);
// Begin acquisition
err = spinCameraBeginAcquisition(hCam);
// Retrieve images
for (int i = 0; i < 10; i++)
{
spinImage hImage = NULL;
err = spinCameraGetNextImageEx(hCam, 1000, &hImage);
bool8_t isIncomplete = False;
spinImageIsIncomplete(hImage, &isIncomplete);
if (!isIncomplete)
{
size_t width = 0, height = 0;
spinImageGetWidth(hImage, &width);
spinImageGetHeight(hImage, &height);
printf("Image %d: %zu x %zu\n", i, width, height);
}
// Release image
spinImageRelease(hImage);
}
// Clean up
err = spinCameraEndAcquisition(hCam);
err = spinCameraDeInit(hCam);
err = spinCameraRelease(hCam);
err = spinCameraListClear(hCameraList);
err = spinCameraListDestroy(hCameraList);
err = spinSystemReleaseInstance(hSystem);
return 0;
}
Key Concepts¶
Error Handling¶
Every C API function returns a spinError value. Always check return codes:
spinError err = spinCameraInit(hCam);
if (err != SPINNAKER_ERR_SUCCESS)
{
printf("Error initializing camera: %d\n", err);
return -1;
}
Node Access¶
Use node handle functions to access GenICam features:
spinNodeMapHandle hNodeMap = NULL;
spinCameraGetNodeMap(hCam, &hNodeMap);
spinNodeHandle hAcquisitionMode = NULL;
spinNodeMapGetNode(hNodeMap, "AcquisitionMode", &hAcquisitionMode);
Feature Snippets¶
Hardware Triggering¶
// Enable trigger mode on Line 0 (rising edge)
spinNodeHandle hTriggerMode = NULL;
spinNodeHandle hTriggerModeOn = NULL;
int64_t triggerModeOn = 0;
spinNodeMapGetNode(hNodeMap, "TriggerMode", &hTriggerMode);
spinEnumerationGetEntryByName(hTriggerMode, "On", &hTriggerModeOn);
spinEnumerationEntryGetValue(hTriggerModeOn, &triggerModeOn);
spinEnumerationSetIntValue(hTriggerMode, triggerModeOn);
spinNodeHandle hTriggerSource = NULL;
spinNodeHandle hTriggerSourceLine0 = NULL;
int64_t triggerSourceLine0 = 0;
spinNodeMapGetNode(hNodeMap, "TriggerSource", &hTriggerSource);
spinEnumerationGetEntryByName(hTriggerSource, "Line0", &hTriggerSourceLine0);
spinEnumerationEntryGetValue(hTriggerSourceLine0, &triggerSourceLine0);
spinEnumerationSetIntValue(hTriggerSource, triggerSourceLine0);
See also: src/Trigger_C/Trigger_C.c
Setting Exposure Time¶
// Turn off auto exposure
spinNodeHandle hExposureAuto = NULL;
spinNodeHandle hExposureAutoOff = NULL;
int64_t exposureAutoOff = 0;
spinNodeMapGetNode(hNodeMap, "ExposureAuto", &hExposureAuto);
spinEnumerationGetEntryByName(hExposureAuto, "Off", &hExposureAutoOff);
spinEnumerationEntryGetValue(hExposureAutoOff, &exposureAutoOff);
spinEnumerationSetIntValue(hExposureAuto, exposureAutoOff);
// Set ExposureTime to 20000 microseconds (20 ms)
spinNodeHandle hExposureTime = NULL;
spinNodeMapGetNode(hNodeMap, "ExposureTime", &hExposureTime);
spinFloatSetValue(hExposureTime, 20000.0);
Grabbing Images¶
spinImage hResultImage = NULL;
// Begin acquisition
spinCameraBeginAcquisition(hCam);
// Retrieve image
spinCameraGetNextImageEx(hCam, 1000, &hResultImage);
// Check for errors
spinImageStatus imageStatus = IMAGE_NO_ERROR;
spinImageGetStatus(hResultImage, &imageStatus);
bool8_t isIncomplete = False;
spinImageIsIncomplete(hResultImage, &isIncomplete);
// Release image
spinImageRelease(hResultImage);
spinCameraEndAcquisition(hCam);
Error Handling¶
Every C API function returns spinError. Always check return codes:
spinError err = spinCameraInit(hCam);
if (err != SPINNAKER_ERR_SUCCESS)
{
printf("Camera init failed: %d\n", err);
return -1;
}
Logging¶
// Spinnaker C API logging uses the same five levels as C++:
// Error, Warn, Notice, Info, Debug
// Logs are saved to C:\ProgramData\Spinnaker\Logs
// See src/Logging_C/Logging_C.c for a full example
Design Conventions¶
Understanding these conventions is essential before using the C API — they apply uniformly across all functions.
Handle Lifecycle¶
All SDK objects are opaque handles that must be explicitly created and destroyed:
spinCamera hCamera = NULL;
/* Acquire handle */
spinSystemGetCameras(hSystem, &hCameraList);
spinCameraListGet(hCameraList, 0, &hCamera);
spinCameraInit(hCamera);
/* ... use camera ... */
/* Release in reverse order */
spinCameraDeInit(hCamera);
spinCameraRelease(hCamera);
spinCameraListClear(hCameraList);
spinCameraListDestroy(hCameraList);
Always release in reverse acquisition order
Releasing handles out of order or failing to release them will cause native resource leaks that persist for the process lifetime.
Error Handling¶
Every function returns spinError — always check it:
spinError err = SPINNAKER_ERR_SUCCESS;
err = spinCameraBeginAcquisition(hCamera);
if (err != SPINNAKER_ERR_SUCCESS) {
char errMsg[MAX_BUFF_LEN];
size_t lenMsg = MAX_BUFF_LEN;
spinErrorGetLastMessage(errMsg, &lenMsg);
fprintf(stderr, "BeginAcquisition failed: %s\n", errMsg);
return err;
}
Error Macro
Consider wrapping the check in a macro for cleaner call sites:
#define SPINNAKER_CHECK(call) \
do { \
spinError _err = (call); \
if (_err != SPINNAKER_ERR_SUCCESS) { \
fprintf(stderr, "Error %d at %s:%d\n", \
_err, __FILE__, __LINE__); \
return _err; \
} \
} while(0)
/* Usage */
SPINNAKER_CHECK(spinCameraBeginAcquisition(hCamera));
String & Buffer Pattern¶
Functions that return strings follow a two-call pattern:
/* First call: get required buffer size */
size_t len = 0;
spinCameraGetDeviceSerialNumber(hCamera, NULL, &len);
/* Second call: fill the buffer */
char serial[len];
spinCameraGetDeviceSerialNumber(hCamera, serial, &len);
Quick Reference¶
System & Discovery¶
| Function | Description |
|---|---|
spinSystemGetInstance() |
Obtain the system singleton |
spinSystemReleaseInstance() |
Release the system singleton |
spinSystemGetCameras() |
Enumerate connected cameras |
spinSystemGetLibraryVersion() |
Query SDK version at runtime |
Camera Lifecycle¶
| Function | Description |
|---|---|
spinCameraInit() |
Initialize a camera handle |
spinCameraDeInit() |
De-initialize a camera handle |
spinCameraRelease() |
Release handle back to the system |
spinCameraBeginAcquisition() |
Start image acquisition |
spinCameraEndAcquisition() |
Stop image acquisition |
Image Handling¶
| Function | Description |
|---|---|
spinCameraGetNextImageEx() |
Retrieve next image with timeout |
spinImageIsIncomplete() |
Check for incomplete transfer |
spinImageGetData() |
Access raw pixel buffer |
spinImageGetWidth() |
Get image width in pixels |
spinImageGetHeight() |
Get image height in pixels |
spinImageGetPixelFormat() |
Get current pixel format |
spinImageRelease() |
Release image back to buffer pool |
Node Map & Configuration¶
| Function | Description |
|---|---|
spinCameraGetNodeMap() |
Access GenICam node map |
spinCameraGetTLDeviceNodeMap() |
Access transport layer device node map |
spinCameraGetTLStreamNodeMap() |
Access transport layer stream node map |
spinNodeMapGetNode() |
Retrieve a node by name |
spinIntegerGetValue() |
Read an integer node value |
spinIntegerSetValue() |
Write an integer node value |
spinEnumerationSetEnumValue() |
Set an enumeration node |
spinBooleanGetValue() |
Read a boolean node value |
Camera List¶
| Function | Description |
|---|---|
spinCameraListCreateEmpty() |
Create an empty camera list |
spinCameraListDestroy() |
Destroy a camera list |
spinCameraListClear() |
Clear all entries from a list |
spinCameraListGetSize() |
Get number of cameras in list |
spinCameraListGet() |
Get camera handle by index |
Error Handling¶
| Function | Description |
|---|---|
spinErrorGetLastMessage() |
Get last error message string |
spinErrorGetLastFullMessage() |
Get full error details |
spinErrorGetLastFileName() |
Get source file of last error |
spinErrorGetLastFunctionName() |
Get function name of last error |
spinErrorGetLastLineNumber() |
Get line number of last error |
Error Code Reference¶
| Code | Value | Meaning |
|---|---|---|
SPINNAKER_ERR_SUCCESS |
0 | Operation succeeded |
SPINNAKER_ERR_ERROR |
-1001 | Generic error |
SPINNAKER_ERR_NOT_INITIALIZED |
-1002 | System not initialized |
SPINNAKER_ERR_NOT_IMPLEMENTED |
-1003 | Feature not implemented |
SPINNAKER_ERR_RESOURCE_IN_USE |
-1004 | Resource already in use |
SPINNAKER_ERR_ACCESS_DENIED |
-1005 | Insufficient permissions |
SPINNAKER_ERR_INVALID_HANDLE |
-1006 | NULL or invalid handle |
SPINNAKER_ERR_INVALID_ID |
-1007 | Invalid node or camera ID |
SPINNAKER_ERR_NO_DATA |
-1008 | No data available |
SPINNAKER_ERR_INVALID_PARAMETER |
-1009 | Bad argument value |
SPINNAKER_ERR_IO |
-1010 | I/O failure |
SPINNAKER_ERR_TIMEOUT |
-1011 | Operation timed out |
SPINNAKER_ERR_ABORT |
-1012 | Operation aborted |
SPINNAKER_ERR_INVALID_BUFFER |
-1013 | Buffer too small or NULL |
SPINNAKER_ERR_NOT_AVAILABLE |
-1014 | Feature not available on device |
Known Issues & Limitations¶
No Exception Safety
The C API uses error codes exclusively. There is no mechanism to catch unhandled errors propagated from the underlying C++ layer. Always check every return value.
Buffer Ownership
Buffers returned by spinImageGetData() are owned by the SDK.
Do not free() them — call spinImageRelease() to return
the buffer to the acquisition pool.
Further Reading¶
- C API Reference — Full function documentation
- Programmer's Guide — Architecture, nodes, image pointer, and more
- Streaming Drivers — GigE driver configuration
- SDK Example: Acquisition_C — Full acquisition example
- SDK Example: Trigger_C — Hardware and software triggering
- SDK Example: Exposure_C — Exposure control