models[]. s/_LIBRARY_H/_CANON_H/. git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@3516 67ed7778-7388-44ab-90cf-0a291f65f57c
1453 lines
37 KiB
C
1453 lines
37 KiB
C
/***************************************************************************
|
|
*
|
|
* library.c
|
|
*
|
|
* Canon Camera library for the gphoto project,
|
|
* (c) 1999 Wolfgang G. Reissnegger
|
|
* Developed for the Canon PowerShot A50
|
|
* Additions for PowerShot A5 by Ole W. Saastad
|
|
* (c) 2000: Other additions by Edouard Lafargue, Philippe Marzouk
|
|
*
|
|
* This file contains all the "glue code" required to use the canon
|
|
* driver with libgphoto2.
|
|
*
|
|
* $Id$
|
|
****************************************************************************/
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* include files
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <termios.h>
|
|
#include <time.h>
|
|
//#include <ctype.h>
|
|
|
|
#include <gphoto2.h>
|
|
|
|
#ifdef ENABLE_NLS
|
|
# include <libintl.h>
|
|
# undef _
|
|
# define _(String) dgettext (PACKAGE, String)
|
|
# ifdef gettext_noop
|
|
# define N_(String) gettext_noop (String)
|
|
# else
|
|
# define N_(String) (String)
|
|
# endif
|
|
#else
|
|
# define textdomain(String) (String)
|
|
# define gettext(String) (String)
|
|
# define dgettext(Domain,Message) (Message)
|
|
# define dcgettext(Domain,Message,Type) (Message)
|
|
# define bindtextdomain(Domain,Directory) (Domain)
|
|
# define _(String) (String)
|
|
# define N_(String) (String)
|
|
#endif
|
|
|
|
#include "util.h"
|
|
#include "library.h"
|
|
#include "canon.h"
|
|
#include "serial.h"
|
|
#include "usb.h"
|
|
|
|
#ifndef HAVE_SNPRINTF
|
|
#warning You do not seem to have a snprintf() function. Using sprintf instead.
|
|
#warning Note that this leads to SECURITY RISKS!
|
|
#define snprintf(buf,size,format,arg) sprintf(buf,format,arg)
|
|
#endif
|
|
|
|
int
|
|
camera_id (CameraText *id)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_id()");
|
|
|
|
strcpy (id->text, "canon");
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
camera_manual (Camera *camera, CameraText *manual)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_manual()");
|
|
|
|
strcpy (manual->text, _("For the A50, 115200 may not be faster than 57600\n"
|
|
"Folders are NOT supported\n"
|
|
"if you experience a lot of transmissions errors,"
|
|
" try to have you computer as idle as possible (ie: no disk activity)"));
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
camera_abilities (CameraAbilitiesList *list)
|
|
{
|
|
int i;
|
|
CameraAbilities a;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_abilities()");
|
|
|
|
for (i = 0; models[i].name; i++) {
|
|
a.status = GP_DRIVER_STATUS_PRODUCTION;
|
|
strcpy (a.model, models[i].name);
|
|
a.port = 0;
|
|
if (models[i].idProduct) {
|
|
a.port |= GP_PORT_USB;
|
|
a.usb_vendor = models[i].idVendor;
|
|
a.usb_product = models[i].idProduct;
|
|
}
|
|
if (models[i].serial) {
|
|
a.port |= GP_PORT_SERIAL;
|
|
a.speed[0] = 9600;
|
|
a.speed[1] = 19200;
|
|
a.speed[2] = 38400;
|
|
a.speed[3] = 57600;
|
|
a.speed[4] = 115200;
|
|
a.speed[5] = 0;
|
|
}
|
|
a.operations = GP_OPERATION_CONFIG;
|
|
a.folder_operations = GP_FOLDER_OPERATION_PUT_FILE |
|
|
GP_FOLDER_OPERATION_MAKE_DIR | GP_FOLDER_OPERATION_REMOVE_DIR;
|
|
a.file_operations = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_PREVIEW;
|
|
gp_abilities_list_append (list, a);
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
void
|
|
clear_readiness (Camera *camera)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "clear_readiness()");
|
|
|
|
camera->pl->cached_ready = 0;
|
|
}
|
|
|
|
static int
|
|
check_readiness (Camera *camera)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "check_readiness() cached_ready == %i",
|
|
camera->pl->cached_ready);
|
|
|
|
if (camera->pl->cached_ready)
|
|
return 1;
|
|
if (canon_int_ready (camera) == GP_OK) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "Camera type: %d\n",
|
|
camera->pl->model);
|
|
camera->pl->cached_ready = 1;
|
|
return 1;
|
|
}
|
|
gp_camera_status (camera, _("Camera unavailable"));
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
canon_int_switch_camera_off (Camera *camera)
|
|
{
|
|
GP_DEBUG ("switch_camera_off()");
|
|
|
|
switch (camera->port->type) {
|
|
case GP_PORT_SERIAL:
|
|
gp_camera_status (camera, _("Switching Camera Off"));
|
|
canon_serial_off (camera);
|
|
break;
|
|
case GP_PORT_USB:
|
|
GP_DEBUG ("Not trying to shut down USB camera...");
|
|
break;
|
|
case GP_PORT_NONE:
|
|
default:
|
|
GP_DEBUG ("Unknown camera->port->type in canon_int_switch_camera_off()");
|
|
}
|
|
clear_readiness (camera);
|
|
}
|
|
|
|
static int
|
|
camera_exit (Camera *camera)
|
|
{
|
|
if (camera->port->type == GP_PORT_USB) {
|
|
canon_usb_unlock_keys (camera);
|
|
}
|
|
|
|
if (camera->pl) {
|
|
canon_int_switch_camera_off (camera);
|
|
free (camera->pl);
|
|
camera->pl = NULL;
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
canon_get_batt_status (Camera *camera, int *pwr_status, int *pwr_source)
|
|
{
|
|
GP_DEBUG ("canon_get_batt_status() called");
|
|
|
|
if (!check_readiness (camera))
|
|
return -1;
|
|
|
|
return canon_int_get_battery (camera, pwr_status, pwr_source);
|
|
}
|
|
|
|
static int
|
|
update_disk_cache (Camera *camera)
|
|
{
|
|
char root[10]; /* D:\ or such */
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "update_disk_cache()");
|
|
|
|
if (camera->pl->cached_disk)
|
|
return 1;
|
|
if (!check_readiness (camera))
|
|
return 0;
|
|
camera->pl->cached_drive = canon_int_get_disk_name (camera);
|
|
if (!camera->pl->cached_drive) {
|
|
gp_camera_status (camera, _("No response"));
|
|
return 0;
|
|
}
|
|
snprintf (root, sizeof (root), "%s\\", camera->pl->cached_drive);
|
|
if (canon_int_get_disk_name_info (camera, root,
|
|
&camera->pl->cached_capacity,
|
|
&camera->pl->cached_available) != GP_OK) {
|
|
gp_camera_status (camera, _("No response"));
|
|
return 0;
|
|
}
|
|
camera->pl->cached_disk = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* This function is only used by A5 */
|
|
|
|
static int
|
|
recurse (Camera *camera, const char *name)
|
|
{
|
|
struct canon_dir *dir, *walk;
|
|
char buffer[300]; /* longest path, etc. */
|
|
int count, curr, res;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "recurse() name '%s'", name);
|
|
|
|
res = canon_int_list_directory (camera, &dir, name);
|
|
if (res != GP_OK)
|
|
return res;
|
|
|
|
if (dir == NULL)
|
|
return 1;
|
|
|
|
count = 0;
|
|
for (walk = dir; walk->name; walk++)
|
|
if (walk->size && (is_image (walk->name) || is_movie (walk->name)))
|
|
count++;
|
|
camera->pl->cached_paths =
|
|
realloc (camera->pl->cached_paths,
|
|
sizeof (char *) * (camera->pl->cached_images + count + 1));
|
|
memset (camera->pl->cached_paths + camera->pl->cached_images + 1, 0,
|
|
sizeof (char *) * count);
|
|
if (!camera->pl->cached_paths) {
|
|
perror ("realloc");
|
|
return 0;
|
|
}
|
|
curr = camera->pl->cached_images;
|
|
camera->pl->cached_images += count;
|
|
for (walk = dir; walk->name; walk++) {
|
|
sprintf (buffer, "%s\\%s", name, walk->name);
|
|
if (!walk->size) {
|
|
if (!recurse (camera, buffer))
|
|
return 0;
|
|
} else {
|
|
if ((!is_image (walk->name)) && (!is_movie (walk->name)))
|
|
continue;
|
|
curr++;
|
|
camera->pl->cached_paths[curr] = strdup (buffer);
|
|
if (!camera->pl->cached_paths[curr]) {
|
|
perror ("strdup");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
free (dir);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/* This function is only used by A50 */
|
|
|
|
static struct canon_dir *
|
|
dir_tree (Camera *camera, const char *path)
|
|
{
|
|
struct canon_dir *dir, *walk;
|
|
char buffer[300]; /* longest path, etc. */
|
|
int res;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "dir_tree() path '%s'", path);
|
|
|
|
res = canon_int_list_directory (camera, &dir, path);
|
|
if (res != GP_OK)
|
|
return NULL;
|
|
|
|
if (dir == NULL)
|
|
return NULL; /* assume it's empty @@@ */
|
|
for (walk = dir; walk->name; walk++) {
|
|
if (walk->is_file) {
|
|
if (is_image (walk->name) || is_movie (walk->name)
|
|
|| is_thumbnail (walk->name))
|
|
camera->pl->cached_images++;
|
|
} else {
|
|
sprintf (buffer, "%s\\%s", path, walk->name);
|
|
walk->user = dir_tree (camera, buffer);
|
|
}
|
|
}
|
|
qsort (dir, walk - dir, sizeof (*dir), comp_dir);
|
|
return dir;
|
|
}
|
|
|
|
|
|
static void
|
|
clear_dir_cache (Camera *camera)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "clear_dir_cache()");
|
|
|
|
canon_int_free_dir (camera, camera->pl->cached_tree);
|
|
}
|
|
|
|
|
|
/* A5 only: sort THB_ and AUT_ into their proper arrangement. */
|
|
static int
|
|
compare_a5_paths (const void *p1, const void *p2)
|
|
{
|
|
const char *s1 = *((const char **) p1);
|
|
const char *s2 = *((const char **) p2);
|
|
const char *ptr, *base1, *base2;
|
|
int n1 = 0, n2 = 0;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "compare_a5_paths()");
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("Comparing %s to %s\n"), s1, s2);
|
|
|
|
ptr = strrchr (s1, '_');
|
|
if (ptr)
|
|
n1 = strtol (ptr + 1, 0, 10);
|
|
ptr = strrchr (s2, '_');
|
|
if (ptr)
|
|
n2 = strtol (ptr + 1, 0, 10);
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("Numbers are %d and %d\n"), n1, n2);
|
|
|
|
if (n1 < n2)
|
|
return -1;
|
|
else if (n1 > n2)
|
|
return 1;
|
|
else {
|
|
base1 = strrchr (s1, '\\');
|
|
base2 = strrchr (s2, '\\');
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("Base 1 is %s and base 2 is %s\n"),
|
|
base1, base2);
|
|
return strcmp (base1, base2);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
update_dir_cache (Camera *camera)
|
|
{
|
|
int i;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "update_dir_cache() "
|
|
"cached_dir = %i", camera->pl->cached_dir);
|
|
|
|
if (camera->pl->cached_dir)
|
|
return 1;
|
|
if (!update_disk_cache (camera))
|
|
return 0;
|
|
if (!check_readiness (camera))
|
|
return 0;
|
|
camera->pl->cached_images = 0;
|
|
switch (camera->pl->model) {
|
|
case CANON_PS_A5:
|
|
case CANON_PS_A5_ZOOM:
|
|
if (recurse (camera, camera->pl->cached_drive)) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("Before sort:\n"));
|
|
for (i = 1; i < camera->pl->cached_images; i++) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "%d: %s\n", i,
|
|
camera->pl->cached_paths[i]);
|
|
}
|
|
qsort (camera->pl->cached_paths + 1, camera->pl->cached_images,
|
|
sizeof (char *), compare_a5_paths);
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("After sort:\n"));
|
|
for (i = 1; i < camera->pl->cached_images; i++) {
|
|
printf ("%d: %s\n", i, camera->pl->cached_paths[i]);
|
|
}
|
|
camera->pl->cached_dir = 1;
|
|
return 1;
|
|
}
|
|
clear_dir_cache (camera);
|
|
return 0;
|
|
break;
|
|
|
|
default: /* A50 or S10 or other */
|
|
camera->pl->cached_tree = dir_tree (camera, camera->pl->cached_drive);
|
|
if (!camera->pl->cached_tree)
|
|
return 0;
|
|
camera->pl->cached_dir = 1;
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
_canon_file_list (struct canon_dir *tree, const char *folder, CameraList *list)
|
|
{
|
|
|
|
if (!tree) {
|
|
return GP_ERROR;
|
|
}
|
|
|
|
while (tree->name) {
|
|
if (is_image (tree->name) || is_movie (tree->name)) {
|
|
gp_list_append (list, (char *) tree->name, NULL);
|
|
} else if (!tree->is_file) {
|
|
_canon_file_list (tree->user, folder, list);
|
|
}
|
|
tree++;
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
canon_file_list (Camera *camera, const char *folder, CameraList *list)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "canon_file_list()");
|
|
|
|
if (!update_dir_cache (camera)) {
|
|
gp_camera_status (camera, _("Could not obtain directory listing"));
|
|
return GP_ERROR;
|
|
}
|
|
|
|
_canon_file_list (camera->pl->cached_tree, folder, list);
|
|
return GP_OK;
|
|
}
|
|
|
|
|
|
static int
|
|
file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, void *data)
|
|
{
|
|
Camera *camera = data;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_file_list()");
|
|
|
|
return canon_file_list (camera, folder, list);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* gphoto library interface calls
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int
|
|
canon_get_picture (Camera *camera, char *filename, char *path, int thumbnail,
|
|
unsigned char **data, int *size)
|
|
{
|
|
unsigned char attribs;
|
|
char complete_filename[300];
|
|
int res;
|
|
|
|
GP_DEBUG ("canon_get_picture()");
|
|
|
|
if (!check_readiness (camera)) {
|
|
return GP_ERROR;
|
|
}
|
|
switch (camera->pl->model) {
|
|
case CANON_PS_A5:
|
|
case CANON_PS_A5_ZOOM:
|
|
#if 0
|
|
picture_number = picture_number * 2 - 1;
|
|
if (thumbnail)
|
|
picture_number += 1;
|
|
GP_DEBUG ("Picture number %i", picture_number);
|
|
|
|
if (!picture_number || picture_number > cached_images) {
|
|
gp_camera_status (camera, _("Invalid index"));
|
|
return GP_ERROR;
|
|
}
|
|
gp_camera_status (camera, cached_paths[picture_number]);
|
|
if (!check_readiness (camera)) {
|
|
return GP_ERROR;
|
|
}
|
|
res = canon_int_get_file (cached_paths[picture_number], size);
|
|
if (res != GP_OK)
|
|
return res;
|
|
#else
|
|
GP_DEBUG ("canon_get_picture: downloading "
|
|
"pictures disabled for cameras: PowerShot A5, "
|
|
"PowerShot A5 ZOOM");
|
|
|
|
return GP_ERROR_NOT_SUPPORTED;
|
|
#endif /* 0 */
|
|
break;
|
|
default:
|
|
/* For A50 or others */
|
|
/* clear_readiness(); */
|
|
if (!update_dir_cache (camera)) {
|
|
gp_camera_status (camera,
|
|
_("Could not obtain directory listing"));
|
|
return GP_ERROR;
|
|
}
|
|
|
|
/* strip trailing backslash on path, if any */
|
|
if (path[strlen (path) - 1] == '\\')
|
|
path[strlen (path) - 1] = 0;
|
|
|
|
snprintf (complete_filename, sizeof (complete_filename), "%s\\%s",
|
|
path, filename);
|
|
|
|
GP_DEBUG ("canon_get_picture: path='%s', file='%s'\n\tcomplete filename='%s'\n", path, filename, complete_filename);
|
|
attribs = 0;
|
|
if (!check_readiness (camera)) {
|
|
return GP_ERROR;
|
|
}
|
|
if (thumbnail) {
|
|
/* The thumbnail of a movie in on a file called MVI_XXXX.THM
|
|
* we replace .AVI by .THM to download the thumbnail (jpeg format)
|
|
*/
|
|
if (is_movie (filename)) {
|
|
strcpy (complete_filename +
|
|
(strlen (complete_filename) - 3), "THM");
|
|
/* XXX check that this works */
|
|
GP_DEBUG ("canon_get_picture: movie thumbnail: %s\n",
|
|
complete_filename);
|
|
return canon_int_get_file (camera, complete_filename,
|
|
data, size);
|
|
} else {
|
|
*data = canon_int_get_thumbnail (camera,
|
|
complete_filename,
|
|
size);
|
|
if (*data)
|
|
return GP_OK;
|
|
else {
|
|
GP_DEBUG ("canon_get_picture: ",
|
|
"canon_int_get_thumbnail() '%s' %d failed!",
|
|
complete_filename, size);
|
|
return GP_ERROR;
|
|
}
|
|
}
|
|
} else {
|
|
res = canon_int_get_file (camera, complete_filename, data,
|
|
size);
|
|
if (res != GP_OK) {
|
|
GP_DEBUG ("canon_get_picture: "
|
|
"canon_int_get_file() failed! returned %i",
|
|
res);
|
|
return res;
|
|
}
|
|
|
|
GP_DEBUG ("canon_get_picture: We now have to set the \"downloaded\" " "flag on the picture");
|
|
/* XXX this is bogus, attrib is not fetched - it is always set to 0 above */
|
|
GP_DEBUG ("canon_get_picture: The old file attributes were: %#x\n", attribs);
|
|
attribs &= ~CANON_ATTR_DOWNLOADED;
|
|
res = canon_int_set_file_attributes (camera, filename, path,
|
|
attribs);
|
|
if (res != GP_OK) {
|
|
/* warn but continue since we allready have the downloaded picture */
|
|
GP_DEBUG ("canon_get_picture: "
|
|
"WARNING: canon_int_set_file_attributes on "
|
|
"'%s' '%s' to 0x%x failed! returned %d.",
|
|
path, filename, attribs, res);
|
|
}
|
|
}
|
|
return GP_OK;
|
|
break;
|
|
}
|
|
/* NOT REACHED */
|
|
return GP_ERROR;
|
|
}
|
|
|
|
/**
|
|
* _get_file_path:
|
|
* @camera: a #Camera to work with
|
|
* @canon_dir: seems to be a reference to the current
|
|
* @filename: seems to be the file name to look for
|
|
* @path: returns (?!) the full path to the file given by @filename
|
|
*
|
|
* _get_file_path seems to find a given filename anywhere in the
|
|
* directory tree and returns the complete path to the file in @path.
|
|
*
|
|
* _get_file_path is an internal function and is only called from #get_file_path.
|
|
*
|
|
* This function recursively looks for @filename in @tree and returns a concatenated
|
|
* @path if the filename is found somewhere in @tree.
|
|
*
|
|
* Return value: a gphoto2 error code.
|
|
**/
|
|
int
|
|
_get_file_path (Camera *camera, struct canon_dir *tree, const char *filename, char *path,
|
|
int recursively_entered)
|
|
{
|
|
static char newpath[1024];
|
|
char *temp_ch;
|
|
|
|
GP_DEBUG ("_get_file_path() called: filename '%s' path '%s' recurs %i", filename, path,
|
|
recursively_entered);
|
|
|
|
if (tree == NULL)
|
|
return GP_ERROR;
|
|
|
|
/* initiate newpath if we are not recursively entered */
|
|
if (!recursively_entered)
|
|
strcpy (newpath, path);
|
|
|
|
/* add trailing backslash if missing */
|
|
if (newpath[strlen (newpath) - 1] != '\\')
|
|
strcat (newpath, "\\");
|
|
|
|
while (tree->name) {
|
|
if (strcmp (tree->name, filename) == 0 &&
|
|
(is_image (tree->name) || is_movie (tree->name) ||
|
|
is_thumbnail (tree->name))) {
|
|
/* we've got a match! */
|
|
GP_DEBUG ("_get_file_path() returns with "
|
|
"filename '%s' path '%s'", filename, path);
|
|
if (!recursively_entered)
|
|
strcpy (path, newpath);
|
|
return GP_OK;
|
|
}
|
|
if (!tree->is_file) {
|
|
/* remember where newpath ends */
|
|
temp_ch = strrchr (newpath, 0);
|
|
|
|
/* not a file, must be a directory. append name to newpath */
|
|
strncat (newpath, tree->name, sizeof (newpath) - strlen (newpath));
|
|
newpath[sizeof (newpath) - 1] = 0;
|
|
|
|
/* enter self recursively */
|
|
if (_get_file_path (camera, tree->user, filename, (char *) newpath, 1)
|
|
== GP_OK) {
|
|
/* file found somewhere underneath */
|
|
|
|
if (!recursively_entered)
|
|
strcpy (path, newpath);
|
|
|
|
return GP_OK;
|
|
}
|
|
/* back out appending of this tree->name to newpath
|
|
* since filename was not found in this newpath
|
|
*/
|
|
*temp_ch = 0;
|
|
}
|
|
tree++;
|
|
}
|
|
|
|
/* the requested file was not found */
|
|
|
|
return GP_ERROR;
|
|
}
|
|
|
|
static int
|
|
get_file_path (Camera *camera, const char *filename, char *path)
|
|
{
|
|
return _get_file_path (camera, camera->pl->cached_tree, filename, path, 0);
|
|
}
|
|
|
|
static int
|
|
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
|
|
CameraFileType type, CameraFile *file, void *user_data)
|
|
{
|
|
Camera *camera = user_data;
|
|
unsigned char *data = NULL;
|
|
int buflen, size, ret;
|
|
char path[300], tempfilename[300];
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_file_get() "
|
|
"folder '%s' filename '%s'", folder, filename);
|
|
|
|
if (check_readiness (camera) != 1)
|
|
return GP_ERROR;
|
|
|
|
strncpy (path, camera->pl->cached_drive, sizeof (path) - 1);
|
|
|
|
/* update file cache (if necessary) first */
|
|
if (!update_dir_cache (camera)) {
|
|
gp_camera_status (camera, _("Could not obtain directory listing"));
|
|
return GP_ERROR;
|
|
}
|
|
|
|
/* update_dir_cache() loads all file names into cache, now call
|
|
* get_file_path() to determine in which folder on flash the file
|
|
* is located
|
|
*/
|
|
if (get_file_path (camera, filename, path) == GP_ERROR) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_file_get: "
|
|
"Filename '%s' path '%s' not found!", filename, path);
|
|
return GP_ERROR;
|
|
}
|
|
|
|
gp_debug_printf (GP_DEBUG_HIGH, "canon", "camera_file_get: "
|
|
"Found picture, '%s' '%s'", path, filename);
|
|
|
|
switch (camera->pl->canon_comm_method) {
|
|
case CANON_USB:
|
|
/* add trailing backslash */
|
|
if (path[strlen (path) - 1] != '\\')
|
|
strncat (path, "\\", sizeof (path) - 1);
|
|
break;
|
|
case CANON_SERIAL_RS232:
|
|
default:
|
|
/* find rightmost \ in path */
|
|
if (strrchr (path, '\\') == NULL) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_file_get: "
|
|
"Could not determine directory part of path '%s'",
|
|
path);
|
|
return GP_ERROR;
|
|
}
|
|
/* truncate path after the last \ */
|
|
path[strrchr (path, '\\') - path + 1] = '\0';
|
|
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case GP_FILE_TYPE_NORMAL:
|
|
ret = canon_get_picture (camera, (char *) filename,
|
|
(char *) path, 0, &data, &buflen);
|
|
break;
|
|
case GP_FILE_TYPE_PREVIEW:
|
|
ret = canon_get_picture (camera, (char *) filename,
|
|
(char *) path, 1, &data, &buflen);
|
|
break;
|
|
default:
|
|
return (GP_ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
if (ret != GP_OK) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_file_get: "
|
|
"canon_get_picture() failed, returned %i", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* 256 is picked out of the blue, I figured no JPEG with EXIF header
|
|
* (not all canon cameras produces EXIF headers I think, but still)
|
|
* should be less than 256 bytes long.
|
|
*/
|
|
if (!data || buflen < 256)
|
|
return GP_ERROR;
|
|
|
|
switch (type) {
|
|
case GP_FILE_TYPE_PREVIEW:
|
|
/* we count the byte returned until the end of the jpeg data
|
|
which is FF D9 */
|
|
/* It would be prettier to get that info from the exif tags */
|
|
for (size = 1; size < buflen; size++)
|
|
if ((data[size - 1] == JPEG_ESC) && (data[size] == JPEG_END))
|
|
break;
|
|
buflen = size + 1;
|
|
gp_file_set_data_and_size (file, data, buflen);
|
|
gp_file_set_mime_type (file, GP_MIME_JPEG); /* always */
|
|
strcpy (tempfilename, filename);
|
|
strcat (tempfilename, "\0");
|
|
strcpy (tempfilename + strlen ("IMG_XXXX"), ".JPG\0");
|
|
gp_file_set_name (file, tempfilename);
|
|
break;
|
|
case GP_FILE_TYPE_NORMAL:
|
|
if (is_movie (filename))
|
|
gp_file_set_mime_type (file, GP_MIME_AVI);
|
|
else if (is_image (filename))
|
|
gp_file_set_mime_type (file, GP_MIME_JPEG);
|
|
/* else if (is_crw (filename))
|
|
* gp_file_set_mime_type (file, GP_MIME_CRW);
|
|
*/
|
|
else
|
|
gp_file_set_mime_type (file, GP_MIME_UNKNOWN);
|
|
gp_file_set_data_and_size (file, data, buflen);
|
|
gp_file_set_name (file, filename);
|
|
break;
|
|
default:
|
|
return (GP_ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
static void
|
|
pretty_number (int number, char *buffer)
|
|
{
|
|
int len, tmp, digits;
|
|
char *pos;
|
|
|
|
len = 0;
|
|
tmp = number;
|
|
do {
|
|
len++;
|
|
tmp /= 10;
|
|
}
|
|
while (tmp);
|
|
len += (len - 1) / 3;
|
|
pos = buffer + len;
|
|
*pos = 0;
|
|
digits = 0;
|
|
do {
|
|
*--pos = (number % 10) + '0';
|
|
number /= 10;
|
|
if (++digits == 3) {
|
|
*--pos = '\'';
|
|
digits = 0;
|
|
}
|
|
}
|
|
while (number);
|
|
}
|
|
|
|
static int
|
|
camera_summary (Camera *camera, CameraText *summary)
|
|
{
|
|
char a[20], b[20];
|
|
char *model;
|
|
int pwr_source, pwr_status;
|
|
char power_stats[48], cde[16];
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_summary()");
|
|
|
|
if (check_readiness (camera) != 1)
|
|
return GP_ERROR;
|
|
|
|
/*clear_readiness(); */
|
|
if (!update_disk_cache (camera))
|
|
return GP_ERROR;
|
|
|
|
pretty_number (camera->pl->cached_capacity, a);
|
|
pretty_number (camera->pl->cached_available, b);
|
|
|
|
model = "Canon PowerShot";
|
|
switch (camera->pl->model) {
|
|
case CANON_PS_A5:
|
|
model = "Canon PowerShot A5";
|
|
break;
|
|
case CANON_PS_A5_ZOOM:
|
|
model = "Canon PowerShot A5 Zoom";
|
|
break;
|
|
case CANON_PS_A50:
|
|
model = "Canon PowerShot A50";
|
|
break;
|
|
case CANON_PS_A70:
|
|
model = "Canon PowerShot A70";
|
|
break;
|
|
case CANON_PS_S10:
|
|
model = "Canon PowerShot S10";
|
|
break;
|
|
case CANON_PS_S20:
|
|
model = "Canon PowerShot S20";
|
|
break;
|
|
case CANON_PS_S30:
|
|
model = "Canon PowerShot S30";
|
|
break;
|
|
case CANON_PS_S40:
|
|
model = "Canon PowerShot S40";
|
|
break;
|
|
case CANON_PS_G1:
|
|
model = "Canon PowerShot G1";
|
|
break;
|
|
case CANON_PS_G2:
|
|
model = "Canon PowerShot G2";
|
|
break;
|
|
case CANON_PS_S100:
|
|
model = "Canon PowerShot S100 / Digital IXUS / IXY DIGITAL";
|
|
break;
|
|
case CANON_PS_S300:
|
|
model = "Canon PowerShot S300 / Digital IXUS 300 / IXY DIGITAL 300";
|
|
break;
|
|
case CANON_PS_A10:
|
|
model = "Canon PowerShot A10";
|
|
break;
|
|
case CANON_PS_A20:
|
|
model = "Canon PowerShot A20";
|
|
break;
|
|
case CANON_EOS_D30:
|
|
model = "Canon EOS D30";
|
|
break;
|
|
case CANON_PS_PRO90_IS:
|
|
model = "Canon Pro90 IS";
|
|
break;
|
|
}
|
|
|
|
canon_get_batt_status (camera, &pwr_status, &pwr_source);
|
|
if ((pwr_source & CAMERA_MASK_BATTERY) == 0) {
|
|
strcpy (power_stats, _("AC adapter "));
|
|
} else {
|
|
strcpy (power_stats, _("on battery "));
|
|
}
|
|
|
|
switch (pwr_status) {
|
|
case CAMERA_POWER_OK:
|
|
strcat (power_stats, _("(power OK)"));
|
|
break;
|
|
case CAMERA_POWER_BAD:
|
|
strcat (power_stats, _("(power low)"));
|
|
break;
|
|
default:
|
|
strcat (power_stats, cde);
|
|
sprintf (cde, " - %i)", pwr_status);
|
|
break;
|
|
}
|
|
|
|
sprintf (summary->text,
|
|
_("%s\n%s\n%s\nDrive %s\n%11s bytes total\n%11s bytes available\n"), model,
|
|
camera->pl->owner, power_stats, camera->pl->cached_drive, a, b);
|
|
return GP_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
camera_about (Camera *camera, CameraText *about)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_about()");
|
|
|
|
strcpy (about->text,
|
|
_("Canon PowerShot series driver by\n"
|
|
"Wolfgang G. Reissnegger,\n"
|
|
"Werner Almesberger,\n"
|
|
"Edouard Lafargue,\n"
|
|
"Philippe Marzouk,\n" "A5 additions by Ole W. Saastad\n" "Holger Klemm\n")
|
|
);
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
delete_file_func (CameraFilesystem *fs, const char *folder, const char *filename, void *data)
|
|
{
|
|
Camera *camera = data;
|
|
char path[300], thumbname[300];
|
|
|
|
GP_DEBUG ("delete_file_func() (previously known as camera_file_delete())");
|
|
|
|
// initialize memory to avoid problems later
|
|
memset (path, 0, sizeof (path));
|
|
memset (thumbname, 0, sizeof (thumbname));
|
|
|
|
if (check_readiness (camera) != 1)
|
|
return GP_ERROR;
|
|
|
|
if (camera->pl->model == CANON_PS_A5 || camera->pl->model == CANON_PS_A5_ZOOM) {
|
|
GP_DEBUG ("delete_file_func: deleting "
|
|
"pictures disabled for cameras: PowerShot A5, PowerShot A5 ZOOM");
|
|
|
|
return GP_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (!update_dir_cache (camera)) {
|
|
gp_camera_status (camera, _("Could not obtain directory listing"));
|
|
return GP_ERROR;
|
|
}
|
|
strcpy (path, camera->pl->cached_drive);
|
|
|
|
if (get_file_path (camera, filename, path) != GP_OK) {
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "Filename not found!\n");
|
|
return GP_ERROR;
|
|
}
|
|
|
|
/* strip trailing backslash on path, if any */
|
|
if (path[strlen (path) - 1] == '\\')
|
|
path[strlen (path) - 1] = 0;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "filename: %s\n path: %s\n", filename, path);
|
|
if (canon_int_delete_file (camera, filename, path) != GP_OK) {
|
|
gp_camera_set_error (camera, _("Error deleting file"));
|
|
return GP_ERROR;
|
|
}
|
|
|
|
/* If we have a movie, delete its thumbnail as well */
|
|
if (is_movie (filename)) {
|
|
strcpy (thumbname, filename);
|
|
strcpy (thumbname + strlen ("MVI_XXXX"), ".THM\0");
|
|
if (canon_int_delete_file (camera, thumbname, path) != GP_OK) {
|
|
gp_camera_set_error (camera, _("Error deleting movie thumbnail"));
|
|
return GP_ERROR;
|
|
}
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
_get_last_dir (Camera *camera, struct canon_dir *tree, char *path, char *temppath)
|
|
{
|
|
|
|
if (tree == NULL)
|
|
return GP_ERROR;
|
|
|
|
if (camera->pl->canon_comm_method != CANON_USB) {
|
|
path = strchr (path, 0);
|
|
*path = '\\';
|
|
}
|
|
|
|
while (tree->name) {
|
|
if (!is_image (tree->name) && !is_movie (tree->name)
|
|
&& !is_thumbnail (tree->name)) {
|
|
switch (camera->pl->canon_comm_method) {
|
|
case CANON_USB:
|
|
strcpy (path, tree->name);
|
|
break;
|
|
case CANON_SERIAL_RS232:
|
|
default:
|
|
strcpy (path + 1, tree->name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!tree->is_file) {
|
|
if ((strcmp (path + 4, "CANON") == 0) && (strcmp (temppath, path) < 0))
|
|
strcpy (temppath, path);
|
|
_get_last_dir (camera, tree->user, path, temppath);
|
|
}
|
|
tree++;
|
|
}
|
|
|
|
strcpy (path, temppath);
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
/*
|
|
* get from the cache the name of the highest numbered directory
|
|
*
|
|
*/
|
|
static int
|
|
get_last_dir (Camera *camera, char *path)
|
|
{
|
|
char temppath[300];
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "get_last_dir()");
|
|
|
|
strncpy (temppath, path, sizeof (temppath));
|
|
|
|
return _get_last_dir (camera, camera->pl->cached_tree, path, temppath);
|
|
}
|
|
|
|
static int
|
|
_get_last_picture (struct canon_dir *tree, char *directory, char *filename)
|
|
{
|
|
|
|
if (tree == NULL)
|
|
return GP_ERROR;
|
|
|
|
while (tree->name) {
|
|
|
|
if (is_image (tree->name) || is_movie (tree->name)
|
|
|| is_thumbnail (tree->name)) {
|
|
if (strcmp (tree->name, filename) > 0)
|
|
strcpy (filename, tree->name);
|
|
}
|
|
|
|
if (!tree->is_file) {
|
|
if ((strcmp (tree->name, "DCIM") == 0)
|
|
|| (strcmp (tree->name, directory) == 0)) {
|
|
_get_last_picture (tree->user, directory, filename);
|
|
}
|
|
}
|
|
|
|
tree++;
|
|
}
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
/*
|
|
* get from the cache the name of the highest numbered picture
|
|
*
|
|
*/
|
|
static int
|
|
get_last_picture (Camera *camera, char *directory, char *filename)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "get_last_picture()");
|
|
|
|
return _get_last_picture (camera->pl->cached_tree, directory, filename);
|
|
}
|
|
|
|
|
|
static int
|
|
put_file_func (CameraFilesystem *fs, const char *folder, CameraFile *file, void *data)
|
|
{
|
|
Camera *camera = data;
|
|
char destpath[300], destname[300], dir[300], dcf_root_dir[10];
|
|
int j, dirnum = 0, r;
|
|
char buf[10];
|
|
CameraAbilities a;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_folder_put_file()");
|
|
|
|
if (check_readiness (camera) != 1)
|
|
return GP_ERROR;
|
|
|
|
gp_camera_get_abilities (camera, &a);
|
|
if (camera->pl->speed > 57600 &&
|
|
(!strcmp (a.model, "Canon PowerShot A50") ||
|
|
!strcmp (a.model, "Canon PowerShot Pro70"))) {
|
|
gp_camera_message (camera,
|
|
_
|
|
("Speeds greater than 57600 are not supported for uploading to this camera"));
|
|
return GP_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (!check_readiness (camera)) {
|
|
return GP_ERROR;
|
|
}
|
|
|
|
for (j = 0; j < sizeof (destpath); j++) {
|
|
destpath[j] = '\0';
|
|
dir[j] = '\0';
|
|
destname[j] = '\0';
|
|
}
|
|
|
|
if (!update_dir_cache (camera)) {
|
|
gp_camera_status (camera, _("Could not obtain directory listing"));
|
|
return GP_ERROR;
|
|
}
|
|
|
|
sprintf (dcf_root_dir, "%s\\DCIM", camera->pl->cached_drive);
|
|
|
|
if (get_last_dir (camera, dir) == GP_ERROR)
|
|
return GP_ERROR;
|
|
|
|
if (strlen (dir) == 0) {
|
|
sprintf (dir, "\\100CANON");
|
|
sprintf (destname, "AUT_0001.JPG");
|
|
} else {
|
|
if (get_last_picture (camera, dir + 1, destname) == GP_ERROR)
|
|
return GP_ERROR;
|
|
|
|
if (strlen (destname) == 0) {
|
|
sprintf (destname, "AUT_%c%c01.JPG", dir[2], dir[3]);
|
|
} else {
|
|
sprintf (buf, "%c%c", destname[6], destname[7]);
|
|
j = 1;
|
|
j = atoi (buf);
|
|
if (j == 99) {
|
|
j = 1;
|
|
sprintf (buf, "%c%c%c", dir[1], dir[2], dir[3]);
|
|
dirnum = atoi (buf);
|
|
if (dirnum == 999) {
|
|
gp_camera_message (camera,
|
|
_
|
|
("Could not upload, no free folder name available!\n"
|
|
"999CANON folder name exists and has an AUT_9999.JPG picture in it."));
|
|
return GP_ERROR;
|
|
} else {
|
|
dirnum++;
|
|
sprintf (dir, "\\%03iCANON", dirnum);
|
|
}
|
|
} else
|
|
j++;
|
|
|
|
sprintf (destname, "AUT_%c%c%02i.JPG", dir[2], dir[3], j);
|
|
}
|
|
|
|
sprintf (destpath, "%s%s", dcf_root_dir, dir);
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "destpath: %s destname: %s\n",
|
|
destpath, destname);
|
|
}
|
|
|
|
r = canon_int_directory_operations (camera, dcf_root_dir, DIR_CREATE);
|
|
if (r < 0) {
|
|
gp_camera_message (camera, "could not create \\DCIM directory");
|
|
return (r);
|
|
}
|
|
|
|
r = canon_int_directory_operations (camera, destpath, DIR_CREATE);
|
|
if (r < 0) {
|
|
gp_camera_message (camera, "could not create destination directory");
|
|
return (r);
|
|
}
|
|
|
|
|
|
j = strlen (destpath);
|
|
destpath[j] = '\\';
|
|
destpath[j + 1] = '\0';
|
|
|
|
clear_readiness (camera);
|
|
|
|
return canon_int_put_file (camera, file, destname, destpath);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
camera_get_config (Camera *camera, CameraWidget **window)
|
|
{
|
|
CameraWidget *t, *section;
|
|
char power_stats[48], firm[64];
|
|
int pwr_status, pwr_source;
|
|
struct tm *camtm;
|
|
time_t camtime;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_get_config()");
|
|
|
|
gp_widget_new (GP_WIDGET_WINDOW, "Canon PowerShot Configuration", window);
|
|
|
|
gp_widget_new (GP_WIDGET_SECTION, _("Configure"), §ion);
|
|
gp_widget_append (*window, section);
|
|
|
|
gp_widget_new (GP_WIDGET_TEXT, _("Camera Model"), &t);
|
|
gp_widget_set_value (t, camera->pl->ident);
|
|
gp_widget_append (section, t);
|
|
|
|
gp_widget_new (GP_WIDGET_TEXT, _("Owner name"), &t);
|
|
gp_widget_set_value (t, camera->pl->owner);
|
|
gp_widget_append (section, t);
|
|
|
|
gp_widget_new (GP_WIDGET_TEXT, "date", &t);
|
|
if (camera->pl->cached_ready == 1) {
|
|
camtime = canon_int_get_time (camera);
|
|
if (camtime != GP_ERROR) {
|
|
camtm = gmtime (&camtime);
|
|
gp_widget_set_value (t, asctime (camtm));
|
|
} else
|
|
gp_widget_set_value (t, _("Error"));
|
|
} else
|
|
gp_widget_set_value (t, _("Unavailable"));
|
|
gp_widget_append (section, t);
|
|
|
|
gp_widget_new (GP_WIDGET_TOGGLE, _("Set camera date to PC date"), &t);
|
|
gp_widget_append (section, t);
|
|
|
|
gp_widget_new (GP_WIDGET_TEXT, _("Firmware revision"), &t);
|
|
sprintf (firm, "%i.%i.%i.%i", camera->pl->firmwrev[3],
|
|
camera->pl->firmwrev[2], camera->pl->firmwrev[1], camera->pl->firmwrev[0]);
|
|
gp_widget_set_value (t, firm);
|
|
gp_widget_append (section, t);
|
|
|
|
if (camera->pl->cached_ready == 1) {
|
|
canon_get_batt_status (camera, &pwr_status, &pwr_source);
|
|
if ((pwr_source & CAMERA_MASK_BATTERY) == 0) {
|
|
strcpy (power_stats, _("AC adapter "));
|
|
} else {
|
|
strcpy (power_stats, _("on battery "));
|
|
}
|
|
|
|
switch (pwr_status) {
|
|
char cde[16];
|
|
|
|
case CAMERA_POWER_OK:
|
|
strcat (power_stats, _("(power OK)"));
|
|
break;
|
|
case CAMERA_POWER_BAD:
|
|
strcat (power_stats, _("(power low)"));
|
|
break;
|
|
default:
|
|
strcat (power_stats, cde);
|
|
sprintf (cde, " - %i)", pwr_status);
|
|
break;
|
|
}
|
|
} else
|
|
strcpy (power_stats, _("Power: camera unavailable"));
|
|
|
|
gp_widget_new (GP_WIDGET_TEXT, _("Power"), &t);
|
|
gp_widget_set_value (t, power_stats);
|
|
gp_widget_append (section, t);
|
|
|
|
gp_widget_new (GP_WIDGET_SECTION, _("Debug"), §ion);
|
|
gp_widget_append (*window, section);
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
camera_set_config (Camera *camera, CameraWidget *window)
|
|
{
|
|
CameraWidget *w;
|
|
char *wvalue;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "camera_set_config()");
|
|
|
|
gp_widget_get_child_by_label (window, _("Owner name"), &w);
|
|
if (gp_widget_changed (w)) {
|
|
gp_widget_get_value (w, &wvalue);
|
|
if (!check_readiness (camera)) {
|
|
gp_camera_status (camera, _("Camera unavailable"));
|
|
} else {
|
|
if (canon_int_set_owner_name (camera, wvalue) == GP_OK)
|
|
gp_camera_status (camera, _("Owner name changed"));
|
|
else
|
|
gp_camera_status (camera, _("could not change owner name"));
|
|
}
|
|
}
|
|
|
|
gp_widget_get_child_by_label (window, _("Set camera date to PC date"), &w);
|
|
if (gp_widget_changed (w)) {
|
|
gp_widget_get_value (w, &wvalue);
|
|
if (!check_readiness (camera)) {
|
|
gp_camera_status (camera, _("Camera unavailable"));
|
|
} else {
|
|
if (canon_int_set_time (camera) == GP_OK) {
|
|
gp_camera_status (camera, _("time set"));
|
|
} else {
|
|
gp_camera_status (camera, _("could not set time"));
|
|
}
|
|
}
|
|
}
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", _("done configuring camera.\n"));
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
get_info_func (CameraFilesystem *fs, const char *folder, const char *filename,
|
|
CameraFileInfo * info, void *data)
|
|
{
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "canon get_info_func() "
|
|
"called for '%s'/'%s'", folder, filename);
|
|
|
|
info->preview.fields = GP_FILE_INFO_TYPE;
|
|
|
|
/* thumbnails are always jpeg on Canon Cameras */
|
|
strcpy (info->preview.type, GP_MIME_JPEG);
|
|
|
|
/* FIXME GP_FILE_INFO_PERMISSIONS to add */
|
|
info->file.fields = GP_FILE_INFO_NAME | GP_FILE_INFO_TYPE;
|
|
// | GP_FILE_INFO_PERMISSIONS | GP_FILE_INFO_SIZE;
|
|
//info->file.fields.permissions =
|
|
|
|
if (is_movie (filename))
|
|
strcpy (info->file.type, GP_MIME_AVI);
|
|
else if (is_image (filename))
|
|
strcpy (info->file.type, GP_MIME_JPEG);
|
|
else
|
|
/* May no be correct behaviour ... */
|
|
strcpy (info->file.type, "unknown");
|
|
|
|
strcpy (info->file.name, filename);
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
static int
|
|
make_dir_func (CameraFilesystem *fs, const char *folder, const char *name, void *data)
|
|
{
|
|
Camera *camera = data;
|
|
char path[2048];
|
|
int r;
|
|
|
|
strncpy (path, folder, sizeof (path));
|
|
if (strlen (folder) > 1)
|
|
strncat (path, "/", sizeof (path));
|
|
strncat (path, name, sizeof (path));
|
|
|
|
r = canon_int_directory_operations (camera, path, DIR_CREATE);
|
|
if (r < 0)
|
|
return (r);
|
|
|
|
return (GP_OK);
|
|
}
|
|
|
|
static int
|
|
remove_dir_func (CameraFilesystem *fs, const char *folder, const char *name, void *data)
|
|
{
|
|
Camera *camera = data;
|
|
char path[2048];
|
|
int r;
|
|
|
|
strncpy (path, folder, sizeof (path));
|
|
if (strlen (folder) > 1)
|
|
strncat (path, "/", sizeof (path));
|
|
strncat (path, name, sizeof (path));
|
|
|
|
r = canon_int_directory_operations (camera, path, DIR_REMOVE);
|
|
if (r < 0)
|
|
return (r);
|
|
|
|
return (GP_OK);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/**
|
|
* camera_init:
|
|
* @camera: the camera to initialize
|
|
*
|
|
* This routine initializes the serial/USB port and also load the
|
|
* camera settings. Right now it is only the speed that is
|
|
* saved.
|
|
**/
|
|
int
|
|
camera_init (Camera *camera)
|
|
{
|
|
GPPortSettings settings;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon", "canon camera_init()");
|
|
|
|
/* First, set up all the function pointers */
|
|
camera->functions->exit = camera_exit;
|
|
camera->functions->get_config = camera_get_config;
|
|
camera->functions->set_config = camera_set_config;
|
|
camera->functions->summary = camera_summary;
|
|
camera->functions->manual = camera_manual;
|
|
camera->functions->about = camera_about;
|
|
|
|
/* Set up the CameraFilesystem */
|
|
gp_filesystem_set_list_funcs (camera->fs, file_list_func, NULL, camera);
|
|
gp_filesystem_set_info_funcs (camera->fs, get_info_func, NULL, camera);
|
|
gp_filesystem_set_file_funcs (camera->fs, get_file_func, delete_file_func, camera);
|
|
gp_filesystem_set_folder_funcs (camera->fs, put_file_func, NULL,
|
|
make_dir_func, remove_dir_func, camera);
|
|
|
|
camera->pl = malloc (sizeof (CameraPrivateLibrary));
|
|
if (!camera->pl)
|
|
return (GP_ERROR_NO_MEMORY);
|
|
memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
|
|
camera->pl->first_init = 1;
|
|
camera->pl->seq_tx = 1;
|
|
camera->pl->seq_rx = 1;
|
|
|
|
switch (camera->port->type) {
|
|
case GP_PORT_USB:
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon",
|
|
"GPhoto tells us that we should use a USB link.\n");
|
|
camera->pl->canon_comm_method = CANON_USB;
|
|
|
|
return canon_usb_init (camera);
|
|
break;
|
|
case GP_PORT_SERIAL:
|
|
default:
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon",
|
|
"GPhoto tells us that we should use a RS232 link.\n");
|
|
|
|
/* Figure out the speed (and set to default speed if 0) */
|
|
gp_port_get_settings (camera->port, &settings);
|
|
camera->pl->speed = settings.serial.speed;
|
|
|
|
if (camera->pl->speed == 0)
|
|
camera->pl->speed = 9600;
|
|
|
|
gp_debug_printf (GP_DEBUG_LOW, "canon",
|
|
"Camera transmission speed : %i\n",
|
|
camera->pl->speed);
|
|
camera->pl->canon_comm_method = CANON_SERIAL_RS232;
|
|
|
|
return canon_serial_init (camera);
|
|
break;
|
|
}
|
|
|
|
/* NOT REACHED */
|
|
return GP_ERROR;
|
|
}
|