GrabCallback

GrabCallback.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "ItalaApiC/ItalaC.h"

#ifdef _WIN32
#include <windows.h>
#define THREAD_HANDLE HANDLE
#define THREAD_RETURN DWORD WINAPI
#define SLEEP_MS(ms) Sleep(ms)
#else
#include <pthread.h>
#include <unistd.h>
#define THREAD_HANDLE pthread_t
#define THREAD_RETURN void*
#define SLEEP_MS(ms) usleep((ms) * 1000)
#endif

#define INDENT "\t"

// Define a convenient type for the callback function pointer
typedef void (*GrabCallback_t)(H_IMAGE hImage);

// Structure to pass data to the acquisition thread
typedef struct {
  H_DEVICE hDevice;
  GrabCallback_t callback;
  volatile bool* pDone;
} AcquisitionThreadData;

// Error manager helper function
ItalaError ErrorManager(ItalaError e) {
  size_t sizeMessage = 255;
  char* message = (char*)malloc(sizeof(char) * sizeMessage);
  ERR_GetLastErrorMessage(message, &sizeMessage);
  printf("\nITALA ERROR (%d):\t%s, %zu char\n", ERR_GetLastErrorCode(), message, sizeMessage);
  free(message);
  return e;
}

/**
 * Grab images in a polling loop (until the "done" flag is true). Then call the callback function
 * provided by the user. The "done" flag is passed by reference. Don't forget to handle errors,
 * otherwise the thread will terminate. This function is meant to be run in a dedicated thread.
 */
THREAD_RETURN AcquisitionLoop(void* pData) {
  AcquisitionThreadData* pThreadData = (AcquisitionThreadData*)pData;
  H_IMAGE hImage = NULL;
  ItalaError error = ItalaErrorSuccess;

  while (!(*pThreadData->pDone)) {
    error = DEV_GetNextImage(pThreadData->hDevice, 1000, &hImage);

    if (error == ItalaErrorSuccess) {
      // Call the user callback with the image
      pThreadData->callback(hImage);
    }
    else if (error == ItalaErrorTimeout) {
      printf("%sTimeout occurred!\n", INDENT);
    }
    else {
      printf("%sError getting next image.\n", INDENT);
      ErrorManager(error);
      break;
    }
  }

#ifdef _WIN32
  return 0;
#else
  return NULL;
#endif
}

/**
 * The actual user callback, called when an image is available.
 */
void GrabCallback(H_IMAGE hImage) {
  ItalaError error = ItalaErrorSuccess;
  uint64_t frameID = 0;

  // Simulate some image processing
  SLEEP_MS(10);

  // Get and print the frame ID
  error = IMG_GetFrameID(hImage, &frameID);
  if (error == ItalaErrorSuccess) {
    printf("%sImage with ID:%llu processed.\n", INDENT, (unsigned long long)frameID);
  }
  else {
    printf("%sImage processed (could not get frame ID).\n", INDENT);
  }

  // Dispose the image when no longer needed
  error = IMG_Dispose(hImage);
  if (error) return ErrorManager(error);
}

int main(int argc, char** argv) {
  printf("***** GrabCallback C example started. *****\n\n");

  ItalaError error = ItalaErrorSuccess;
  H_DEVICE hDevice = NULL;
  size_t devicesInfoSize = 0;
  DeviceInfo deviceInfo;
  volatile bool done = false;
  AcquisitionThreadData threadData;
  THREAD_HANDLE grabberThread;

  // Initialize the system
  error = SYS_Initialize();
  if (error) return ErrorManager(error);
 

  // Enumerate devices
  error = SYS_EnumerateDevices(700);
  if (error) return ErrorManager(error);

  error = SYS_GetDeviceCount(&devicesInfoSize);
  if (error) return ErrorManager(error);

  if (devicesInfoSize == 0) {
    printf("No devices found. Example canceled.\n");
    return ItalaErrorError;
  }

  // Get the first device
  error = SYS_GetDeviceByIndex(0, &deviceInfo);
  if (error) return ErrorManager(error);

  // Check if the device is accessible in read-write mode
  if (deviceInfo.AccessStatus != AvailableReadWrite) {
    printf("Target device is unaccessible in RW mode. Example canceled.\n");
    return ItalaErrorError;
  }

  // Create the device
  error = SYS_CreateDevice(deviceInfo, &hDevice);
  if (error) return ErrorManager(error);
  printf("First device initialized.\n");

  // Start acquisition
  error = DEV_StartAcquisition(hDevice);
  if (error) return ErrorManager(error);
  printf("Acquisition started.\n\n");

  // Prepare thread data
  threadData.hDevice = hDevice;
  threadData.callback = GrabCallback;
  threadData.pDone = &done;

  // Start the acquisition thread. The "done" variable is passed by reference
  // to the "AcquisitionLoop" function
#ifdef _WIN32
  grabberThread = CreateThread(NULL, 0, AcquisitionLoop, &threadData, 0, NULL);
  if (grabberThread == NULL) {
    printf("Failed to create acquisition thread.\n");
    DEV_StopAcquisition(hDevice);
    DEV_Dispose(hDevice);
    SYS_Dispose();
    return ItalaErrorError;
  }
#else
  if (pthread_create(&grabberThread, NULL, AcquisitionLoop, &threadData) != 0) {
    printf("Failed to create acquisition thread.\n");
    DEV_StopAcquisition(hDevice);
    DEV_Dispose(hDevice);
    SYS_Dispose();
    return ItalaErrorError;
  }
#endif

  // Wait for user input to set the "done" flag to true and stop the acquisition
  printf("Press Enter to stop acquisition..\n\n");
  getchar();
  done = true;

  // Wait for the thread to finish
#ifdef _WIN32
  WaitForSingleObject(grabberThread, INFINITE);
  CloseHandle(grabberThread);
#else
  pthread_join(grabberThread, NULL);
#endif

  // Stop acquisition
  error = DEV_StopAcquisition(hDevice);
  if (error) return ErrorManager(error);
  printf("\nAcquisition stopped.\n\n");

  // Dispose the device
  error = DEV_Dispose(hDevice);
  hDevice = NULL;
  if (error) return ErrorManager(error);
  printf("Device instance disposed.\n");

  // Dispose the system
  error = SYS_Dispose();
  if (error) return ErrorManager(error);
  printf("System instance disposed.\n");
  return 0;
}