/***************************************************************************
 *            mltrec.h
 *
 *  Sun May 23 19:05:36 2004
 *  Copyright  2004  Stanislav Brabec
 *  utx@penguin.cz
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef _MLTREC_H
#define _MLTREC_H

#include <stdint.h>
#include <usb.h>
#include <pthread.h>

#ifdef __cplusplus
extern "C"
{
#endif

/* mltusb.c */

struct mltusb_device;
struct mltusb_handle;

typedef enum
{
  MLTUSB_DEVICE_UNKNOWN = 0,
  MLTUSB_DEVICE_MASS_STORAGE = -1,
  MLTUSB_DEVICE_REMOTE = 1
} mltusb_device_type;

typedef enum
{
  MLTUSB_LOCATE_ALL = 0,
  MLTUSB_LOCATE_REMOTE = 1
} mltusb_locate_request;

typedef struct
{
  struct mltusb_device *usb_device;
  int device_type;
} mltusb_device_array;

mltusb_device_array *mltusb_find_devices (mltusb_locate_request request);

void mltrec_find_devices_free (mltusb_device_array * devices);

struct mltusb_device *mltusb_find_device (void);

mltusb_device_type mltusb_check_device_type (struct mltusb_device *dev);

struct mltusb_handle *mltusb_open (struct mltusb_device *usbdev);

char *mltusb_unicode_to_ascii (const char *usb_unicode_filename, int minusculize);

/* mltprot.c */

typedef uint32_t mltrec_image_id;
/* FIXME: should be internal in future */
typedef uint8_t mltprot_header;

typedef mltrec_image_id mltrec_image_open_callback (const char
						    *usb_unicode_filename,
						    void *user_data);
typedef void mltrec_image_write_callback (mltrec_image_id image_id,
					  const char *buffer, int buffer_size,
					  void *user_data);
typedef void mltrec_image_close_callback (mltrec_image_id image_id,
					  void *user_data);
typedef void mltrec_thumb_write_callback (const char *buffer, int buffer_size,
					 void *user_data);

struct mltprot_queue_item;
/* FIXME: Properly mark values as volatile */
/* FIXME for whole code: Use const, where appropriate. */
typedef struct
{
  struct mltusb_handle *usb_handle;
  uint32_t write_serial;
  /* FIXME: if firmware limitation will be removed, such simple solutions stops to work */
  uint32_t capture_serial;
  /* FIXME: Looks obsolete: We don't know it, but camera does not do confirm, if there anything to send. */
  int images_to_complete;
  /* WARNING for docs: You must take extreme care, if you want to
     change callback on fly. Other threads can still use it! */
  /* FIXME: stub prototype */
  void *complete_callback;
  void *complete_user_data;
  /* WARNING for docs: image_open is called with usb_mutex */
  mltrec_image_open_callback *image_open;
  mltrec_image_write_callback *image_write;
  mltrec_image_close_callback *image_close;
  void *image_user_data;
  mltrec_thumb_write_callback *live_callback;
  void *live_user_data;
  mltrec_thumb_write_callback *preview_callback;
  void *preview_user_data;
  /* threads */
  pthread_t read_thread;
  pthread_t write_thread;
  /* active command queue first element */
  /*(sent but not yet replied goes first) */
  struct mltprot_queue_item *command_queue_head;
  /* active command queue last element */
  struct mltprot_queue_item *command_queue_tail;
  /* active command first unsent */
  struct mltprot_queue_item *command_queue_unsent_head;
  /* condition for activation of read queue */
  pthread_cond_t usb_read_cond;
  /* condition for activation of write queue */
  pthread_cond_t usb_write_cond;
  /* mutex for active command queue */
  pthread_mutex_t queue_mutex;
  /* mutex for USB transfers */
  /* FIXME: Not sure, whether it is needed. Shoul be experimented once it will work. */
  pthread_mutex_t usb_mutex;
  /* write queue waiting for finishing command */
  uint16_t active_write_waiting_for;
  /* Request for thread cacellation. */
  char cancel;
  } mltrec_device;

/* FIXME: should be internal, but we need it here */
typedef void(*mltprot_complete_callback)(mltrec_device *mltdev, mltprot_header *hdr, void *user_data);

struct mltprot_queue_item
{
  struct mltprot_queue_item *next;
  uint8_t *data_to_send;
  /* FIXME: duplicate size to simplify porting? */
  uint32_t size;
  uint16_t command;
  uint32_t serial;
  mltprot_complete_callback complete_callback;
  void *user_data;
};

