/* library.c * * Copyright 2002 Lutz Mueller * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #define _DEFAULT_SOURCE #include "config.h" #include #include #include #include #include #include "libgphoto2/i18n.h" #include "ricoh.h" #define GP_MODULE "ricoh" #define CR(result) {int r=(result); if (r<0) return r;} #define CRW(result,widget) {int r=(result); if (r<0) { gp_widget_free (widget); return r; } } static struct { RicohModel id; const char *model; } models[] = { {RICOH_MODEL_1, "Ricoh:RDC-1"}, {RICOH_MODEL_2, "Ricoh:RDC-2"}, {RICOH_MODEL_2E, "Ricoh:RDC-2E"}, {RICOH_MODEL_100G, "Ricoh:RDC-100G"}, {RICOH_MODEL_300, "Ricoh:RDC-300"}, {RICOH_MODEL_300Z, "Ricoh:RDC-300Z"}, {RICOH_MODEL_4200, "Ricoh:RDC-4200"}, {RICOH_MODEL_4300, "Ricoh:RDC-4300"}, {RICOH_MODEL_5000, "Ricoh:RDC-5000"}, {RICOH_MODEL_ESP2, "Philips:ESP2"}, {RICOH_MODEL_ESP50, "Philips:ESP50"}, {RICOH_MODEL_ESP60, "Philips:ESP60"}, {RICOH_MODEL_ESP70, "Philips:ESP70"}, {RICOH_MODEL_ESP80, "Philips:ESP80"}, {RICOH_MODEL_ESP80SXG, "Philips:ESP80SXG"}, {0, NULL} }; struct _CameraPrivateLibrary { RicohModel model; }; int camera_abilities (CameraAbilitiesList *list) { int i; CameraAbilities a; memset (&a, 0, sizeof (CameraAbilities)); for (i = 0; models[i].model; i++) { strcpy (a.model, models[i].model); a.status = GP_DRIVER_STATUS_EXPERIMENTAL; a.port = GP_PORT_SERIAL; a.operations = GP_OPERATION_CAPTURE_IMAGE | GP_OPERATION_CONFIG; a.file_operations = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_PREVIEW; a.folder_operations = GP_FOLDER_OPERATION_PUT_FILE; CR (gp_abilities_list_append (list, a)); } return (GP_OK); } static int camera_exit (Camera *camera, GPContext *context) { if (camera->pl) { free (camera->pl); camera->pl = NULL; } ricoh_disconnect (camera, context); return GP_OK; } static int file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, void *data, GPContext *context) { Camera *camera = data; unsigned int n, i; const char *name; CR (ricoh_get_num (camera, context, &n)); for (i = 0; i < n; i++) { CR (ricoh_get_pic_name (camera, context, i + 1, &name)); CR (gp_list_append (list, name, NULL)); } 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; const char *name; CR (n = gp_filesystem_number (fs, folder, filename, context)); n++; info->audio.fields = GP_FILE_INFO_NONE; /* no info anbout audio files */ info->preview.width = 80; info->preview.height = 60; info->preview.fields = GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT; CR (ricoh_get_pic_name (camera, context, n, &name)); CR (ricoh_get_pic_date (camera, context, n, &info->file.mtime)); CR (ricoh_get_pic_size (camera, context, n, &info->file.size)); strcpy (info->file.type, GP_MIME_EXIF); info->file.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_MTIME | GP_FILE_INFO_TYPE; return (GP_OK); } static int get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *user_data, GPContext *context) { Camera *camera = user_data; int n; unsigned int size; unsigned char *data; CR (n = gp_filesystem_number (fs, folder, filename, context)); n++; switch (type) { case GP_FILE_TYPE_NORMAL: CR (ricoh_get_pic (camera, context, n, RICOH_FILE_TYPE_NORMAL, &data, &size)); gp_file_set_mime_type (file, GP_MIME_EXIF); break; case GP_FILE_TYPE_PREVIEW: CR (ricoh_get_pic (camera, context, n, RICOH_FILE_TYPE_PREVIEW, &data, &size)); gp_file_set_mime_type (file, GP_MIME_TIFF); break; default: return (GP_ERROR_NOT_SUPPORTED); } gp_file_set_data_and_size (file, (char*)data, size); return (GP_OK); } static int del_file_func (CameraFilesystem *fs, const char *folder, const char *filename, void *user_data, GPContext *context) { Camera *camera = user_data; int n; CR (n = gp_filesystem_number (fs, folder, filename, context)); n++; CR (ricoh_del_pic (camera, context, n)); return (GP_OK); } static int camera_about (Camera *camera, CameraText *about, GPContext *context) { GP_DEBUG ("camera_about()"); strcpy (about->text, _("Ricoh / Philips driver by\n" "Lutz Mueller ,\n" "Martin Fischer ,\n" "based on Bob Paauwe's driver\n" ) ); return GP_OK; } int camera_id (CameraText *id) { strcpy (id->text, "Ricoh"); return (GP_OK); } static int camera_summary (Camera *camera, CameraText *about, GPContext *context) { int avail_mem, total_mem; char model[128]; unsigned int i; CR (ricoh_get_cam_amem (camera, context, &avail_mem)); CR (ricoh_get_cam_mem (camera, context, &total_mem)); memset (model, 0, sizeof (model)); for (i = 0; models[i].model; i++) if (models[i].id == camera->pl->model) break; if (models[i].model) strncpy (model, models[i].model, sizeof (model) - 1); else snprintf (model, sizeof (model) - 1, _("unknown (0x%02x)"), camera->pl->model); sprintf (about->text, _("Model: %s\n" "Memory: %d byte(s) of %d available"), model, avail_mem, total_mem); return (GP_OK); } static int camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path, GPContext *context) { unsigned int n; if (type != GP_CAPTURE_IMAGE) return (GP_ERROR_NOT_SUPPORTED); CR (ricoh_get_num (camera, context, &n)); CR (ricoh_take_pic (camera, context)); sprintf (path->name, "rdc%04i.jpg", n + 1); strcpy (path->folder, "/"); CR (gp_filesystem_append (camera->fs, path->folder, path->name, context)); return (GP_OK); } static int put_file_func (CameraFilesystem *fs, const char *folder, const char *name, CameraFileType type, CameraFile *file, void *user_data, GPContext *context) { const char *data; unsigned long int size; Camera *camera = user_data; if (type != GP_FILE_TYPE_NORMAL) return GP_ERROR_BAD_PARAMETERS; CR (gp_file_get_data_and_size (file, &data, &size)); return ricoh_put_file (camera, context, name, (const unsigned char *)data, size); } #undef N_ELEMENTS #define N_ELEMENTS(v) (sizeof(v)/sizeof(v[0])) static struct { RicohExposure exposure; const char *name; } ricoh_exposures[] = { {RICOH_EXPOSURE_M20, N_("-2.0")}, {RICOH_EXPOSURE_M15, N_("-1.5")}, {RICOH_EXPOSURE_M10, N_("-1.0")}, {RICOH_EXPOSURE_M05, N_("-0.5")}, {RICOH_EXPOSURE_00, N_("0.0")}, {RICOH_EXPOSURE_05, N_("0.5")}, {RICOH_EXPOSURE_10, N_("1.0")}, {RICOH_EXPOSURE_15, N_("1.5")}, {RICOH_EXPOSURE_20, N_("2.0")}, {RICOH_EXPOSURE_AUTO, N_("Auto")} }; static struct { RicohResolution resolution; const char *name; } ricoh_resolutions[] = { {RICOH_RESOLUTION_640_480, N_("640 x 480")}, {RICOH_RESOLUTION_1280_960, N_("1280 x 960")} }; static struct { RicohWhiteLevel white_level; const char *name; } ricoh_white_levels[] = { {RICOH_WHITE_LEVEL_AUTO, N_("Auto")}, {RICOH_WHITE_LEVEL_OUTDOOR, N_("Outdoor")}, {RICOH_WHITE_LEVEL_FLUORESCENT, N_("Fluorescent")}, {RICOH_WHITE_LEVEL_INCANDESCENT, N_("Incandescent")}, {RICOH_WHITE_LEVEL_BLACK_WHITE, N_("Black & White")}, {RICOH_WHITE_LEVEL_SEPIA, N_("Sepia")} }; static struct { RicohMacro macro; const char *name; } ricoh_macros[] = { {RICOH_MACRO_ON, N_("On")}, {RICOH_MACRO_OFF, N_("Off")} }; static struct { RicohCompression compression; const char *name; } ricoh_compressions[] = { {RICOH_COMPRESSION_NONE, N_("None")}, {RICOH_COMPRESSION_MAX, N_("Maximal")}, {RICOH_COMPRESSION_NORM, N_("Normal")}, {RICOH_COMPRESSION_MIN, N_("Minimal")} }; static struct { RicohRecMode rec_mode; const char *name; } ricoh_rec_modes[] = { {RICOH_REC_MODE_IMAGE, N_("Image")}, {RICOH_REC_MODE_CHARACTER, N_("Character")}, {RICOH_REC_MODE_SOUND, N_("Sound")}, {RICOH_REC_MODE_IMAGE_SOUND, N_("Image & Sound")}, {RICOH_REC_MODE_CHARACTER_SOUND, N_("Character & Sound")} }; static struct { RicohFlash flash; const char *name; } ricoh_flashs[] = { {RICOH_FLASH_AUTO, N_("Auto")}, {RICOH_FLASH_OFF, N_("Off")}, {RICOH_FLASH_ON, N_("On")} }; static struct { RicohZoom zoom; const char *name; } ricoh_zooms[] = { {RICOH_ZOOM_OFF, N_("Off")}, {RICOH_ZOOM_1, N_("2x")}, {RICOH_ZOOM_2, N_("3x")}, {RICOH_ZOOM_3, N_("4x")}, {RICOH_ZOOM_4, N_("5x")}, {RICOH_ZOOM_5, N_("6x")}, {RICOH_ZOOM_6, N_("7x")}, {RICOH_ZOOM_7, N_("8x")}, {RICOH_ZOOM_8, N_("9x")} }; #undef R_ADD_RADIO #define R_ADD_RADIO(ca,co,s,type,n,Name) \ { \ CameraWidget *__w = NULL; \ type __v; \ unsigned int __i; \ \ CR (gp_widget_new (GP_WIDGET_RADIO, _(Name), &__w)); \ CRW (gp_widget_set_name (__w, (Name)), __w); \ CRW (gp_widget_append ((s), __w), __w); \ CR (ricoh_get_##n ((ca), (co), &__v)); \ for (__i = 0; __i < N_ELEMENTS (ricoh_##n##s); __i++) { \ CR (gp_widget_add_choice (__w, _(ricoh_##n##s[__i].name))); \ if (__v == ricoh_##n##s[__i].n) \ CR (gp_widget_set_value (__w, \ _(ricoh_##n##s[__i].name))); \ } \ } #undef R_CHECK_RADIO #define R_CHECK_RADIO(c,co,wi,n,Name) \ { \ CameraWidget *__w = NULL; \ const char *__v = NULL; \ unsigned int __i; \ \ CR (gp_widget_get_child_by_name (wi, Name, &__w)); \ if (gp_widget_changed (__w)) { \ gp_widget_set_changed (__w, 0); \ CR (gp_widget_get_value (__w, &__v)); \ for (__i = 0; __i < N_ELEMENTS (ricoh_##n##s); __i++) \ if (!strcmp (__v, _(ricoh_##n##s[__i].name))) { \ CR (ricoh_set_##n (c, co, ricoh_##n##s[__i].n)); \ break; \ } \ } \ } static int camera_get_config (Camera *c, CameraWidget **window, GPContext *co) { CameraWidget *s, *w; const char *copyright; time_t time; CR (gp_widget_new (GP_WIDGET_WINDOW, _("Configuration"), window)); /* General settings */ CR (gp_widget_new (GP_WIDGET_SECTION, _("General"), &s)); CRW (gp_widget_append (*window, s), s); /* Copyright */ CR (gp_widget_new (GP_WIDGET_TEXT, _("Copyright"), &w)); CRW (gp_widget_set_name (w, "copyright"), w); CRW (gp_widget_set_info (w, _("Copyright (max. 20 characters)")), w); CRW (gp_widget_append (s, w), w); CR (ricoh_get_copyright (c, co, ©right)); CR (gp_widget_set_value (w, (void *) copyright)); /* Date */ CR (gp_widget_new (GP_WIDGET_DATE, _("Date & Time"), &w)); CRW (gp_widget_set_name (w, "date"), w); CRW (gp_widget_set_info (w, _("Date & Time")), w); CRW (gp_widget_append (s, w), w); CR (ricoh_get_date (c, co, &time)); CR (gp_widget_set_value (w, &time)); /* Picture related settings */ CR (gp_widget_new (GP_WIDGET_SECTION, _("Pictures"), &s)); CRW (gp_widget_append (*window, s), w); R_ADD_RADIO (c, co, s, RicohResolution, resolution, "Resolution") R_ADD_RADIO (c, co, s, RicohExposure, exposure, "Exposure") R_ADD_RADIO (c, co, s, RicohMacro, macro, "Macro") R_ADD_RADIO (c, co, s, RicohFlash, flash, "Flash") R_ADD_RADIO (c, co, s, RicohZoom, zoom, "Zoom") R_ADD_RADIO (c, co, s, RicohCompression, compression, "Compression") R_ADD_RADIO (c, co, s, RicohWhiteLevel, white_level, "White Level") R_ADD_RADIO (c, co, s, RicohRecMode, rec_mode, "Record Mode") return (GP_OK); } static int camera_set_config (Camera *c, CameraWidget *window, GPContext *co) { CameraWidget *w; const char *v_char; time_t time; RicohMode mode; /* We need to be in record mode to set settings. */ CR (ricoh_get_mode (c, co, &mode)); if (mode != RICOH_MODE_RECORD) CR (ricoh_set_mode (c, co, RICOH_MODE_RECORD)); /* Copyright */ CR (gp_widget_get_child_by_name (window, "copyright", &w)); if (gp_widget_changed (w)) { gp_widget_set_changed (w, 0); CR (gp_widget_get_value (w, &v_char)); CR (ricoh_set_copyright (c, co, v_char)); } /* Date */ CR (gp_widget_get_child_by_name (window, "date", &w)); if (gp_widget_changed (w)) { gp_widget_set_changed (w, 0); CR (gp_widget_get_value (w, &time)); CR (ricoh_set_date (c, co, time)); } R_CHECK_RADIO (c, co, window, resolution, N_("Resolution")) R_CHECK_RADIO (c, co, window, exposure, N_("Exposure")) R_CHECK_RADIO (c, co, window, white_level, N_("White level")) R_CHECK_RADIO (c, co, window, macro, N_("Macro")) R_CHECK_RADIO (c, co, window, zoom, N_("Zoom")) R_CHECK_RADIO (c, co, window, flash, N_("Flash")) R_CHECK_RADIO (c, co, window, rec_mode, N_("Record Mode")) R_CHECK_RADIO (c, co, window, compression, N_("Compression")) return (GP_OK); } static struct { unsigned int speed; RicohSpeed rspeed; } speeds[] = { { 2400, RICOH_SPEED_2400}, {115200, RICOH_SPEED_115200}, { 4800, RICOH_SPEED_4800}, { 19200, RICOH_SPEED_19200}, { 38400, RICOH_SPEED_38400}, { 57600, RICOH_SPEED_57600}, { 0, 0} }; static CameraFilesystemFuncs fsfuncs = { .file_list_func = file_list_func, .get_file_func = get_file_func, .del_file_func = del_file_func, .put_file_func = put_file_func, .get_info_func = get_info_func }; int camera_init (Camera *camera, GPContext *context) { GPPortSettings settings; unsigned int speed, i; int result; RicohModel model = 0; /* Try to contact the camera. */ CR (gp_port_set_timeout (camera->port, 5000)); CR (gp_port_get_settings (camera->port, &settings)); speed = (settings.serial.speed ? settings.serial.speed : 115200); for (i = 0; speeds[i].speed; i++) { GP_DEBUG ("Trying speed %i...", speeds[i].speed); settings.serial.speed = speeds[i].speed; CR (gp_port_set_settings (camera->port, settings)); /* * Note that ricoh_connect can only be called to * initialize the connection at 2400 bps. At other * speeds, a different function needs to be used. */ result = (speeds[i].rspeed == RICOH_SPEED_2400) ? ricoh_connect (camera, NULL, &model) : ricoh_get_mode (camera, NULL, NULL); if (result == GP_OK) break; } /* Contact made? If not, report error. */ if (!speeds[i].speed) { gp_context_error (context, _("Could not contact camera.")); return (GP_ERROR); } /* Contact made. Do we need to change the speed? */ if ((unsigned int)settings.serial.speed != speed) { for (i = 0; speeds[i].speed; i++) if (speeds[i].speed == speed) break; if (!speeds[i].speed) { gp_context_error (context, _("Speed %i is not " "supported!"), speed); return (GP_ERROR); } CR (ricoh_set_speed (camera, context, speeds[i].rspeed)); settings.serial.speed = speed; CR (gp_port_set_settings (camera->port, settings)); /* Check if the camera is still there. */ CR (ricoh_get_mode (camera, context, NULL)); } /* setup the function calls */ camera->functions->exit = camera_exit; camera->functions->summary = camera_summary; camera->functions->capture = camera_capture; camera->functions->about = camera_about; camera->functions->get_config = camera_get_config; camera->functions->set_config = camera_set_config; CR (gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera)); /* * Remember the model. It could be that there hasn't been the * need to call ricoh_connect. Then we don't have a model. Should * we disconnect and reconnect in this case? */ camera->pl = malloc (sizeof (CameraPrivateLibrary)); if (!camera->pl) return (GP_ERROR_NO_MEMORY); memset (camera->pl, 0, sizeof (CameraPrivateLibrary)); camera->pl->model = model; return (GP_OK); }