<commit_before>/* Backend for libdc1394 v2.0 */
#include "cam_iface.h"

#include <dc1394/control.h>
#include <dc1394/utils.h>

//#define CAM_IFACE_CALL_UNLISTEN
#ifdef CAM_IFACE_CALL_UNLISTEN
#include <dc1394/kernel-video1394.h> // for VIDEO1394_IOC_UNLISTEN_CHANNEL
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/select.h>
#include <errno.h>

#undef CAM_IFACE_DC1394_SLOWDEBUG
#define INVALID_FILENO 0
#define DELAY 50000

struct CCdc1394; // forward declaration

// keep functable in sync across backends
typedef struct {
  cam_iface_constructor_func_t construct;
  void (*destruct)(struct CamContext*);

  void (*CCdc1394)(struct CCdc1394*,int,int,int);
  void (*close)(struct CCdc1394*);
  void (*start_camera)(struct CCdc1394*);
  void (*stop_camera)(struct CCdc1394*);
  void (*get_num_camera_properties)(struct CCdc1394*,int*);
  void (*get_camera_property_info)(struct CCdc1394*,
				   int,
				   CameraPropertyInfo*);
  void (*get_camera_property)(struct CCdc1394*,int,long*,int*);
  void (*set_camera_property)(struct CCdc1394*,int,long,int);
  void (*grab_next_frame_blocking)(struct CCdc1394*,
				   unsigned char*,
				   float);
  void (*grab_next_frame_blocking_with_stride)(struct CCdc1394*,
					       unsigned char*,
					       intptr_t,
					       float);
  void (*point_next_frame_blocking)(struct CCdc1394*,unsigned char**,float);
  void (*unpoint_frame)(struct CCdc1394*);
  void (*get_last_timestamp)(struct CCdc1394*,double*);
  void (*get_last_framenumber)(struct CCdc1394*,long*);
  void (*get_num_trigger_modes)(struct CCdc1394*,int*);
  void (*get_trigger_mode_string)(struct CCdc1394*,int,char*,int);
  void (*get_trigger_mode_number)(struct CCdc1394*,int*);
  void (*set_trigger_mode_number)(struct CCdc1394*,int);
  void (*get_frame_offset)(struct CCdc1394*,int*,int*);
  void (*set_frame_offset)(struct CCdc1394*,int,int);
  void (*get_frame_size)(struct CCdc1394*,int*,int*);
  void (*set_frame_size)(struct CCdc1394*,int,int);
  void (*get_max_frame_size)(struct CCdc1394*,int*,int*);
  void (*get_buffer_size)(struct CCdc1394*,int*);
  void (*get_framerate)(struct CCdc1394*,float*);
  void (*set_framerate)(struct CCdc1394*,float);
  void (*get_num_framebuffers)(struct CCdc1394*,int*);
  void (*set_num_framebuffers)(struct CCdc1394*,int);
} CCdc1394_functable;

typedef struct CCdc1394 {
  CamContext inherited;
} CCdc1394;

// forward declarations
CCdc1394* CCdc1394_construct( int device_number, int NumImageBuffers,
			      int mode_number);
void delete_CCdc1394(struct CCdc1394*);

void CCdc1394_CCdc1394(struct CCdc1394*,int,int,int);
void CCdc1394_close(struct CCdc1394*);
void CCdc1394_start_camera(struct CCdc1394*);
void CCdc1394_stop_camera(struct CCdc1394*);
void CCdc1394_get_num_camera_properties(struct CCdc1394*,int*);
void CCdc1394_get_camera_property_info(struct CCdc1394*,
			      int,
			      CameraPropertyInfo*);
void CCdc1394_get_camera_property(struct CCdc1394*,int,long*,int*);
void CCdc1394_set_camera_property(struct CCdc1394*,int,long,int);
void CCdc1394_grab_next_frame_blocking(struct CCdc1394*,
			      unsigned char*,
			      float);
void CCdc1394_grab_next_frame_blocking_with_stride(struct CCdc1394*,
					  unsigned char*,
					  intptr_t,
					  float);
void CCdc1394_point_next_frame_blocking(struct CCdc1394*,unsigned char**,float);
void CCdc1394_unpoint_frame(struct CCdc1394*);
void CCdc1394_get_last_timestamp(struct CCdc1394*,double*);
void CCdc1394_get_last_framenumber(struct CCdc1394*,long*);
void CCdc1394_get_num_trigger_modes(struct CCdc1394*,int*);
void CCdc1394_get_trigger_mode_string(struct CCdc1394*,int,char*,int);
void CCdc1394_get_trigger_mode_number(struct CCdc1394*,int*);
void CCdc1394_set_trigger_mode_number(struct CCdc1394*,int);
void CCdc1394_get_frame_offset(struct CCdc1394*,int*,int*);
void CCdc1394_set_frame_offset(struct CCdc1394*,int,int);
void CCdc1394_get_frame_size(struct CCdc1394*,int*,int*);
void CCdc1394_set_frame_size(struct CCdc1394*,int,int);
void CCdc1394_get_max_frame_size(struct CCdc1394*,int*,int*);
void CCdc1394_get_buffer_size(struct CCdc1394*,int*);
void CCdc1394_get_framerate(struct CCdc1394*,float*);
void CCdc1394_set_framerate(struct CCdc1394*,float);
void CCdc1394_get_num_framebuffers(struct CCdc1394*,int*);
void CCdc1394_set_num_framebuffers(struct CCdc1394*,int);

CCdc1394_functable CCdc1394_vmt = {
  (cam_iface_constructor_func_t)CCdc1394_construct,
  (void (*)(CamContext*))delete_CCdc1394,
  CCdc1394_CCdc1394,
  CCdc1394_close,
  CCdc1394_start_camera,
  CCdc1394_stop_camera,
  CCdc1394_get_num_camera_properties,
  CCdc1394_get_camera_property_info,
  CCdc1394_get_camera_property,
  CCdc1394_set_camera_property,
  CCdc1394_grab_next_frame_blocking,
  CCdc1394_grab_next_frame_blocking_with_stride,
  CCdc1394_point_next_frame_blocking,
  CCdc1394_unpoint_frame,
  CCdc1394_get_last_timestamp,
  CCdc1394_get_last_framenumber,
  CCdc1394_get_num_trigger_modes,
  CCdc1394_get_trigger_mode_string,
  CCdc1394_get_trigger_mode_number,
  CCdc1394_set_trigger_mode_number,
  CCdc1394_get_frame_offset,
  CCdc1394_set_frame_offset,
  CCdc1394_get_frame_size,
  CCdc1394_set_frame_size,
  CCdc1394_get_max_frame_size,
  CCdc1394_get_buffer_size,
  CCdc1394_get_framerate,
  CCdc1394_set_framerate,
  CCdc1394_get_num_framebuffers,
  CCdc1394_set_num_framebuffers
};

/* typedefs */
struct cam_iface_dc1394_mode {
  dc1394video_mode_t video_mode;
  dc1394framerate_t framerate;
  dc1394color_coding_t color_coding;
};
typedef struct cam_iface_dc1394_mode cam_iface_dc1394_mode_t;

struct cam_iface_dc1394_modes {
  int num_modes;
  cam_iface_dc1394_mode_t *modes;
};
typedef struct cam_iface_dc1394_modes cam_iface_dc1394_modes_t;

struct cam_iface_dc1394_feature_list {
  int num_features;
  int *dc1394_feature_ids;
};
typedef struct cam_iface_dc1394_feature_list cam_iface_dc1394_feature_list_t;

