Events#

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

#ifdef _WIN32
  #include <windows.h>
  #define SLEEP_MS(ms) Sleep(ms)
#else
  #include <unistd.h>
  #define SLEEP_MS(ms) usleep(ms * 1000)
#endif

#define SLEEP 1000

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", ERR_GetLastErrorCode(), message, sizeMessage);
  free(message);
  return e;
}

// Define a callback function which can be registered to a node with GenApi.
// When the target node value changes, the callback is executed. The value
// change is performed automatically by Itala API when the event related
// to the node occurs (e.g. when an exposure end event occurs,
// the EventExposureEndTimestamp node value changes).
void EventExposureEndTimestampCallback(H_NODE hNode, void* pContext) {
  ItalaError error = ItalaErrorSuccess;
  int64_t timestamp = 0;
  error = NODE_IntegerGetValue(hNode, &timestamp);
  if (!error)
    printf(
        "\tExposureEndEventTimestamp value change detected by the node callback, new value is  "
        "%jd\n",
        timestamp);
  else
    printf("\tSome erros occures in the callback.\n");
}

// Define a callback which is automatically called when a device event is detected.
void DeviceEventCallback(H_DEVICE hDevice, uint64_t eventId, void* pContext) {
  H_NODEMAP hNodeMap = NULL;
  DEV_GetNodeMap(hDevice, &hNodeMap);
  H_NODE hNodeEventExposureEnd = NULL;
  NODEMAP_GetNode(hNodeMap, "EventExposureEnd", &hNodeEventExposureEnd);

  int64_t eventExposureEndValue = 0;
  NODE_IntegerGetValue(hNodeEventExposureEnd, &eventExposureEndValue);

  if (eventExposureEndValue == eventId) {
    H_NODE hNodeEventExposereEndTimestamp = NULL;
    NODEMAP_GetNode(hNodeMap, "EventExposureEndTimestamp", &hNodeEventExposereEndTimestamp);
    int64_t eventExposereEndTimestampValue = 0;
    NODE_IntegerGetValue(hNodeEventExposereEndTimestamp, &eventExposereEndTimestampValue);
    printf("\nEvent callback called on device event, occurred at %jd\n\n",
           eventExposereEndTimestampValue);
  }
}

int main(int argc, char** argv) {
  printf("***** Events example started. *****\n");
  ItalaError error = ItalaErrorSuccess;

  error = SYS_Initialize();
  if (error) return ErrorManager(error);

  size_t devicesInfoSize = 0;
  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;
  }
  DeviceInfo deviceInfo;
  error = SYS_GetDeviceByIndex(0, &deviceInfo);
  if (error) return ErrorManager(error);
  if (deviceInfo.AccessStatus != AvailableReadWrite) {
    printf("Target device is unaccessible in RW mode. Example canceled.\n");
    return ItalaErrorError;
  }

  H_DEVICE hDevice = NULL;
  error = SYS_CreateDevice(deviceInfo, &hDevice);
  if (error) return ErrorManager(error);
  printf("First device found is initialized.\n");

  H_NODEMAP hNodeMap = NULL;
  error = DEV_GetNodeMap(hDevice, &hNodeMap);
  if (error) return ErrorManager(error);

  // Select the exposure end event..
  H_NODE hNodeEventSelector = NULL;
  error = NODEMAP_GetNode(hNodeMap, "EventSelector", &hNodeEventSelector);
  if (error) return ErrorManager(error);
  bool isWritable = false;
  error = IsNodeWritable(hNodeEventSelector, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to select the exposure end event. Aborting.\n");
    return ItalaErrorError;
  }
  error = NODE_FromString(hNodeEventSelector, "ExposureEnd");

  // ..and enable it on the device. The original value is also kept so
  // that it can be restored at the end of the example.
  H_NODE hNodeEventNotification = NULL;
  error = NODEMAP_GetNode(hNodeMap, "EventNotification", &hNodeEventNotification);
  if (error) return ErrorManager(error);
  isWritable = false;
  error = IsNodeWritable(hNodeEventNotification, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to turn on notifications for exposure end event. Aborting.\n");
    return ItalaErrorError;
  }
  int64_t originalEventNotification = 0;
  error = NODE_EnumerationGetIntValue(hNodeEventNotification, &originalEventNotification);
  if (error) return ErrorManager(error);
  error = NODE_FromString(hNodeEventNotification, "On");
  if (error) return ErrorManager(error);
  printf("Exposure end event enabled on the device.\n");

  // Start to listen for events on the host.
  error = DEV_EnableEvents(hDevice);
  printf("Event listening enabled on the host.\n");

  // Get one of the exposure end event related nodes. In this case, the frame timestamp
  // is chosen. WARNING: the event node is not available until the event occurs, so no
  // availability check is performed here.
  H_NODE hNodeEventExposureEndTimestamp = NULL;
  NODEMAP_GetNode(hNodeMap, "EventExposureEndTimestamp", &hNodeEventExposureEndTimestamp);
  if (error) return ErrorManager(error);

  // The callback is registered to the EventExposureEndTimestamp node. Every time the
  // node value changes, the function gets called and the new value can be read.
  H_NODECALLBACK hNodeCallback = NULL;
  error = NODE_RegisterCallback(hNodeEventExposureEndTimestamp, EventExposureEndTimestampCallback,
                                NULL, &hNodeCallback);
  if (error) return ErrorManager(error);
  printf("Callback registered to the EventExposureEndTimestamp node..\n");

  // Alternatively, a user-defined callback is registered to ItalaApi.
  // When a device event occurs, the callback registered by the user is called.
  error = DEV_RegisterEventCallback(hDevice, DeviceEventCallback, NULL);
  if (error) return ErrorManager(error);

  error = DEV_StartAcquisition(hDevice);
  if (error) return ErrorManager(error);

  // Let the camera perform some exposures..
  SLEEP_MS(SLEEP);

  error = DEV_StopAcquisition(hDevice);
  if (error) return ErrorManager(error);

  // When the callback-on-event functionality is no longer required, the function
  // must be unregistered from the node. The same is true for the device event callback.
  // The event listening must be disabled.
  error = NODE_DeregisterCallback(hNodeEventExposureEndTimestamp, hNodeCallback);
  if (error) return ErrorManager(error);
  error = DEV_DisableEvents(hDevice);
  if (error) return ErrorManager(error);
  error = DEV_DeregisterEventCallback(hDevice);
  if (error) return ErrorManager(error);

  // Set original value in camera
  error = NODE_EnumerationSetIntValue(hNodeEventNotification, originalEventNotification);
  if (error) return ErrorManager(error);

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

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