mltrec_device *mltrec_device_open (struct mltusb_device *usbdev);
int mltrec_device_close (mltrec_device * mltdev);

void mltrec_image_open_callback_set (mltrec_device * mltdev,
				     mltrec_image_open_callback *
				     image_write, void *user_data);
void mltrec_image_write_callback_set (mltrec_device * mltdev,
				      mltrec_image_write_callback *
				      image_write);
void mltrec_image_close_callback_set (mltrec_device * mltdev,
				      mltrec_image_close_callback *
				      image_close);
void mltrec_live_callback_set (mltrec_device * mltdev,
				     mltrec_thumb_write_callback * live_write,
				     void *user_data);
void mltrec_preview_callback_set (mltrec_device * mltdev,
				     mltrec_thumb_write_callback * preview_write,
				     void *user_data);

void mltrec_complete_all (mltrec_device * mltdev);

/* commands.c */

/* for MLTREC_SETTINGS_SET and MLTREC_SETTINGS_GET */
/* FIXME: Not sure whether GET and PUT has the same. GET are MLTSETG. */ 
#define MLTSET_EXP_MODE		0x00000000
  #define MLTVAL_EXP_MODE_P	0
  #define MLTVAL_EXP_MODE_A	1
  #define MLTVAL_EXP_MODE_S	2
  #define MLTVAL_EXP_MODE_M	3
  #define MLTVAL_EXP_MODE_UNKN4	4
#define MLTSET_FLASH_MODE	0x00000001
  #define MLTVAL_FLASH_MODE_FILL 0
  #define MLTVAL_FLASH_MODE_REDEYE 1
  #define MLTVAL_FLASH_MODE_REAR 2
  #define MLTVAL_FLASH_MODE_WIRELESS 3
#define MLTSET_WB_MODE		0x00000002
  /* FIXME: Later, see exifprobe patch - identical */
#define MLTSET_SIZE		0x00000003
  /* FIXME: HOWTO */
#define MLTSET_QUALITY		0x00000004
  #define MLTVAL_QUALITY_RAW	0
  #define MLTVAL_QUALITY_TIFF	1
  #define MLTVAL_QUALITY_FINE	2
  #define MLTVAL_QUALITY_STANDARD 3
  #define MLTVAL_QUALITY_ECONOMY 4
  #define MLTVAL_QUALITY_XFINE	5
/* FIXME: self timer is not reflected */
#define MLTSET_DRIVE		0x00000005
  #define MLTVAL_DRIVE_CONT	1
  #define MLTVAL_BRACK_S3	3
  #define MLTVAL_BRACK_C3	4
  #define MLTVAL_DRIVE_HI	8
  #define MLTVAL_BRACK_C3_CON	10

  /* FIXME: HOWTO */
#define MLTSET_METERING		0x00000006
  /* FIXME: Later, see exifprobe patch - identical (FIXME strange maxval) */
#define MLTSET_FILM_SPEED	0x00000007
  #define MLTVAL_FILM_SPEED_100	0
  #define MLTVAL_FILM_SPEED_200	1
  #define MLTVAL_FILM_SPEED_400	2
  #define MLTVAL_FILM_SPEED_800	3
  #define MLTVAL_FILM_SPEED_AUTO 4
#define MLTSET_SHUTTER		0x00000008
#define MLTSET_APERTURE		0x00000009
#define MLTSET_FOCUS_MODE	0x0000000a
  #define MLTVAL_FOCUS_MODE_AUTO 0
  #define MLTVAL_FOCUS_MODE_MANUAL 1
/* #define MLTSET_DIGIZOOM */
#define MLTSET_MACRO_MODE	0x0000000b

#define MLTSET_UNKNOWN12	0x0000000c
#define MLTSET_UNKNOWN13	0x0000000d
#define MLTSET_UNKNOWN14	0x0000000e

#define MLTSET_EXP_COMP		0x0000000f
  #define MLTCMP_EXP_COMP_x3(v)	(v-6)

#define MLTSET_INSTPLAY_MODE	0x00000010
/* 0=no, 2=2sec., 3=10sec. */
/* FIXME: Maybe also sets image destination (card, computer). */

#define MLTSET_BRACK_STEP	0x00000011
/* 0=1/3, 1=2/3, 2=1 ??? strange - I do not see any change */