/* globals -- allocate space */
dc1394_t * libdc1394_instance=NULL;
int cam_iface_error = 0;
#define CAM_IFACE_MAX_ERROR_LEN 255
char cam_iface_error_string[CAM_IFACE_MAX_ERROR_LEN]  = {0x00}; //...

uint32_t num_cameras = 0;
dc1394camera_t **cameras = NULL;
cam_iface_dc1394_modes_t *modes_by_device_number=NULL;
cam_iface_dc1394_feature_list_t *features_by_device_number=NULL;

#define CAM_IFACE_ERROR_FORMAT(m)					\
  snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	   "%s (%d): %s\n",__FILE__,__LINE__,(m));

#define CAM_IFACE_CHECK_DEVICE_NUMBER(m)				\
  if ( ((m)<0) | ((m)>=num_cameras) ) {					\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("invalid device_number");			\
    return;								\
  }

#define CIDC1394CHK(err) {						\
    dc1394error_t m = (err);						\
    if (m!=DC1394_SUCCESS) {						\
      cam_iface_error = -1;						\
      snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	       "%s (%d): libdc1394 err %d: %s\n",__FILE__,__LINE__,	\
	       m,							\
	       dc1394_error_get_string(m));				\
      return;								\
    }									\
  }

#define CIDC1394CHKV(err) {						\
    dc1394error_t m = (err);						\
    if (m!=DC1394_SUCCESS) {						\
      cam_iface_error = -1;						\
      snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	       "%s (%d): libdc1394 err %d: %s\n",__FILE__,__LINE__,	\
	       m,							\
	       dc1394_error_get_string(m));				\
      return NULL;							\
    }									\
  }


#define CHECK_CC(m)							\
  if (!(m)) {								\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("no CamContext specified (NULL argument)");	\
    return;								\
  }

#define CHECK_CCV(m)							\
  if (!(m)) {								\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("no CamContext specified (NULL argument)");	\
    return NULL;							\
  }


#define NOT_IMPLEMENTED					\
  cam_iface_error = -1;					\
  CAM_IFACE_ERROR_FORMAT("not yet implemented");	\
  return;

int cam_iface_is_video_mode_scalable(dc1394video_mode_t video_mode)
{
  return ((video_mode>=DC1394_VIDEO_MODE_FORMAT7_MIN)&&(video_mode<=DC1394_VIDEO_MODE_FORMAT7_MAX));
}

/* internal structures for dc1394 implementation */

struct _cam_iface_backend_extras {
  char *device_name;

  int cam_iface_mode_number; // different than DC1934 mode number

  int max_width;       // maximum buffer width
  int max_height;      // maximum buffer height
  int roi_width;
  int roi_height;
  int buffer_size;     // bytes per frame
  long nframe_hack;

  int num_dma_buffers;
  uint64_t last_timestamp;

  // for select()
  int fileno;
  fd_set fdset;
  int nfds;
  int capture_is_set;
};
typedef struct _cam_iface_backend_extras cam_iface_backend_extras;

const char *cam_iface_get_driver_name() {
  return "dc1394";
}

void cam_iface_clear_error() {
  cam_iface_error = 0;
}

int cam_iface_have_error() {
  return cam_iface_error;
}

const char * cam_iface_get_error_string() {
  return cam_iface_error_string;
}

dc1394bool_t _available_feature_filter( int feature_id, dc1394bool_t was_available ) {
  if (!was_available) {
    return was_available;
  }
  switch (feature_id) {
  case DC1394_FEATURE_TRIGGER: return 0; break;
  default: return 1;
  }
}

const char* cam_iface_get_api_version() {
  return CAM_IFACE_API_VERSION;
}

#define MODE_CASE(m) case m:\
    result = #m;	      \
  break;

void fprint_dc1394format7mode_t(FILE* fd, dc1394format7mode_t* mode) {
  if (!(mode->present)) {
    fprintf(fd,"present: FALSE\n");
    return;
  }

  fprintf(fd,"present: TRUE\n");
  fprintf(fd,"size_x: %d\n",mode->size_x);
  fprintf(fd,"size_y: %d\n",mode->size_y);
  fprintf(fd,"max_size_x: %d\n",mode->max_size_x);
  fprintf(fd,"max_size_y: %d\n",mode->max_size_y);
  fprintf(fd,"(more info display not implemented...)\n");
};

const char* get_dc1394_mode_string(dc1394video_mode_t mode) {
  const char* result;
  switch (mode) {
  MODE_CASE(DC1394_VIDEO_MODE_160x120_YUV444)
  MODE_CASE(DC1394_VIDEO_MODE_320x240_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_YUV411)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_EXIF)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_0)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_1)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_2)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_3)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_4)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_5)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_6)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_7)
  default:
    result = "UNKNOWN";
  }
  return result;

}

