Files
libgphoto2/camlibs/fuji/library.c
2003-01-10 19:21:51 +00:00

548 lines
14 KiB
C

/* library.c:
*
* Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <gphoto2-library.h>
#include <gphoto2-port.h>
#include <gphoto2-port-log.h>
#include "fuji.h"
#ifdef ENABLE_NLS
# include <libintl.h>
# undef _
# define _(String) dgettext (GETTEXT_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
#define GP_MODULE "fuji"
#define CR(result) {int r = (result); if (r < 0) return (r);}
static struct {
const char *model;
} models[] = {
{"Apple:QuickTake 200"},
{"Fuji:DS-7"},
{"Fuji:DX-5"},
{"Fuji:DX-7"},
{"Fuji:DX-10"},
{"Fuji:MX-500"},
{"Fuji:MX-600"},
{"Fuji:MX-700"},
{"Fuji:MX-1200"},
{"Fuji:MX-1700"},
{"Fuji:MX-2700"},
{"Fuji:MX-2900"},
{"Leica:Digilux Zoom"},
{"Samsung:Kenox SSC-350N"},
{"Toshiba:PDR-M1"},
{NULL}
};
struct _CameraPrivateLibrary {
unsigned long speed;
unsigned char cmds[0xff];
};
struct {
FujiCmd command;
const char *name;
} Commands[] = {
{FUJI_CMD_PIC_GET, "get picture"},
{FUJI_CMD_PIC_GET_THUMB, "get thumbnail"},
{FUJI_CMD_SPEED, "change speed"},
{FUJI_CMD_VERSION, "get version"},
{FUJI_CMD_PIC_NAME, "get name of picture"},
{FUJI_CMD_PIC_COUNT, "get number of pictures"},
{FUJI_CMD_PIC_SIZE, "get size of picture"},
{FUJI_CMD_PIC_DEL, "delete picture"},
{FUJI_CMD_TAKE, "capture picture"},
{FUJI_CMD_FLASH_GET, "get flash mode"},
{FUJI_CMD_FLASH_SET, "set flash mode"},
{FUJI_CMD_FLASH_CHARGE, "charge flash"},
{FUJI_CMD_CMDS_VALID, "list valid commands"},
{FUJI_CMD_PREVIEW, "capture preview"},
{FUJI_CMD_DATE_GET, "get date"},
{0, NULL}};
static const char *
cmd_get_name (FujiCmd command)
{
unsigned int i;
for (i = 0; Commands[i].name; i++)
if (Commands[i].command == command)
break;
return (Commands[i].name);
}
int
camera_id (CameraText *id)
{
strcpy (id->text, "Fuji");
return (GP_OK);
}
int
camera_abilities (CameraAbilitiesList *list)
{
CameraAbilities a;
int i;
memset (&a, 0, sizeof (a));
for (i = 0; models[i].model; i++) {
strcpy (a.model, models[i].model);
a.port = GP_PORT_SERIAL;
a.speed[0] = 9600;
a.speed[1] = 19200;
a.speed[2] = 38400;
a.speed[3] = 56700;
a.speed[4] = 115200;
a.speed[5] = 0;
a.folder_operations = GP_FOLDER_OPERATION_PUT_FILE;
a.file_operations = GP_FILE_OPERATION_PREVIEW |
GP_FILE_OPERATION_DELETE;
a.operations = GP_OPERATION_CONFIG;
CR (gp_abilities_list_append (list, a));
}
return (GP_OK);
}
static int
camera_about (Camera *camera, CameraText *about, GPContext *context)
{
strcpy (about->text, _(""
"Matthew G. Martin\n"
"Based on fujiplay by Thierry Bousch "
"<bousch@topo.math.u-psud.fr>\n"));
return (GP_OK);
}
static int
file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
void *data, GPContext *context)
{
Camera *camera = data;
int n, i;
const char *name;
/*
* Count the pictures on the camera. If we don't have any, we
* are done.
*/
CR (fuji_pic_count (camera, &n, context));
if (!n)
return (GP_OK);
/*
* Try to get the name of the first file. If we can't, just come
* up with some dummy names.
*/
if (fuji_pic_name (camera, 1, &name, context) < 0) {
CR (gp_list_populate (list, "DSCF%04i.JPG", n));
return (GP_OK);
}
CR (gp_list_append (list, name, NULL));
/* Get the names of the remaining files. */
for (i = 2; i <= n; i++) {
CR (fuji_pic_name (camera, i, &name, context));
CR (gp_list_append (list, name, NULL));
}
return (GP_OK);
}
static int
get_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, CameraFileType type,
CameraFile *file, void *data, GPContext *context)
{
Camera *camera = data;
int n;
unsigned char *d;
unsigned int size;
/* We need file numbers starting with 1 */
CR (n = gp_filesystem_number (camera->fs, folder, filename, context));
n++;
switch (type) {
case GP_FILE_TYPE_NORMAL:
CR (fuji_pic_get (camera, n, &d, &size, context));
break;
case GP_FILE_TYPE_PREVIEW:
CR (fuji_pic_get_thumb (camera, n, &d, &size, context));
break;
default:
return (GP_ERROR_NOT_SUPPORTED);
}
CR (gp_file_set_data_and_size (file, d, size));
CR (gp_file_set_mime_type (file, GP_MIME_JPEG));
return (GP_OK);
}
static int
put_file_func (CameraFilesystem *fs, const char *folder,
CameraFile *file, void *data, GPContext *context)
{
Camera *camera = data;
const char *d, *name;
unsigned long int d_len;
CR (gp_file_get_data_and_size (file, &d, &d_len));
CR (gp_file_get_name (file, &name));
CR (fuji_upload_init (camera, name, context));
CR (fuji_upload (camera, d, d_len, context));
return (GP_OK);
}
static int
del_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, void *data, GPContext *context)
{
Camera *camera = data;
int n;
/* We need file numbers starting with 1 */
CR (n = gp_filesystem_number (camera->fs, folder, filename, context));
n++;
CR (fuji_pic_del (camera, n, context));
return (GP_OK);
}
struct {
FujiSpeed speed;
unsigned int bit_rate;
} Speeds[] = {
{FUJI_SPEED_115200, 115200},
{FUJI_SPEED_57600, 57600},
{FUJI_SPEED_38400, 38400},
{FUJI_SPEED_19200, 19200},
{FUJI_SPEED_9600, 9600},
{FUJI_SPEED_9600, 0}
};
static int
camera_exit (Camera *camera, GPContext *context)
{
if (camera->pl) {
free (camera->pl);
camera->pl = NULL;
}
return (GP_OK);
}
static int
pre_func (Camera *camera, GPContext *context)
{
int r;
unsigned int i;
GPPortSettings settings;
GP_DEBUG ("Initializing connection...");
CR (gp_port_get_settings (camera->port, &settings));
CR (fuji_ping (camera, context));
if (!camera->pl->speed) {
/* Set to the highest possible speed. */
for (i = 0; Speeds[i].bit_rate; i++) {
r = fuji_set_speed (camera, Speeds[i].speed, NULL);
if (r >= 0)
break;
}
/*
* Change the port's speed and check if the camera is
* still there.
*/
settings.serial.speed = Speeds[i].bit_rate;
CR (gp_port_set_settings (camera->port, settings));
GP_DEBUG("Pinging to check new speed %i.", Speeds[i].bit_rate);
CR (fuji_ping (camera, context));
} else {
/* User specified a speed. Check if the speed is possible */
for (i = 0; Speeds[i].bit_rate; i++)
if (Speeds[i].bit_rate == camera->pl->speed)
break;
if (!Speeds[i].bit_rate) {
gp_context_error (context, _("Bit rate %i is not "
"supported."), camera->pl->speed);
return (GP_ERROR_NOT_SUPPORTED);
}
/* Change the speed if necessary. */
if (camera->pl->speed != Speeds[i].bit_rate) {
CR (fuji_set_speed (camera, Speeds[i].speed, context));
/*
* Change the port's speed and check if the camera is
* still there.
*/
settings.serial.speed = Speeds[i].bit_rate;
CR (gp_port_set_settings (camera->port, settings));
CR (fuji_ping (camera, context));
}
}
return (GP_OK);
}
static int
post_func (Camera *camera, GPContext *context)
{
GPPortSettings settings;
GP_DEBUG ("Terminating connection...");
/* Put the camera back to 9600 bps if necessary. */
CR (gp_port_get_settings (camera->port, &settings));
if (settings.serial.speed != 9600) {
CR (fuji_set_speed (camera, FUJI_SPEED_9600, context));
settings.serial.speed = 9600;
CR (gp_port_set_settings (camera->port, settings));
}
return (GP_OK);
}
static int
camera_get_config (Camera *camera, CameraWidget **window, GPContext *context)
{
CameraWidget *widget;
struct tm tm;
time_t t;
FujiDate date;
const char *id;
CR (gp_widget_new (GP_WIDGET_WINDOW, _("Configuration for "
"your FUJI camera"), window));
/* Date & Time */
if (fuji_date_get (camera, &date, context) >= 0) {
CR (gp_widget_new (GP_WIDGET_DATE, _("Date & Time"), &widget));
CR (gp_widget_append (*window, widget));
memset (&tm, 0, sizeof (struct tm));
tm.tm_year = date.year;
tm.tm_mon = date.month;
tm.tm_mday = date.day;
tm.tm_hour = date.hour;
tm.tm_min = date.min;
tm.tm_sec = date.sec;
t = mktime (&tm);
CR (gp_widget_set_value (widget, &t));
}
/* ID */
if (fuji_id_get (camera, &id, context) >= 0) {
CR (gp_widget_new (GP_WIDGET_TEXT, _("ID"), &widget));
CR (gp_widget_append (*window, widget));
CR (gp_widget_set_value (widget, (void *) id));
}
return (GP_OK);
}
static int
camera_set_config (Camera *camera, CameraWidget *window, GPContext *context)
{
CameraWidget *widget;
FujiDate date;
time_t t;
struct tm *tm;
const char *id;
/* Date & Time */
if ((gp_widget_get_child_by_label (window, _("Date & Time"),
&widget) >= 0) &&
gp_widget_changed (widget)) {
CR (gp_widget_get_value (widget, &t));
tm = localtime (&t);
date.year = tm->tm_year;
date.month = tm->tm_mon;
date.day = tm->tm_mday;
date.hour = tm->tm_hour;
date.min = tm->tm_min;
date.sec = tm->tm_sec;
CR (fuji_date_set (camera, date, context));
}
/* ID */
if ((gp_widget_get_child_by_label (window, _("ID"), &widget) >= 0) &&
gp_widget_changed (widget)) {
CR (gp_widget_get_value (widget, &id));
CR (fuji_id_set (camera, id, context));
}
return (GP_OK);
}
static int
camera_summary (Camera *camera, CameraText *text, GPContext *context)
{
const char *string;
char buf[1024];
unsigned int avail_mem;
memset (text->text, 0, sizeof (text->text));
if (fuji_version (camera, &string, context) >= 0) {
strcat (text->text, _("Version: "));
strcat (text->text, string);
strcat (text->text, "\n");
}
if (fuji_model (camera, &string, context) >= 0) {
strcat (text->text, _("Model: "));
strcat (text->text, string);
strcat (text->text, "\n");
}
if (fuji_avail_mem (camera, &avail_mem, context) >= 0) {
snprintf (buf, sizeof (buf), "%d", avail_mem);
strcat (text->text, _("Available memory: "));
strcat (text->text, buf);
strcat (text->text, "\n");
}
return (GP_OK);
}
static int
get_info_func (CameraFilesystem *fs, const char *folder, const char *filename,
CameraFileInfo *info, void *data, GPContext *context)
{
Camera *camera = data;
int n;
unsigned int size;
info->file.fields = GP_FILE_INFO_NONE;
info->preview.fields = GP_FILE_INFO_NONE;
info->audio.fields = GP_FILE_INFO_NONE;
/* Name */
info->file.fields |= GP_FILE_INFO_NAME;
strncpy (info->file.name, filename, sizeof (info->file.name));
/* We need file numbers starting with 1 */
CR (n = gp_filesystem_number (camera->fs, folder, filename, context));
n++;
/* Size */
if (fuji_pic_size (camera, n, &size, context) >= 0) {
info->file.fields |= GP_FILE_INFO_SIZE;
info->file.size = size;
}
return (GP_OK);
}
int
camera_init (Camera *camera, GPContext *context)
{
GPPortSettings settings;
unsigned int i;
/* Setup all function pointers */
camera->functions->pre_func = pre_func;
camera->functions->post_func = post_func;
camera->functions->about = camera_about;
camera->functions->exit = camera_exit;
camera->functions->get_config = camera_get_config;
camera->functions->set_config = camera_set_config;
camera->functions->summary = camera_summary;
/* We need to store some data */
camera->pl = malloc (sizeof (CameraPrivateLibrary));
if (!camera->pl)
return (GP_ERROR_NO_MEMORY);
memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
/* Set up the port, but remember the current speed. */
CR (gp_port_set_timeout (camera->port, 1000));
CR (gp_port_get_settings (camera->port, &settings));
camera->pl->speed = settings.serial.speed;
settings.serial.speed = 9600;
settings.serial.bits = 8;
settings.serial.parity = GP_PORT_SERIAL_PARITY_EVEN;
settings.serial.stopbits = 1;
CR (gp_port_set_settings (camera->port, settings));
/* Set up the filesystem. */
CR (gp_filesystem_set_list_funcs (camera->fs, file_list_func, NULL,
camera));
CR (gp_filesystem_set_file_funcs (camera->fs, get_file_func,
del_file_func, camera));
CR (gp_filesystem_set_info_funcs (camera->fs, get_info_func, NULL,
camera));
CR (gp_filesystem_set_folder_funcs (camera->fs, put_file_func, NULL,
NULL, NULL, camera));
/* Initialize the connection */
CR (pre_func (camera, context));
/*
* What commands does this camera support? The question is not
* easy to answer, as "One issue the DS7 has is that the
* supported command list command is not supported"
* (Matt Martin <matt.martin@ieee.org>).
*/
if (fuji_get_cmds (camera, camera->pl->cmds, context) >= 0) {
GP_DEBUG ("Your camera supports the following command(s):");
for (i = 0; i < 0xff; i++)
if (camera->pl->cmds[i])
GP_DEBUG (" - 0x%02x: '%s'", i,
cmd_get_name (i));
}
return (GP_OK);
}