#define MLTSET_UNKNOWN18	0x00000012
#define MLTSET_UNKNOWN19	0x00000013
#define MLTSET_UNKNOWN20	0x00000014

#define MLTSET_FOLDER_SERIAL	0x00000015
#define MLTSET_FILENUM_MEMORY	0x00000016

/* MLTSET_INTERVAL_..., FOCAL_LENGTH, FLASH_FIRED,
   DATE, MAX_APERTURE, FILE_NUBER_..., WB, SATURATION, CONTRAST, SHARPNESS, */
#define MLTSET_SUBJ_PROG	0x00000019
  /* FIXME: Later, see exifprobe patch - identical (FIXME what does text) */

#define MLTSET_FOCALDIST	0x0000001b
  /* FIXME: verify it (in mm) */

/* FLASH_COMP, ISO, CAMERA_MODEL, INTERVAL, FOLDER... */
#define MLTSET_COLORMODE	0x0000001d
  /* FIXME: Later, see exifprobe patch - identical (FIXME what does text) */

#define MLTSET_FLASH_COMP	0x0000001f
  #define MLTCMP_FLASH_COMP_x3(v) (v-6)
/* verified only R/O */
#define MLTSET_BATTERY_STATUS	0x00000025

/* FIXME: has soemthing to do with 3f */
#define MLTSET_3D_FOCUS		0x00000026

#define MLTSET_FLEXFP_XPOS	0x00000027
  /* In CCD coords */
/* verified only R/O */
#define MLTSET_FLEXFP_YPOS	0x00000028
  /* In CCD coords */
#define MLTSET_EFF_SAT		0x0000002e
#define MLTSET_EFF_CONTRAST	0x0000002f
#define MLTSET_MAX_APERTURE	0x00000030
#define MLTSET_FLASH_UP		0x00000034
/* Remaining frames in bracketing and interval capture. */
#define MLTSET_MULT_REMAINING	0x00000035
#define MLTSET_FLASH_METER	0x00000037
#define MLTSET_SHARPNESS	0x00000038

/* FIXME: has something to do with 3D focus and 26 - 3F both 1 - maybe focus error? */
#define MLTSET_FOCUS_EMODE	0x0000003f
/* Reversed value of full time AF */
#define MLTSET_FOCUS_ONCE	0x00000040

#define MLTSETG_UNKNOWN42	0x00000042
  /* Either bitfield or scene dependent */

#define MLTSET_FILE_NUM		0x00000044
#define MLTSET_FLASH_CHARGE	0x00000046
#define MLTSET_FOLDERNM_DATE	0x0000004c
#define MLTSET_EFF_FILTER	0x0000004d
#define MLTSET_EFF_HUE		0x0000004e
/* FIXME: what it is, maybe related with WB */
#define MLTSET_WB_UNKNOWN	0x00000053
/* FIXME: what is this: */
#define MLTSET_FLEX_SPOT_CENTER	0x00000055
/* Incomplete... */


#define MLTVAL_SIZE_1600x1200	1

#define MLTVAL_SIZE_2560x1920	0
#define MLTVAL_SIZE_640x480	3
#define MLTVAL_SIZE_UNKNOWN4	4
#define MLTVAL_SIZE_UNKNOWN5	5
#define MLTVAL_SIZE_UNKNOWN6	6

/* MLTREC_OPEN 0x1001 */
int mltrec_rec_open (mltrec_device * mltdev);

/* MLTREC_CLOSE_SLEEP 0x1002 */
int mltrec_rec_close (mltrec_device * mltdev);
int mltrec_rec_sleep (mltrec_device * mltdev, uint16_t seconds);

/* MLTREC_POWERSAVE 0x1003 */
int mltrec_powersave (mltrec_device * mltdev);

/* MLTREC_UNKNOWN_1004 0x1004 */
int mltrec_unknown1004 (mltrec_device * mltdev);

/* MLTREC_LOCK_AE_AF 0x1005 */
int mltrec_lock_ae_af (mltrec_device * mltdev);
int mltrec_unlock_ae_af (mltrec_device * mltdev);

/* MLTREC_CAPTURE_START 0x1006 */
int
mltrec_capture_start (mltrec_device * mltdev, uint32_t drive,
		      uint32_t size, uint32_t quality, uint32_t unknown);

/* MLTREC_CAPTURE_STOP 0x1007 */
int mltrec_capture_stop (mltrec_device * mltdev);