void cam_iface_startup() {
  //extern void cam_iface_startup() {
  int device_number,i,j,current_mode,feature_number;
  dc1394video_modes_t video_modes;
  dc1394framerates_t framerates;
  dc1394featureset_t features;
  dc1394feature_info_t    *feature_info;
  dc1394color_codings_t color_codings;
  dc1394camera_list_t * list;

  libdc1394_instance = dc1394_new ();

  // Disable printouts of error messages - we are pretty good about
  // checking return codes, so this should be fine.
  CIDC1394CHK(dc1394_log_register_handler(DC1394_LOG_ERROR,NULL,NULL));

  CIDC1394CHK(dc1394_camera_enumerate (libdc1394_instance, &list));

  num_cameras = list->num;

  cameras = malloc( num_cameras*sizeof(dc1394camera_t));
  if (cameras == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  modes_by_device_number = malloc( num_cameras*sizeof(cam_iface_dc1394_modes_t));
  if (modes_by_device_number == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  features_by_device_number = malloc( num_cameras*sizeof(cam_iface_dc1394_feature_list_t));
  if (features_by_device_number == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  // initialize cameras
  for (device_number=0;device_number<num_cameras;device_number++) {
    cameras[device_number] = dc1394_camera_new( libdc1394_instance, list->ids[device_number].guid );
    if (!cameras[device_number]) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("Failed to initialize camera.");
      return;
    }
  }

  // initialize new structures
  for (device_number=0;device_number<num_cameras;device_number++) {
    modes_by_device_number[device_number].num_modes = 0;
    modes_by_device_number[device_number].modes = NULL;
    features_by_device_number[device_number].num_features = 0;
    features_by_device_number[device_number].dc1394_feature_ids = NULL;
  }

  // fill new structures
  for (device_number=0;device_number<num_cameras;device_number++) {
    // features: pass 1 count num available
    CIDC1394CHK(dc1394_feature_get_all(cameras[device_number], &features));
    for (i=0; i<DC1394_FEATURE_NUM; i++) {
      feature_info = &(features.feature[i]);

      if (_available_feature_filter( feature_info->id, feature_info->available)) {
	features_by_device_number[device_number].num_features++;
      }

#ifdef DISABLE_TRIGGER_CODE
      if (feature_info->id == DC1394_FEATURE_TRIGGER) {
	continue;
      }
#endif

      if (feature_info->id == DC1394_FEATURE_TRIGGER) {
	/*
	printf("feature_info->trigger_modes.num = %d\n",feature_info->trigger_modes.num);
	for (j=0; j<(feature_info->trigger_modes.num); j++) {
	  printf("AVAIL feature_info->trigger_mode = %d\n",feature_info->trigger_modes.modes[j]);
	}
	printf("feature_info->trigger_mode = %d\n",feature_info->trigger_mode);
	printf("feature_info->trigger_polarity = %d\n",feature_info->trigger_polarity);
	printf("feature_info->trigger_sources.num = %d\n",feature_info->trigger_sources.num);
	for (j=0; j<(feature_info->trigger_sources.num); j++) {
	  printf("AVAIL feature_info->trigger_source = %d\n",feature_info->trigger_sources.sources[j]);
	}
	printf("feature_info->trigger_source = %d\n",feature_info->trigger_source);
	*/

	if (feature_info->trigger_sources.num) {
	  CIDC1394CHK(dc1394_external_trigger_set_source(cameras[device_number], DC1394_TRIGGER_SOURCE_0));
	  //printf("set source\n");
	}
      }

    }

    // modes:
    CIDC1394CHK(dc1394_video_get_supported_modes(cameras[device_number],
						 &video_modes));

    // enumerate total number of modes ("mode" = dc1394 mode + dc1394 framerate)
    for (i=video_modes.num-1;i>=0;i--) {
      // framerates don't work for format 7
      //fprintf(stderr,"mode: %s ",get_dc1394_mode_string(video_modes.modes[i]));
      if (cam_iface_is_video_mode_scalable(video_modes.modes[i])) {
	// format7
	//dc1394_format7_get_mode_info(cameras[device_number], video_modes.modes[i],&sf7mode);
	//fprint_dc1394format7mode_t(stderr,&sf7mode);
	CIDC1394CHK(dc1394_format7_get_color_codings(cameras[device_number],
						     video_modes.modes[i],
						     &color_codings));
	for (j=0;j<color_codings.num;j++) {
	  modes_by_device_number[device_number].num_modes++; // a single mode entry
	}
      } else {
	CIDC1394CHK(dc1394_video_get_supported_framerates(cameras[device_number],
							  video_modes.modes[i],
							  &framerates));
	for (j=framerates.num-1;j>=0;j--) {
	  modes_by_device_number[device_number].num_modes++;
	  //fprintf(stderr,"non-format7: num_modes++\n");
	}
      }
    }

    // features: pass 2 - allocate memory
    features_by_device_number[device_number].dc1394_feature_ids = malloc(features_by_device_number[device_number].num_features *sizeof(int));
    if (features_by_device_number[device_number].dc1394_feature_ids==NULL) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("error allocating memory");
      return;
    }
    feature_number = 0;
    for (i=0; i<DC1394_FEATURE_NUM; i++) {
      feature_info = &(features.feature[i]);
      if (_available_feature_filter( feature_info->id, feature_info->available)) {
	features_by_device_number[device_number].dc1394_feature_ids[feature_number] = feature_info->id;
	feature_number++;
      }
    }

    // modes:

    // allocate memory for each device to store possible modes
    modes_by_device_number[device_number].modes = malloc(modes_by_device_number[device_number].num_modes * sizeof(cam_iface_dc1394_mode_t));
    if (modes_by_device_number[device_number].modes==NULL) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("error allocating memory");
      return;
    }

    // now fill mode list
    current_mode = 0;
    // enumerate total number of modes ("mode" = dc1394 mode + dc1394 framerate)
    for (i=video_modes.num-1;i>=0;i--) {
      if (cam_iface_is_video_mode_scalable(video_modes.modes[i])) {
	// format7
	CIDC1394CHK(dc1394_format7_get_color_codings(cameras[device_number],
						     video_modes.modes[i],
						     &color_codings));
	for (j=0;j<color_codings.num;j++) {
	  modes_by_device_number[device_number].modes[current_mode].video_mode = video_modes.modes[i];
	  modes_by_device_number[device_number].modes[current_mode].framerate = -1; // format7 - no framerate
	  modes_by_device_number[device_number].modes[current_mode].color_coding = color_codings.codings[j];
	  current_mode++;
	}
      } else {
	CIDC1394CHK(dc1394_video_get_supported_framerates(cameras[device_number],
							  video_modes.modes[i],
							  &framerates));
	for (j=framerates.num-1;j>=0;j--) {
	  modes_by_device_number[device_number].modes[current_mode].video_mode = video_modes.modes[i];
	  modes_by_device_number[device_number].modes[current_mode].framerate = framerates.framerates[j];
	  CIDC1394CHK(dc1394_get_color_coding_from_video_mode(cameras[device_number],
							      video_modes.modes[i],
							      &(modes_by_device_number[device_number].modes[current_mode].color_coding)));
	  current_mode++;
	}
      }
    }

  }
  dc1394_camera_free_list (list);
}

void cam_iface_shutdown() {
  int device_number;

  for (device_number=0;device_number<num_cameras;device_number++) {
    if (modes_by_device_number!=NULL) {
      if (modes_by_device_number[device_number].modes!=NULL) {
	free(modes_by_device_number[device_number].modes);
      }
    }
    if (features_by_device_number!=NULL) {
      if (features_by_device_number[device_number].dc1394_feature_ids!=NULL) {
	free(features_by_device_number[device_number].dc1394_feature_ids);
      }
    }
  }

  if (modes_by_device_number!=NULL) {
    free(modes_by_device_number);
  }

  if (features_by_device_number!=NULL) {
    free(features_by_device_number);
  }

  for (device_number=0;device_number<num_cameras;device_number++) {
    dc1394_camera_free(cameras[device_number]);
  }

  free(cameras);

  num_cameras=0;
}


int cam_iface_get_num_cameras() {
  return num_cameras;
}

void cam_iface_get_camera_info(int device_number, Camwire_id *out_camid) {
  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);

  if (out_camid==NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("return structure NULL");
    return;
  }
  snprintf(out_camid->vendor, CAMWIRE_ID_MAX_CHARS, "%s", cameras[device_number]->vendor);
  snprintf(out_camid->model, CAMWIRE_ID_MAX_CHARS, "%s", cameras[device_number]->model);
  snprintf(out_camid->chip, CAMWIRE_ID_MAX_CHARS, "%llXh", (long long unsigned int)cameras[device_number]->guid);
}

void cam_iface_get_num_modes(int device_number, int *num_modes) {
  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);
  *num_modes = modes_by_device_number[device_number].num_modes;
}

int _get_size_for_video_mode(int device_number,
			     dc1394video_mode_t video_mode,
			     uint32_t *h_size,uint32_t *v_size,
			     int *scalable){
  switch (video_mode) {
  case DC1394_VIDEO_MODE_160x120_YUV444: *h_size=160; *v_size=120; break;
  case DC1394_VIDEO_MODE_320x240_YUV422: *h_size=320; *v_size=240; break;
  case DC1394_VIDEO_MODE_640x480_YUV411: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_YUV422: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_RGB8: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_MONO8: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_MONO16: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_800x600_YUV422: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_800x600_RGB8: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_800x600_MONO8: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_YUV422: *h_size=1024; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_RGB8: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_1024x768_MONO8: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_800x600_MONO16: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_MONO16: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_1280x960_YUV422: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1280x960_RGB8: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1280x960_MONO8: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1600x1200_YUV422: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1600x1200_RGB8: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1600x1200_MONO8: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1280x960_MONO16: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1600x1200_MONO16: *h_size=1600; *v_size=1200; break;
  default: *h_size=0; *v_size=0; break;
  }

  if (dc1394_is_video_mode_scalable(video_mode)) {
    if (DC1394_SUCCESS!=dc1394_format7_get_max_image_size(cameras[device_number],
							  video_mode,
							  h_size,v_size)) {
      return 0;
    }
    *scalable = 1;
  } else {
    *scalable = 0;
  }
  return 1;
}

void cam_iface_get_mode_string(int device_number,
			       int mode_number,
			       char* mode_string,
			       int mode_string_maxlen) {
  dc1394video_mode_t video_mode;
  dc1394framerate_t framerate;
  char *coding_string, *framerate_string;
  const char *dc1394_mode_string;
  int scalable;
  uint32_t h_size,v_size;

  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);
  if ((mode_number<0)|
      (mode_number>=modes_by_device_number[device_number].num_modes)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("invalid mode_number");
    return;
  }
  video_mode = modes_by_device_number[device_number].modes[mode_number].video_mode;
  framerate = modes_by_device_number[device_number].modes[mode_number].framerate;

  if (!_get_size_for_video_mode(device_number,video_mode,&h_size,&v_size,&scalable)){
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("Could not get size for video mode");
    return;
  }

  switch (modes_by_device_number[device_number].modes[mode_number].color_coding) {
  case DC1394_COLOR_CODING_MONO8:  coding_string = "MONO8";  break;
  case DC1394_COLOR_CODING_YUV411: coding_string = "YUV411"; break;
  case DC1394_COLOR_CODING_YUV422: coding_string = "YUV422"; break;
  case DC1394_COLOR_CODING_YUV444: coding_string = "YUV444"; break;
  case DC1394_COLOR_CODING_RGB8:   coding_string = "RGB8";   break;
  case DC1394_COLOR_CODING_MONO16: coding_string = "MONO16"; break;
  case DC1394_COLOR_CODING_RGB16:  coding_string = "RGB16";  break;
  case DC1394_COLOR_CODING_MONO16S:coding_string = "MONO16S";break;
  case DC1394_COLOR_CODING_RGB16S: coding_string = "RGB16S"; break;
  case DC1394_COLOR_CODING_RAW8:   coding_string = "RAW8";   break;
  case DC1394_COLOR_CODING_RAW16:  coding_string = "RAW16";  break;
  default: coding_string = "unknown color coding"; break;
  }

  if (cam_iface_is_video_mode_scalable(video_mode)) {
    framerate_string="(user selectable framerate)";
  } else {
    switch (framerate){
    case DC1394_FRAMERATE_1_875: framerate_string="1.875 fps"; break;
    case DC1394_FRAMERATE_3_75:  framerate_string="3.75 fps"; break;
    case DC1394_FRAMERATE_7_5:   framerate_string="7.5 fps"; break;
    case DC1394_FRAMERATE_15:    framerate_string="15 fps"; break;
    case DC1394_FRAMERATE_30:    framerate_string="30 fps"; break;
    case DC1394_FRAMERATE_60:    framerate_string="60 fps"; break;
    case DC1394_FRAMERATE_120:   framerate_string="120 fps"; break;
    case DC1394_FRAMERATE_240:   framerate_string="240 fps"; break;
    default: framerate_string="unknown framerate"; break;
    }
  }

  dc1394_mode_string = get_dc1394_mode_string(video_mode);
  if (dc1394_is_video_mode_scalable(video_mode)) {
    snprintf(mode_string,mode_string_maxlen,"%d x %d %s %s %s",
	     h_size,v_size,dc1394_mode_string,coding_string,framerate_string);
  } else {
    snprintf(mode_string,mode_string_maxlen,"%d x %d %s %s",
	     h_size,v_size,dc1394_mode_string,framerate_string);
  }
}

cam_iface_constructor_func_t cam_iface_get_constructor_func(int device_number) {
  return (CamContext* (*)(int, int, int))CCdc1394_construct;
}

CCdc1394* CCdc1394_construct( int device_number, int NumImageBuffers,
			      int mode_number) {
  CCdc1394* this=NULL;

  this = malloc(sizeof(CCdc1394));
  if (this==NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
  } else {
    CCdc1394_CCdc1394( this,
		       device_number, NumImageBuffers,
		       mode_number);
  }
  return this;
}

void delete_CCdc1394( CCdc1394 *this ) {
  CCdc1394_close(this);
  free(this);
}

void CCdc1394_CCdc1394( CCdc1394 *this,
			int device_number, int NumImageBuffers,
			int mode_number) {
  cam_iface_backend_extras* backend_extras;
  dc1394video_mode_t video_mode, test_video_mode;
  dc1394framerate_t framerate;
  uint32_t h_size,v_size,tmp_depth;
  dc1394color_coding_t coding;
  int scalable;

  // call parent
  CamContext_CamContext((CamContext*)this,device_number,NumImageBuffers,mode_number); // XXX cast error?
  this->inherited.vmt = (CamContext_functable*)&CCdc1394_vmt;

#ifdef CAM_IFACE_DC1394_SLOWDEBUG
  char mode_string[255];

  fprintf(stderr,"attempting to start camera %d with mode_number %d\n",device_number,mode_number);
  cam_iface_get_mode_string(device_number,mode_number,mode_string,255);
  if (cam_iface_error) {
    return;
  }
  fprintf(stderr,"mode string: %s\n",mode_string);
#endif

  if ((device_number < 0)|(device_number >= num_cameras)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("requested invalid camera number");
    return;
  }
  if ((mode_number<0)|
      (mode_number>=modes_by_device_number[device_number].num_modes)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("invalid mode_number");
    return;
  }
  video_mode = modes_by_device_number[device_number].modes[mode_number].video_mode;
  framerate = modes_by_device_number[device_number].modes[mode_number].framerate;
  coding = modes_by_device_number[device_number].modes[mode_number].color_coding;

  /* initialize */
  this->inherited.cam = (void *)NULL;
  this->inherited.backend_extras = malloc(sizeof(cam_iface_backend_extras));
  if (!this) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("malloc failed");
    return;
  }
  backend_extras = (cam_iface_backend_extras*)this->inherited.backend_extras;
  bzero( (void*)backend_extras, sizeof(cam_iface_backend_extras) );
  backend_extras->cam_iface_mode_number = mode_number; // different than DC1934 mode number
  backend_extras->nframe_hack=0;
  backend_extras->fileno = INVALID_FILENO;
  backend_extras->nfds = 0;
  FD_ZERO(&(backend_extras->fdset));

  CIDC1394CHK(dc1394_capture_stop(cameras[device_number]));
  backend_extras->capture_is_set=0;

  backend_extras->device_name=NULL;

  CIDC1394CHK(dc1394_video_set_iso_speed(cameras[device_number], DC1394_ISO_SPEED_400));

  this->inherited.device_number = device_number;

  if (!_get_size_for_video_mode(device_number,video_mode,&h_size,&v_size,&scalable)){
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("Could not get size for video mode");
    return;
  }

  backend_extras->max_width = h_size;
  backend_extras->max_height = v_size;
<commit_msg>stop iso transmission when camera is first initialized<commit_after>/* Backend for libdc1394 v2.0 */
#include "cam_iface.h"

#include <dc1394/control.h>
#include <dc1394/utils.h>

//#define CAM_IFACE_CALL_UNLISTEN
#ifdef CAM_IFACE_CALL_UNLISTEN
#include <dc1394/kernel-video1394.h> // for VIDEO1394_IOC_UNLISTEN_CHANNEL
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/select.h>
#include <errno.h>

#undef CAM_IFACE_DC1394_SLOWDEBUG
#define INVALID_FILENO 0
#define DELAY 50000

struct CCdc1394; // forward declaration