/* MLTREC_REMOTE_START 0x1008 */
int mltrec_remote_start (mltrec_device * mltdev);

/* MLTREC_REMOTE_STOP 0x1009 */
int mltrec_remote_stop (mltrec_device * mltdev);

/* MLTREC_LIVE_GET 0x100a */
int mltrec_live_get (mltrec_device * mltdev);

/* MLTREC_UNKNOWN_100B 0x100b */

/* MLTREC_SETTINGS_SET 0x100c */
int mltrec_settings_set (mltrec_device * mltdev, uint32_t val1, uint32_t val2);

/* MLTREC_SETTINGS_GET 0x100e */
int mltrec_settings_get (mltrec_device * mltdev);

/* MLTREC_FLEXMAG_TOGGLE 0x101e */
int mltrec_flexmag_toggle (mltrec_device * mltdev);

/* MLTREC_FOCUS_SET 0x1020 */
int mltrec_focus_set (mltrec_device * mltdev, int focus);

/* MLTREC_INSTPLAY_CONFIRM 0x1021 */
int mltrec_instplay_confirm (mltrec_device * mltdev, uint16_t confirm,
		     uint16_t unknown);

/* MLTREC_FLEXFOCUS_MODE 0x1025 */
int mltrec_flexfocus_mode (mltrec_device * mltdev, int flexmode);

/* MLTREC_FLEXFOCUS_POS 0x1026 */
int mltrec_flexfocus_pos (mltrec_device * mltdev, uint16_t pos1, uint16_t pos2,
		      uint16_t pos3, uint16_t pos4);

/* MLTREC_FLEX_AESPOT 0x1027 */
int mltrec_flex_aespot (mltrec_device * mltdev, uint16_t unknown);

/* MLTREC_CLOCK_SET 0x1028 */
int mltrec_clock_set (mltrec_device * mltdev, uint16_t year, uint8_t month,
		  uint8_t day, uint8_t hour, uint8_t minute,
		  uint8_t second, uint8_t tick);

/* MLTREC_REMOTE_START2 0x1029 */
int mltrec_remote_start2 (mltrec_device * mltdev);

/* MLTREC_WB_MODE 0x102a */
int mltrec_wb_mode (mltrec_device * mltdev, uint16_t unknown1, uint16_t unknown2);

/* MLTREC_PREVIEW_GET 0x102b */
int mltrec_preview_get (mltrec_device * mltdev);

/* MLTREC_WB_POINT 0x102c */
int mltrec_wb_point (mltrec_device * mltdev, uint16_t unknown1,
		 uint16_t unknown2, uint16_t unknown3, uint16_t unknown4);

/* MLTREC_FLEXMAG_POS 0x102d */
int mltrec_flexmag_pos (mltrec_device * mltdev, uint16_t unknown1,
		    uint16_t unknown2, uint16_t unknown3, uint16_t unknown4);

/* MLTREC_INTERVAL_CTL 0x102e */
int mltrec_interval_start (mltrec_device * mltdev, uint16_t unknown);
int mltrec_interval_stop (mltrec_device * mltdev, uint16_t unknown);

/* MLTREC_UNKNOWN_1100 0x1100 */

/* fallbacks.c */

mltrec_image_id
mltrec_default_image_open (const char *usb_unicode_filename,
			    void *user_data);
void
mltrec_default_image_write (mltrec_image_id image_id,
			     const char *buffer, int buffer_size,
			     void *user_data);
void
mltrec_default_image_close (mltrec_image_id image_id,
					  void *user_data);
void
mltrec_default_live (const char *buffer, int buffer_size,
			     void *user_data);
void
mltrec_default_preview (const char *buffer, int buffer_size,
			     void *user_data);

/* FIXME: move elsewhere */
/* FIXME: Requires GNU C. Workaround is to replace DBG1("str", arg) by DBG1(("str", arg)) */
#define DBG0(arg...) { printf (arg); fflush (stdout); }
//#define DBG0(arg...) {}
#define DBG1(arg...) { printf (arg); fflush (stdout); }
//#define DBG1(arg...) {}
#define DBG2(arg...) { printf (arg); fflush (stdout); }
//#define DBG2(arg...) {}
#define DBG3(arg...) { printf (arg); fflush (stdout); }
//#define DBG3(arg...) {}
#define DBG4(arg...) { printf (arg); fflush (stdout); }
//#define DBG4(arg...) {}


#ifdef __cplusplus
}
#endif

#endif				/* _MLTREC_H */