// keep functable in sync across backends
typedef struct {
  cam_iface_constructor_func_t construct;
  void (*destruct)(struct CamContext*);

  void (*CCdc1394)(struct CCdc1394*,int,int,int);
  void (*close)(struct CCdc1394*);
  void (*start_camera)(struct CCdc1394*);
  void (*stop_camera)(struct CCdc1394*);
  void (*get_num_camera_properties)(struct CCdc1394*,int*);
  void (*get_camera_property_info)(struct CCdc1394*,
				   int,
				   CameraPropertyInfo*);
  void (*get_camera_property)(struct CCdc1394*,int,long*,int*);
  void (*set_camera_property)(struct CCdc1394*,int,long,int);
  void (*grab_next_frame_blocking)(struct CCdc1394*,
				   unsigned char*,
				   float);
  void (*grab_next_frame_blocking_with_stride)(struct CCdc1394*,
					       unsigned char*,
					       intptr_t,
					       float);
  void (*point_next_frame_blocking)(struct CCdc1394*,unsigned char**,float);
  void (*unpoint_frame)(struct CCdc1394*);
  void (*get_last_timestamp)(struct CCdc1394*,double*);
  void (*get_last_framenumber)(struct CCdc1394*,long*);
  void (*get_num_trigger_modes)(struct CCdc1394*,int*);
  void (*get_trigger_mode_string)(struct CCdc1394*,int,char*,int);
  void (*get_trigger_mode_number)(struct CCdc1394*,int*);
  void (*set_trigger_mode_number)(struct CCdc1394*,int);
  void (*get_frame_offset)(struct CCdc1394*,int*,int*);
  void (*set_frame_offset)(struct CCdc1394*,int,int);
  void (*get_frame_size)(struct CCdc1394*,int*,int*);
  void (*set_frame_size)(struct CCdc1394*,int,int);
  void (*get_max_frame_size)(struct CCdc1394*,int*,int*);
  void (*get_buffer_size)(struct CCdc1394*,int*);
  void (*get_framerate)(struct CCdc1394*,float*);
  void (*set_framerate)(struct CCdc1394*,float);
  void (*get_num_framebuffers)(struct CCdc1394*,int*);
  void (*set_num_framebuffers)(struct CCdc1394*,int);
} CCdc1394_functable;

typedef struct CCdc1394 {
  CamContext inherited;
} CCdc1394;

// forward declarations
CCdc1394* CCdc1394_construct( int device_number, int NumImageBuffers,
			      int mode_number);
void delete_CCdc1394(struct CCdc1394*);

void CCdc1394_CCdc1394(struct CCdc1394*,int,int,int);
void CCdc1394_close(struct CCdc1394*);
void CCdc1394_start_camera(struct CCdc1394*);
void CCdc1394_stop_camera(struct CCdc1394*);
void CCdc1394_get_num_camera_properties(struct CCdc1394*,int*);
void CCdc1394_get_camera_property_info(struct CCdc1394*,
			      int,
			      CameraPropertyInfo*);
void CCdc1394_get_camera_property(struct CCdc1394*,int,long*,int*);
void CCdc1394_set_camera_property(struct CCdc1394*,int,long,int);
void CCdc1394_grab_next_frame_blocking(struct CCdc1394*,
			      unsigned char*,
			      float);
void CCdc1394_grab_next_frame_blocking_with_stride(struct CCdc1394*,
					  unsigned char*,
					  intptr_t,
					  float);
void CCdc1394_point_next_frame_blocking(struct CCdc1394*,unsigned char**,float);
void CCdc1394_unpoint_frame(struct CCdc1394*);
void CCdc1394_get_last_timestamp(struct CCdc1394*,double*);
void CCdc1394_get_last_framenumber(struct CCdc1394*,long*);
void CCdc1394_get_num_trigger_modes(struct CCdc1394*,int*);
void CCdc1394_get_trigger_mode_string(struct CCdc1394*,int,char*,int);
void CCdc1394_get_trigger_mode_number(struct CCdc1394*,int*);
void CCdc1394_set_trigger_mode_number(struct CCdc1394*,int);
void CCdc1394_get_frame_offset(struct CCdc1394*,int*,int*);
void CCdc1394_set_frame_offset(struct CCdc1394*,int,int);
void CCdc1394_get_frame_size(struct CCdc1394*,int*,int*);
void CCdc1394_set_frame_size(struct CCdc1394*,int,int);
void CCdc1394_get_max_frame_size(struct CCdc1394*,int*,int*);
void CCdc1394_get_buffer_size(struct CCdc1394*,int*);
void CCdc1394_get_framerate(struct CCdc1394*,float*);
void CCdc1394_set_framerate(struct CCdc1394*,float);
void CCdc1394_get_num_framebuffers(struct CCdc1394*,int*);
void CCdc1394_set_num_framebuffers(struct CCdc1394*,int);

CCdc1394_functable CCdc1394_vmt = {
  (cam_iface_constructor_func_t)CCdc1394_construct,
  (void (*)(CamContext*))delete_CCdc1394,
  CCdc1394_CCdc1394,
  CCdc1394_close,
  CCdc1394_start_camera,
  CCdc1394_stop_camera,
  CCdc1394_get_num_camera_properties,
  CCdc1394_get_camera_property_info,
  CCdc1394_get_camera_property,
  CCdc1394_set_camera_property,
  CCdc1394_grab_next_frame_blocking,
  CCdc1394_grab_next_frame_blocking_with_stride,
  CCdc1394_point_next_frame_blocking,
  CCdc1394_unpoint_frame,
  CCdc1394_get_last_timestamp,
  CCdc1394_get_last_framenumber,
  CCdc1394_get_num_trigger_modes,
  CCdc1394_get_trigger_mode_string,
  CCdc1394_get_trigger_mode_number,
  CCdc1394_set_trigger_mode_number,
  CCdc1394_get_frame_offset,
  CCdc1394_set_frame_offset,
  CCdc1394_get_frame_size,
  CCdc1394_set_frame_size,
  CCdc1394_get_max_frame_size,
  CCdc1394_get_buffer_size,
  CCdc1394_get_framerate,
  CCdc1394_set_framerate,
  CCdc1394_get_num_framebuffers,
  CCdc1394_set_num_framebuffers
};

/* typedefs */
struct cam_iface_dc1394_mode {
  dc1394video_mode_t video_mode;
  dc1394framerate_t framerate;
  dc1394color_coding_t color_coding;
};
typedef struct cam_iface_dc1394_mode cam_iface_dc1394_mode_t;

struct cam_iface_dc1394_modes {
  int num_modes;
  cam_iface_dc1394_mode_t *modes;
};
typedef struct cam_iface_dc1394_modes cam_iface_dc1394_modes_t;

struct cam_iface_dc1394_feature_list {
  int num_features;
  int *dc1394_feature_ids;
};
typedef struct cam_iface_dc1394_feature_list cam_iface_dc1394_feature_list_t;

/* globals -- allocate space */
dc1394_t * libdc1394_instance=NULL;
int cam_iface_error = 0;
#define CAM_IFACE_MAX_ERROR_LEN 255
char cam_iface_error_string[CAM_IFACE_MAX_ERROR_LEN]  = {0x00}; //...

uint32_t num_cameras = 0;
dc1394camera_t **cameras = NULL;
cam_iface_dc1394_modes_t *modes_by_device_number=NULL;
cam_iface_dc1394_feature_list_t *features_by_device_number=NULL;

#define CAM_IFACE_ERROR_FORMAT(m)					\
  snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	   "%s (%d): %s\n",__FILE__,__LINE__,(m));

#define CAM_IFACE_CHECK_DEVICE_NUMBER(m)				\
  if ( ((m)<0) | ((m)>=num_cameras) ) {					\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("invalid device_number");			\
    return;								\
  }

#define CIDC1394CHK(err) {						\
    dc1394error_t m = (err);						\
    if (m!=DC1394_SUCCESS) {						\
      cam_iface_error = -1;						\
      snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	       "%s (%d): libdc1394 err %d: %s\n",__FILE__,__LINE__,	\
	       m,							\
	       dc1394_error_get_string(m));				\
      return;								\
    }									\
  }

#define CIDC1394CHKV(err) {						\
    dc1394error_t m = (err);						\
    if (m!=DC1394_SUCCESS) {						\
      cam_iface_error = -1;						\
      snprintf(cam_iface_error_string,CAM_IFACE_MAX_ERROR_LEN,		\
	       "%s (%d): libdc1394 err %d: %s\n",__FILE__,__LINE__,	\
	       m,							\
	       dc1394_error_get_string(m));				\
      return NULL;							\
    }									\
  }


#define CHECK_CC(m)							\
  if (!(m)) {								\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("no CamContext specified (NULL argument)");	\
    return;								\
  }

#define CHECK_CCV(m)							\
  if (!(m)) {								\
    cam_iface_error = -1;						\
    CAM_IFACE_ERROR_FORMAT("no CamContext specified (NULL argument)");	\
    return NULL;							\
  }


#define NOT_IMPLEMENTED					\
  cam_iface_error = -1;					\
  CAM_IFACE_ERROR_FORMAT("not yet implemented");	\
  return;

int cam_iface_is_video_mode_scalable(dc1394video_mode_t video_mode)
{
  return ((video_mode>=DC1394_VIDEO_MODE_FORMAT7_MIN)&&(video_mode<=DC1394_VIDEO_MODE_FORMAT7_MAX));
}

/* internal structures for dc1394 implementation */

struct _cam_iface_backend_extras {
  int cam_iface_mode_number; // different than DC1934 mode number

  int max_width;       // maximum buffer width
  int max_height;      // maximum buffer height
  int roi_width;
  int roi_height;
  int buffer_size;     // bytes per frame
  long nframe_hack;

  int num_dma_buffers;
  uint64_t last_timestamp;

  // for select()
  int fileno;
  fd_set fdset;
  int nfds;
  int capture_is_set;
};
typedef struct _cam_iface_backend_extras cam_iface_backend_extras;

const char *cam_iface_get_driver_name() {
  return "dc1394";
}

void cam_iface_clear_error() {
  cam_iface_error = 0;
}

int cam_iface_have_error() {
  return cam_iface_error;
}

const char * cam_iface_get_error_string() {
  return cam_iface_error_string;
}

dc1394bool_t _available_feature_filter( int feature_id, dc1394bool_t was_available ) {
  if (!was_available) {
    return was_available;
  }
  switch (feature_id) {
  case DC1394_FEATURE_TRIGGER: return 0; break;
  default: return 1;
  }
}

const char* cam_iface_get_api_version() {
  return CAM_IFACE_API_VERSION;
}

#define MODE_CASE(m) case m:\
    result = #m;	      \
  break;

void fprint_dc1394format7mode_t(FILE* fd, dc1394format7mode_t* mode) {
  if (!(mode->present)) {
    fprintf(fd,"present: FALSE\n");
    return;
  }

  fprintf(fd,"present: TRUE\n");
  fprintf(fd,"size_x: %d\n",mode->size_x);
  fprintf(fd,"size_y: %d\n",mode->size_y);
  fprintf(fd,"max_size_x: %d\n",mode->max_size_x);
  fprintf(fd,"max_size_y: %d\n",mode->max_size_y);
  fprintf(fd,"(more info display not implemented...)\n");
};

const char* get_dc1394_mode_string(dc1394video_mode_t mode) {
  const char* result;
  switch (mode) {
  MODE_CASE(DC1394_VIDEO_MODE_160x120_YUV444)
  MODE_CASE(DC1394_VIDEO_MODE_320x240_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_YUV411)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_640x480_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_800x600_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1024x768_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_YUV422)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_RGB8)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_MONO8)
  MODE_CASE(DC1394_VIDEO_MODE_1280x960_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_1600x1200_MONO16)
  MODE_CASE(DC1394_VIDEO_MODE_EXIF)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_0)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_1)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_2)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_3)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_4)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_5)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_6)
  MODE_CASE(DC1394_VIDEO_MODE_FORMAT7_7)
  default:
    result = "UNKNOWN";
  }
  return result;

}

void cam_iface_startup() {
  //extern void cam_iface_startup() {
  int device_number,i,j,current_mode,feature_number;
  dc1394video_modes_t video_modes;
  dc1394framerates_t framerates;
  dc1394featureset_t features;
  dc1394feature_info_t    *feature_info;
  dc1394color_codings_t color_codings;
  dc1394camera_list_t * list;

  libdc1394_instance = dc1394_new ();

  // Disable printouts of error messages - we are pretty good about
  // checking return codes, so this should be fine.
  CIDC1394CHK(dc1394_log_register_handler(DC1394_LOG_ERROR,NULL,NULL));

  CIDC1394CHK(dc1394_camera_enumerate (libdc1394_instance, &list));

  num_cameras = list->num;

  cameras = malloc( num_cameras*sizeof(dc1394camera_t));
  if (cameras == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  modes_by_device_number = malloc( num_cameras*sizeof(cam_iface_dc1394_modes_t));
  if (modes_by_device_number == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  features_by_device_number = malloc( num_cameras*sizeof(cam_iface_dc1394_feature_list_t));
  if (features_by_device_number == NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
    return;
  }

  // initialize cameras
  for (device_number=0;device_number<num_cameras;device_number++) {
    cameras[device_number] = dc1394_camera_new( libdc1394_instance, list->ids[device_number].guid );
    if (!cameras[device_number]) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("Failed to initialize camera.");
      return;
    }
  }

  // initialize new structures
  for (device_number=0;device_number<num_cameras;device_number++) {
    modes_by_device_number[device_number].num_modes = 0;
    modes_by_device_number[device_number].modes = NULL;
    features_by_device_number[device_number].num_features = 0;
    features_by_device_number[device_number].dc1394_feature_ids = NULL;
  }

  // fill new structures
  for (device_number=0;device_number<num_cameras;device_number++) {
    // features: pass 1 count num available
    CIDC1394CHK(dc1394_feature_get_all(cameras[device_number], &features));
    for (i=0; i<DC1394_FEATURE_NUM; i++) {
      feature_info = &(features.feature[i]);

      if (_available_feature_filter( feature_info->id, feature_info->available)) {
	features_by_device_number[device_number].num_features++;
      }

#ifdef DISABLE_TRIGGER_CODE
      if (feature_info->id == DC1394_FEATURE_TRIGGER) {
	continue;
      }
#endif

      if (feature_info->id == DC1394_FEATURE_TRIGGER) {
	/*
	printf("feature_info->trigger_modes.num = %d\n",feature_info->trigger_modes.num);
	for (j=0; j<(feature_info->trigger_modes.num); j++) {
	  printf("AVAIL feature_info->trigger_mode = %d\n",feature_info->trigger_modes.modes[j]);
	}
	printf("feature_info->trigger_mode = %d\n",feature_info->trigger_mode);
	printf("feature_info->trigger_polarity = %d\n",feature_info->trigger_polarity);
	printf("feature_info->trigger_sources.num = %d\n",feature_info->trigger_sources.num);
	for (j=0; j<(feature_info->trigger_sources.num); j++) {
	  printf("AVAIL feature_info->trigger_source = %d\n",feature_info->trigger_sources.sources[j]);
	}
	printf("feature_info->trigger_source = %d\n",feature_info->trigger_source);
	*/

	if (feature_info->trigger_sources.num) {
	  CIDC1394CHK(dc1394_external_trigger_set_source(cameras[device_number], DC1394_TRIGGER_SOURCE_0));
	  //printf("set source\n");
	}
      }

    }

    // modes:
    CIDC1394CHK(dc1394_video_get_supported_modes(cameras[device_number],
						 &video_modes));

    // enumerate total number of modes ("mode" = dc1394 mode + dc1394 framerate)
    for (i=video_modes.num-1;i>=0;i--) {
      // framerates don't work for format 7
      //fprintf(stderr,"mode: %s ",get_dc1394_mode_string(video_modes.modes[i]));
      if (cam_iface_is_video_mode_scalable(video_modes.modes[i])) {
	// format7
	//dc1394_format7_get_mode_info(cameras[device_number], video_modes.modes[i],&sf7mode);
	//fprint_dc1394format7mode_t(stderr,&sf7mode);
	CIDC1394CHK(dc1394_format7_get_color_codings(cameras[device_number],
						     video_modes.modes[i],
						     &color_codings));
	for (j=0;j<color_codings.num;j++) {
	  modes_by_device_number[device_number].num_modes++; // a single mode entry
	}
      } else {
	CIDC1394CHK(dc1394_video_get_supported_framerates(cameras[device_number],
							  video_modes.modes[i],
							  &framerates));
	for (j=framerates.num-1;j>=0;j--) {
	  modes_by_device_number[device_number].num_modes++;
	  //fprintf(stderr,"non-format7: num_modes++\n");
	}
      }
    }

    // features: pass 2 - allocate memory
    features_by_device_number[device_number].dc1394_feature_ids = malloc(features_by_device_number[device_number].num_features *sizeof(int));
    if (features_by_device_number[device_number].dc1394_feature_ids==NULL) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("error allocating memory");
      return;
    }
    feature_number = 0;
    for (i=0; i<DC1394_FEATURE_NUM; i++) {
      feature_info = &(features.feature[i]);
      if (_available_feature_filter( feature_info->id, feature_info->available)) {
	features_by_device_number[device_number].dc1394_feature_ids[feature_number] = feature_info->id;
	feature_number++;
      }
    }

    // modes:

    // allocate memory for each device to store possible modes
    modes_by_device_number[device_number].modes = malloc(modes_by_device_number[device_number].num_modes * sizeof(cam_iface_dc1394_mode_t));
    if (modes_by_device_number[device_number].modes==NULL) {
      cam_iface_error = -1;
      CAM_IFACE_ERROR_FORMAT("error allocating memory");
      return;
    }

    // now fill mode list
    current_mode = 0;
    // enumerate total number of modes ("mode" = dc1394 mode + dc1394 framerate)
    for (i=video_modes.num-1;i>=0;i--) {
      if (cam_iface_is_video_mode_scalable(video_modes.modes[i])) {
	// format7
	CIDC1394CHK(dc1394_format7_get_color_codings(cameras[device_number],
						     video_modes.modes[i],
						     &color_codings));
	for (j=0;j<color_codings.num;j++) {
	  modes_by_device_number[device_number].modes[current_mode].video_mode = video_modes.modes[i];
	  modes_by_device_number[device_number].modes[current_mode].framerate = -1; // format7 - no framerate
	  modes_by_device_number[device_number].modes[current_mode].color_coding = color_codings.codings[j];
	  current_mode++;
	}
      } else {
	CIDC1394CHK(dc1394_video_get_supported_framerates(cameras[device_number],
							  video_modes.modes[i],
							  &framerates));
	for (j=framerates.num-1;j>=0;j--) {
	  modes_by_device_number[device_number].modes[current_mode].video_mode = video_modes.modes[i];
	  modes_by_device_number[device_number].modes[current_mode].framerate = framerates.framerates[j];
	  CIDC1394CHK(dc1394_get_color_coding_from_video_mode(cameras[device_number],
							      video_modes.modes[i],
							      &(modes_by_device_number[device_number].modes[current_mode].color_coding)));
	  current_mode++;
	}
      }
    }

  }
  dc1394_camera_free_list (list);
}

void cam_iface_shutdown() {
  int device_number;

  for (device_number=0;device_number<num_cameras;device_number++) {
    if (modes_by_device_number!=NULL) {
      if (modes_by_device_number[device_number].modes!=NULL) {
	free(modes_by_device_number[device_number].modes);
      }
    }
    if (features_by_device_number!=NULL) {
      if (features_by_device_number[device_number].dc1394_feature_ids!=NULL) {
	free(features_by_device_number[device_number].dc1394_feature_ids);
      }
    }
  }

  if (modes_by_device_number!=NULL) {
    free(modes_by_device_number);
  }

  if (features_by_device_number!=NULL) {
    free(features_by_device_number);
  }

  for (device_number=0;device_number<num_cameras;device_number++) {
    dc1394_camera_free(cameras[device_number]);
  }

  free(cameras);

  num_cameras=0;
}


int cam_iface_get_num_cameras() {
  return num_cameras;
}

void cam_iface_get_camera_info(int device_number, Camwire_id *out_camid) {
  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);

  if (out_camid==NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("return structure NULL");
    return;
  }
  snprintf(out_camid->vendor, CAMWIRE_ID_MAX_CHARS, "%s", cameras[device_number]->vendor);
  snprintf(out_camid->model, CAMWIRE_ID_MAX_CHARS, "%s", cameras[device_number]->model);
  snprintf(out_camid->chip, CAMWIRE_ID_MAX_CHARS, "%llXh", (long long unsigned int)cameras[device_number]->guid);
}

void cam_iface_get_num_modes(int device_number, int *num_modes) {
  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);
  *num_modes = modes_by_device_number[device_number].num_modes;
}

int _get_size_for_video_mode(int device_number,
			     dc1394video_mode_t video_mode,
			     uint32_t *h_size,uint32_t *v_size,
			     int *scalable){
  switch (video_mode) {
  case DC1394_VIDEO_MODE_160x120_YUV444: *h_size=160; *v_size=120; break;
  case DC1394_VIDEO_MODE_320x240_YUV422: *h_size=320; *v_size=240; break;
  case DC1394_VIDEO_MODE_640x480_YUV411: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_YUV422: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_RGB8: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_MONO8: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_640x480_MONO16: *h_size=640; *v_size=480; break;
  case DC1394_VIDEO_MODE_800x600_YUV422: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_800x600_RGB8: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_800x600_MONO8: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_YUV422: *h_size=1024; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_RGB8: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_1024x768_MONO8: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_800x600_MONO16: *h_size=800; *v_size=600; break;
  case DC1394_VIDEO_MODE_1024x768_MONO16: *h_size=1024; *v_size=768; break;
  case DC1394_VIDEO_MODE_1280x960_YUV422: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1280x960_RGB8: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1280x960_MONO8: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1600x1200_YUV422: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1600x1200_RGB8: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1600x1200_MONO8: *h_size=1600; *v_size=1200; break;
  case DC1394_VIDEO_MODE_1280x960_MONO16: *h_size=1280; *v_size=960; break;
  case DC1394_VIDEO_MODE_1600x1200_MONO16: *h_size=1600; *v_size=1200; break;
  default: *h_size=0; *v_size=0; break;
  }

  if (dc1394_is_video_mode_scalable(video_mode)) {
    if (DC1394_SUCCESS!=dc1394_format7_get_max_image_size(cameras[device_number],
							  video_mode,
							  h_size,v_size)) {
      return 0;
    }
    *scalable = 1;
  } else {
    *scalable = 0;
  }
  return 1;
}

void cam_iface_get_mode_string(int device_number,
			       int mode_number,
			       char* mode_string,
			       int mode_string_maxlen) {
  dc1394video_mode_t video_mode;
  dc1394framerate_t framerate;
  char *coding_string, *framerate_string;
  const char *dc1394_mode_string;
  int scalable;
  uint32_t h_size,v_size;

  CAM_IFACE_CHECK_DEVICE_NUMBER(device_number);
  if ((mode_number<0)|
      (mode_number>=modes_by_device_number[device_number].num_modes)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("invalid mode_number");
    return;
  }
  video_mode = modes_by_device_number[device_number].modes[mode_number].video_mode;
  framerate = modes_by_device_number[device_number].modes[mode_number].framerate;

  if (!_get_size_for_video_mode(device_number,video_mode,&h_size,&v_size,&scalable)){
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("Could not get size for video mode");
    return;
  }

  switch (modes_by_device_number[device_number].modes[mode_number].color_coding) {
  case DC1394_COLOR_CODING_MONO8:  coding_string = "MONO8";  break;
  case DC1394_COLOR_CODING_YUV411: coding_string = "YUV411"; break;
  case DC1394_COLOR_CODING_YUV422: coding_string = "YUV422"; break;
  case DC1394_COLOR_CODING_YUV444: coding_string = "YUV444"; break;
  case DC1394_COLOR_CODING_RGB8:   coding_string = "RGB8";   break;
  case DC1394_COLOR_CODING_MONO16: coding_string = "MONO16"; break;
  case DC1394_COLOR_CODING_RGB16:  coding_string = "RGB16";  break;
  case DC1394_COLOR_CODING_MONO16S:coding_string = "MONO16S";break;
  case DC1394_COLOR_CODING_RGB16S: coding_string = "RGB16S"; break;
  case DC1394_COLOR_CODING_RAW8:   coding_string = "RAW8";   break;
  case DC1394_COLOR_CODING_RAW16:  coding_string = "RAW16";  break;
  default: coding_string = "unknown color coding"; break;
  }

  if (cam_iface_is_video_mode_scalable(video_mode)) {
    framerate_string="(user selectable framerate)";
  } else {
    switch (framerate){
    case DC1394_FRAMERATE_1_875: framerate_string="1.875 fps"; break;
    case DC1394_FRAMERATE_3_75:  framerate_string="3.75 fps"; break;
    case DC1394_FRAMERATE_7_5:   framerate_string="7.5 fps"; break;
    case DC1394_FRAMERATE_15:    framerate_string="15 fps"; break;
    case DC1394_FRAMERATE_30:    framerate_string="30 fps"; break;
    case DC1394_FRAMERATE_60:    framerate_string="60 fps"; break;
    case DC1394_FRAMERATE_120:   framerate_string="120 fps"; break;
    case DC1394_FRAMERATE_240:   framerate_string="240 fps"; break;
    default: framerate_string="unknown framerate"; break;
    }
  }

  dc1394_mode_string = get_dc1394_mode_string(video_mode);
  if (dc1394_is_video_mode_scalable(video_mode)) {
    snprintf(mode_string,mode_string_maxlen,"%d x %d %s %s %s",
	     h_size,v_size,dc1394_mode_string,coding_string,framerate_string);
  } else {
    snprintf(mode_string,mode_string_maxlen,"%d x %d %s %s",
	     h_size,v_size,dc1394_mode_string,framerate_string);
  }
}

cam_iface_constructor_func_t cam_iface_get_constructor_func(int device_number) {
  return (CamContext* (*)(int, int, int))CCdc1394_construct;
}

CCdc1394* CCdc1394_construct( int device_number, int NumImageBuffers,
			      int mode_number) {
  CCdc1394* this=NULL;

  this = malloc(sizeof(CCdc1394));
  if (this==NULL) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("error allocating memory");
  } else {
    CCdc1394_CCdc1394( this,
		       device_number, NumImageBuffers,
		       mode_number);
  }
  return this;
}

void delete_CCdc1394( CCdc1394 *this ) {
  CCdc1394_close(this);
  free(this);
}

void CCdc1394_CCdc1394( CCdc1394 *this,
			int device_number, int NumImageBuffers,
			int mode_number) {
  cam_iface_backend_extras* backend_extras;
  dc1394video_mode_t video_mode, test_video_mode;
  dc1394framerate_t framerate;
  uint32_t h_size,v_size,tmp_depth;
  dc1394color_coding_t coding;
  int scalable;

  // call parent
  CamContext_CamContext((CamContext*)this,device_number,NumImageBuffers,mode_number); // XXX cast error?
  this->inherited.vmt = (CamContext_functable*)&CCdc1394_vmt;

#ifdef CAM_IFACE_DC1394_SLOWDEBUG
  char mode_string[255];

  fprintf(stderr,"attempting to start camera %d with mode_number %d\n",device_number,mode_number);
  cam_iface_get_mode_string(device_number,mode_number,mode_string,255);
  if (cam_iface_error) {
    return;
  }
  fprintf(stderr,"mode string: %s\n",mode_string);
#endif

  if ((device_number < 0)|(device_number >= num_cameras)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("requested invalid camera number");
    return;
  }
  if ((mode_number<0)|
      (mode_number>=modes_by_device_number[device_number].num_modes)) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("invalid mode_number");
    return;
  }
  video_mode = modes_by_device_number[device_number].modes[mode_number].video_mode;
  framerate = modes_by_device_number[device_number].modes[mode_number].framerate;
  coding = modes_by_device_number[device_number].modes[mode_number].color_coding;

  /* initialize */
  this->inherited.cam = (void *)NULL;
  this->inherited.backend_extras = malloc(sizeof(cam_iface_backend_extras));
  if (!this) {
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("malloc failed");
    return;
  }
  backend_extras = (cam_iface_backend_extras*)this->inherited.backend_extras;
  bzero( (void*)backend_extras, sizeof(cam_iface_backend_extras) );
  backend_extras->cam_iface_mode_number = mode_number; // different than DC1934 mode number
  backend_extras->nframe_hack=0;
  backend_extras->fileno = INVALID_FILENO;
  backend_extras->nfds = 0;
  FD_ZERO(&(backend_extras->fdset));

  CIDC1394CHK(dc1394_video_set_transmission(cameras[device_number],
					    DC1394_OFF));
  backend_extras->capture_is_set=0;

  CIDC1394CHK(dc1394_video_set_iso_speed(cameras[device_number], DC1394_ISO_SPEED_400));

  this->inherited.device_number = device_number;

  if (!_get_size_for_video_mode(device_number,video_mode,&h_size,&v_size,&scalable)){
    cam_iface_error = -1;
    CAM_IFACE_ERROR_FORMAT("Could not get size for video mode");
    return;
  }

  backend_extras->max_width = h_size;
  backend_extras->max_height = v_size;

{'fraction_non_alphanumeric': 0.10821809213423765, 'fraction_numerical': 0.0753633400863208, 'mean_word_length': 5.4433598183881955, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 138, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '200469', 'n_tokens_mistral': 25400, 'n_tokens_neox': 22195, 'n_words': 3033}