/* Pentax K series library * * Copyright (c) 2011,2017 Marcus Meissner * * This program 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.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; 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" #define GP_MODULE "pentax" #include #include #include #include #include #include #include #include #include #include #include "libgphoto2/i18n.h" #include "pslr.h" bool debug = true; struct _CameraPrivateLibrary { ipslr_handle_t pslr; char *lastfn; int capcnt; }; int camera_id (CameraText *id) { strcpy (id->text, "pentax"); return GP_OK; } int camera_abilities (CameraAbilitiesList *list) { CameraAbilities a; int ret; memset (&a, 0, sizeof(a)); strcpy (a.model, "Pentax:K20D"); a.status = GP_DRIVER_STATUS_TESTING; a.port = GP_PORT_USB_SCSI; a.speed[0] = 0; a.usb_vendor = 0x0a17; a.usb_product = 0x0091; a.operations = GP_OPERATION_CAPTURE_IMAGE | GP_OPERATION_CONFIG | GP_OPERATION_TRIGGER_CAPTURE; a.folder_operations = GP_FOLDER_OPERATION_NONE; a.file_operations = GP_FILE_OPERATION_DELETE; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K10D"); a.usb_product = 0x006e; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K100D"); a.usb_product = 0x0070; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K100DS"); a.usb_product = 0x00a1; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K200D"); a.usb_product = 0x0093; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; /* weird usb vendor? */ strcpy (a.model, "Pentax:K5D"); a.usb_vendor = 0x25fb; a.usb_product = 0x0102; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K50D"); a.usb_vendor = 0x25fb; a.usb_product = 0x0160; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; /* TommyLimKW at Twitter */ strcpy (a.model, "Pentax:K01"); a.usb_vendor = 0x25fb; a.usb_product = 0x0130; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K30"); a.usb_vendor = 0x25fb; a.usb_product = 0x0132; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K5II"); a.usb_vendor = 0x25fb; a.usb_product = 0x0148; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; /* TommyLimKW @ Twitter */ strcpy (a.model, "Pentax:K5IIs"); a.usb_vendor = 0x25fb; a.usb_product = 0x014a; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K3"); a.usb_vendor = 0x25fb; a.usb_product = 0x0164; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K1"); a.usb_vendor = 0x25fb; a.usb_product = 0x0178; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; strcpy (a.model, "Pentax:K3II"); a.usb_vendor = 0x25fb; a.usb_product = 0x017a; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; /* Keld Henningsen */ strcpy (a.model, "Pentax:K70"); a.usb_vendor = 0x25fb; a.usb_product = 0x017c; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; /* fifu7fi@gmail.com */ strcpy (a.model, "Pentax:KP"); a.usb_vendor = 0x25fb; a.usb_product = 0x017e; if (GP_OK != (ret = gp_abilities_list_append (list, a))) return ret; return GP_OK; } int scsi_write(GPPort *port, uint8_t *cmd, uint32_t cmdLen, uint8_t *buf, uint32_t bufLen) { int ret; char sense_buffer[32]; ret = gp_port_send_scsi_cmd (port, 1, (char*)cmd, cmdLen, sense_buffer, sizeof(sense_buffer), (char*)buf, bufLen); if (ret == GP_OK) return PSLR_OK; return PSLR_SCSI_ERROR; } int scsi_read(GPPort *port, uint8_t *cmd, uint32_t cmdLen, uint8_t *buf, uint32_t bufLen) { int ret; char sense_buffer[32]; ret = gp_port_send_scsi_cmd (port, 0, (char*)cmd, cmdLen, sense_buffer, sizeof(sense_buffer), (char*)buf, bufLen); if (ret == GP_OK) return bufLen; return -PSLR_SCSI_ERROR; } void close_drive(GPPort **port) { /* is going to be closed by other means */ return; } static int camera_summary (Camera *camera, CameraText *summary, GPContext *context) { char *statusinfo; pslr_status status; pslr_get_status (&camera->pl->pslr, &status); statusinfo = collect_status_info( &camera->pl->pslr, status ); sprintf (summary->text, _( "Pentax K DSLR capture driver.\n" "Using code from pktriggercord by Andras Salamon.\n" "Collected Status Information:\n%s" ), statusinfo); free (statusinfo); return GP_OK; } static int get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context) { return GP_ERROR_NOT_SUPPORTED; } static int file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, void *data, GPContext *context) { return GP_OK; } static int delete_file_func (CameraFilesystem *fs, const char *folder, const char *filename, void *data, GPContext *context) { /* virtual file created by Penta capture */ if (!strncmp (filename, "capt", 4)) return GP_OK; return GP_ERROR_NOT_SUPPORTED; } static CameraFilesystemFuncs fsfuncs = { .file_list_func = file_list_func, .get_file_func = get_file_func, .del_file_func = delete_file_func }; static int save_buffer(pslr_handle_t camhandle, int bufno, pslr_buffer_type buftype, uint32_t jpegres, CameraFile *file) { uint8_t buf[65536]; uint32_t current; gp_log(GP_LOG_DEBUG, "pentax", "save_buffer: get buffer %d type %d res %d\n", bufno, buftype, jpegres); if ( pslr_buffer_open(camhandle, bufno, buftype, jpegres) != PSLR_OK) return GP_ERROR; current = 0; while (1) { uint32_t bytes; bytes = pslr_buffer_read(camhandle, buf, sizeof(buf)); if (bytes == 0) break; if (((ipslr_handle_t*)camhandle)->model->id == 0x12b9c) { // PEF file got from K100D Super have broken header, WTF? if (current == 0 && (buftype == PSLR_BUF_PEF)) { const unsigned char correct_header[92] = { 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0xe0, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0xe8, 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x80, 0x05, 0x00, 0x00, 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x80, 0x23, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf2, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00 }; if (bytes < sizeof(correct_header)) return GP_ERROR; memcpy(buf, correct_header, sizeof(correct_header)); } } gp_file_append (file, (char*)buf, bytes); current += bytes; } pslr_buffer_close(camhandle); return current; } static int _timeout_passed(struct timeval *start, int timeout) { struct timeval curtime; gettimeofday (&curtime, NULL); return ((curtime.tv_sec - start->tv_sec)*1000)+((curtime.tv_usec - start->tv_usec)/1000) >= timeout; } static int camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path, GPContext *context) { pslr_handle_t p = &camera->pl->pslr; pslr_status status; int ret, length; CameraFile *file = NULL; CameraFileInfo info; int bufno, i; const char *mimes[2]; int buftypes[2], jpegres[2], nrofdownloads = 1; char *fns[2], *lastfn = NULL; struct timeval event_start; gp_log (GP_LOG_DEBUG, "pentax", "camera_capture"); pslr_get_status (p, &status); pslr_shutter (p); strcpy (path->folder, "/"); gp_log (GP_LOG_ERROR, "pentax", "image format image=0x%x, raw=0x%x", status.image_format, status.raw_format); switch (status.image_format) { case PSLR_IMAGE_FORMAT_JPEG: sprintf (path->name, "capt%04d.jpg", camera->pl->capcnt++); mimes[0] = GP_MIME_JPEG; buftypes[0] = status.jpeg_quality + 1; jpegres[0] = status.jpeg_resolution; fns[0] = strdup(path->name); break; case PSLR_IMAGE_FORMAT_RAW_PLUS: /* FIXME: the same as _RAW ? */ buftypes[1] = status.jpeg_quality + 1; jpegres[1] = status.jpeg_resolution; mimes[1] = GP_MIME_JPEG; sprintf (path->name, "capt%04d.jpg", camera->pl->capcnt); fns[1] = strdup(path->name); lastfn = strdup (fns[1]); nrofdownloads = 2; /* FALLTHROUGH */ case PSLR_IMAGE_FORMAT_RAW: jpegres[0] = 0; switch (status.raw_format) { case PSLR_RAW_FORMAT_PEF: sprintf (path->name, "capt%04d.pef", camera->pl->capcnt++); fns[0] = strdup (path->name); mimes[0] = GP_MIME_RAW; buftypes[0] = PSLR_BUF_PEF; break; case PSLR_RAW_FORMAT_DNG: sprintf (path->name, "capt%04d.dng", camera->pl->capcnt++); fns[0] = strdup (path->name); mimes[0] = "image/x-adobe-dng"; buftypes[0] = PSLR_BUF_DNG; break; default: gp_log (GP_LOG_ERROR, "pentax", "unknown format image=0x%x, raw=0x%x", status.image_format, status.raw_format); return GP_ERROR; } break; default: gp_log (GP_LOG_ERROR, "pentax", "unknown format image=0x%x (raw=0x%x)", status.image_format, status.raw_format); return GP_ERROR; } /* get status again, also waits until not busy */ pslr_get_status (p, &status); gettimeofday (&event_start, 0); while (1) { if (status.bufmask != 0) break; if (_timeout_passed (&event_start, 30*1000)) break; usleep(100*1000); /* 100 ms */ pslr_get_status (p, &status); } if (status.bufmask == 0) { gp_log (GP_LOG_ERROR, "pentax", "no buffer available for download after 30 seconds."); free (lastfn); return GP_ERROR; } for (bufno=0;bufno<16;bufno++) if (status.bufmask & (1 << bufno)) break; /* we will have found one if bufmask != 0 */ for (i = 0; i= GP_OK) break; usleep(100000); } gp_log (GP_LOG_DEBUG, "pentax", "append image to fs"); ret = gp_filesystem_append(camera->fs, path->folder, fns[i], context); if (ret != GP_OK) { gp_file_free (file); return ret; } gp_log (GP_LOG_DEBUG, "pentax", "adding filedata to fs"); ret = gp_filesystem_set_file_noop(camera->fs, path->folder, fns[i], GP_FILE_TYPE_NORMAL, file, context); if (ret != GP_OK) { gp_file_free (file); return ret; } /* We have now handed over the file, disclaim responsibility by unref. */ gp_file_unref (file); memset (&info, 0, sizeof (info)); /* we also get the fs info for free, so just set it */ info.file.fields = GP_FILE_INFO_TYPE | GP_FILE_INFO_SIZE | GP_FILE_INFO_MTIME; strcpy (info.file.type, GP_MIME_JPEG); info.file.size = length; info.file.mtime = time(NULL); info.preview.fields = 0; gp_log (GP_LOG_DEBUG, "pentax", "setting fileinfo in fs"); ret = gp_filesystem_set_info_noop(camera->fs, path->folder, fns[i], info, context); free (fns[i]); } camera->pl->lastfn = lastfn; pslr_delete_buffer(p, bufno ); pslr_get_status (&camera->pl->pslr, &status); /* wait until busy is gone */ return ret; } static int camera_trigger_capture (Camera *camera, GPContext *context) { pslr_handle_t p = &camera->pl->pslr; pslr_status status; gp_log (GP_LOG_DEBUG, "pentax", "camera_trigger_capture"); pslr_get_status (p, &status); pslr_shutter (p); /* get status again, also waits until not busy */ pslr_get_status (p, &status); return GP_OK; } static int camera_wait_for_event (Camera *camera, int timeout, CameraEventType *eventtype, void **eventdata, GPContext *context) { struct timeval event_start; CameraFilePath *path; pslr_handle_t p = &camera->pl->pslr; int ret, length; CameraFile *file = NULL; CameraFileInfo info; gp_log (GP_LOG_DEBUG, "pentax", "camera_wait_for_event %d ms", timeout); *eventtype = GP_EVENT_TIMEOUT; *eventdata = NULL; if (camera->pl->lastfn) { path = malloc(sizeof(CameraFilePath)); strcpy (path->folder, "/"); strcpy (path->name, camera->pl->lastfn); free (camera->pl->lastfn); camera->pl->lastfn = NULL; *eventtype = GP_EVENT_FILE_ADDED; *eventdata = path; return GP_OK; } gettimeofday (&event_start, 0); while (1) { pslr_status status; int i, bufno; const char *mimes[2]; int buftypes[2], jpegres[2], nrofdownloads = 1; char *fns[2]; if (PSLR_OK != pslr_get_status (&camera->pl->pslr, &status)) break; if (status.bufmask == 0) goto next; gp_log (GP_LOG_ERROR, "pentax", "wait_for_event: new image found! mask 0x%x", status.bufmask); /* New image on camera! */ for (bufno=0;bufno<16;bufno++) if (status.bufmask & (1<folder, "/"); gp_log (GP_LOG_ERROR, "pentax", "wait_for_event: imageformat %d / rawformat %d", status.image_format, status.raw_format); switch (status.image_format) { case PSLR_IMAGE_FORMAT_JPEG: sprintf (path->name, "capt%04d.jpg", camera->pl->capcnt++); mimes[0] = GP_MIME_JPEG; buftypes[0] = status.jpeg_quality + 1; jpegres[0] = status.jpeg_resolution; fns[0] = strdup (path->name); break; case PSLR_IMAGE_FORMAT_RAW_PLUS: /* FIXME: the same as _RAW ? */ mimes[1] = GP_MIME_JPEG; buftypes[1] = status.jpeg_quality + 1; jpegres[1] = status.jpeg_resolution; nrofdownloads = 2; sprintf (path->name, "capt%04d.jpg", camera->pl->capcnt); fns[1] = strdup (path->name); /* we pass back the secondary file via the private struct, and return the first */ camera->pl->lastfn = strdup (fns[1]); /* FALLTHROUGH */ case PSLR_IMAGE_FORMAT_RAW: jpegres[0] = 0; switch (status.raw_format) { case PSLR_RAW_FORMAT_PEF: sprintf (path->name, "capt%04d.pef", camera->pl->capcnt++); fns[0] = strdup (path->name); mimes[0] = GP_MIME_RAW; buftypes[0] = PSLR_BUF_PEF; break; case PSLR_RAW_FORMAT_DNG: sprintf (path->name, "capt%04d.dng", camera->pl->capcnt++); fns[0] = strdup (path->name); mimes[0] = "image/x-adobe-dng"; buftypes[0] = PSLR_BUF_DNG; break; default: gp_log (GP_LOG_ERROR, "pentax", "unknown format image=0x%x, raw=0x%x", status.image_format, status.raw_format); return GP_ERROR; } break; default: gp_log (GP_LOG_ERROR, "pentax", "unknown format image=0x%x (raw=0x%x)", status.image_format, status.raw_format); return GP_ERROR; } for (i = 0; i < nrofdownloads; i++) { ret = gp_file_new(&file); if (ret!=GP_OK) return ret; gp_file_set_mtime (file, time(NULL)); gp_file_set_mime_type (file, mimes[i]); while (1) { length = save_buffer( p, bufno, buftypes[i], jpegres[i], file); if (length == GP_ERROR_NOT_SUPPORTED) return length; if (length >= GP_OK) break; usleep(100000); } gp_log (GP_LOG_DEBUG, "pentax", "append image to fs"); ret = gp_filesystem_append(camera->fs, path->folder, fns[i], context); if (ret != GP_OK) { gp_file_free (file); return ret; } gp_log (GP_LOG_DEBUG, "pentax", "adding filedata to fs"); ret = gp_filesystem_set_file_noop(camera->fs, path->folder, fns[i], GP_FILE_TYPE_NORMAL, file, context); if (ret != GP_OK) { gp_file_free (file); return ret; } /* We have now handed over the file, disclaim responsibility by unref. */ gp_file_unref (file); memset (&info, 0, sizeof (info)); /* we also get the fs info for free, so just set it */ info.file.fields = GP_FILE_INFO_TYPE | GP_FILE_INFO_SIZE | GP_FILE_INFO_MTIME; strcpy (info.file.type, GP_MIME_JPEG); info.file.size = length; info.file.mtime = time(NULL); info.preview.fields = 0; gp_log (GP_LOG_DEBUG, "pentax", "setting fileinfo in fs"); ret = gp_filesystem_set_info_noop(camera->fs, path->folder, fns[i], info, context); free (fns[i]); } pslr_delete_buffer (p, bufno); pslr_get_status (&camera->pl->pslr, &status); /* wait until busy is gone */ *eventtype = GP_EVENT_FILE_ADDED; *eventdata = path; return GP_OK; next: if (_timeout_passed (&event_start, timeout)) break; usleep(100*1000); /* 100 ms */ } return GP_OK; } static int camera_get_config (Camera *camera, CameraWidget **window, GPContext *context) { CameraWidget *t, *section; const char *model; pslr_status status; char buf[20]; int *available_resolutions; int i, ival; float fval; pslr_get_status (&camera->pl->pslr, &status); model = pslr_camera_name (&camera->pl->pslr); available_resolutions = pslr_get_model_jpeg_resolutions (&camera->pl->pslr); gp_log (GP_LOG_DEBUG, "pentax", "*** camera_get_config"); gp_widget_new (GP_WIDGET_WINDOW, _("Camera and Driver Configuration"), window); gp_widget_set_name (*window, "main"); gp_widget_new (GP_WIDGET_SECTION, _("Camera Settings"), §ion); gp_widget_set_name (section, "settings"); gp_widget_append (*window, section); gp_widget_new (GP_WIDGET_TEXT, _("Model"), &t); gp_widget_set_name (t, "model"); gp_widget_set_value (t, model); gp_widget_set_readonly (t, 1); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RADIO, _("Image Format"), &t); gp_widget_set_name (t, "imageformat"); /* it seems the upstream code seems to have it always available? */ gp_widget_add_choice (t, "JPEG"); gp_widget_add_choice (t, "RAW"); gp_widget_add_choice (t, "RAW+JPEG"); switch (status.image_format) { case PSLR_IMAGE_FORMAT_JPEG: gp_widget_set_value (t, "JPEG"); break; case PSLR_IMAGE_FORMAT_RAW: gp_widget_set_value (t, "RAW"); break; case PSLR_IMAGE_FORMAT_RAW_PLUS: gp_widget_set_value (t, "RAW+"); break; default: sprintf(buf, _("Unknown format %d"), status.image_format); gp_widget_set_value (t, buf); break; } gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RADIO, _("Image Size"), &t); gp_widget_set_name (t, "imgsize"); for (i = 0; i < MAX_RESOLUTION_SIZE && available_resolutions[i]; i++) { char buf[20]; sprintf(buf,"%d", available_resolutions[i]); gp_widget_add_choice (t, buf); } if (status.jpeg_resolution > 0 && status.jpeg_resolution < MAX_RESOLUTION_SIZE) { char buf[20]; sprintf(buf, "%d", status.jpeg_resolution); gp_widget_set_value (t, buf); } else gp_widget_set_value (t, _("Unknown")); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RADIO, _("Image Quality"), &t); gp_widget_set_name (t, "imagequality"); gp_widget_add_choice (t, "4"); gp_widget_add_choice (t, "3"); gp_widget_add_choice (t, "2"); gp_widget_add_choice (t, "1"); sprintf (buf,"%d",status.jpeg_quality); gp_widget_set_value (t, buf); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RADIO, _("ISO"), &t); gp_widget_set_name (t, "iso"); gp_widget_add_choice (t, "100"); gp_widget_add_choice (t, "200"); gp_widget_add_choice (t, "400"); gp_widget_add_choice (t, "800"); gp_widget_add_choice (t, "1600"); gp_widget_add_choice (t, "3200"); sprintf(buf,"%d",status.current_iso); gp_widget_set_value (t, buf); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TEXT, _("Shutter Speed"), &t); gp_widget_set_name (t, "shutterspeed"); sprintf(buf,"%d/%d",status.current_shutter_speed.nom,status.current_shutter_speed.denom); gp_widget_set_value (t, buf); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TEXT, _("Aperture"), &t); gp_widget_set_name (t, "aperture"); if (status.current_aperture.denom == 1) { sprintf(buf,"%d",status.current_aperture.nom); } else if (status.current_aperture.denom == 10) { if (status.current_aperture.nom % 10 == 0) sprintf(buf,"%d",status.current_aperture.nom/10); else sprintf(buf,"%d.%d",status.current_aperture.nom/10,status.current_aperture.nom%10); } else { sprintf(buf,"%d/%d",status.current_aperture.nom,status.current_aperture.denom); } gp_widget_set_value (t, buf); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TEXT, _("Aperture at Lens Minimum Focal Length"), &t); gp_widget_set_name (t, "apertureatminfocallength"); if (status.lens_min_aperture.denom == 1) { sprintf(buf,"%d",status.lens_min_aperture.nom); } else if (status.lens_min_aperture.denom == 10) { if (status.lens_min_aperture.nom % 10 == 0) sprintf(buf,"%d",status.lens_min_aperture.nom/10); else sprintf(buf,"%d.%d",status.lens_min_aperture.nom/10,status.lens_min_aperture.nom%10); } else { sprintf(buf,"%d/%d",status.lens_min_aperture.nom,status.lens_min_aperture.denom); } gp_widget_set_value (t, buf); gp_widget_set_readonly (t, 1); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TEXT, _("Aperture at Lens Maximum Focal Length"), &t); gp_widget_set_name (t, "apertureatmaxfocallength"); if (status.lens_max_aperture.denom == 1) { sprintf(buf,"%d",status.lens_max_aperture.nom); } else if (status.lens_max_aperture.denom == 10) { if (status.lens_max_aperture.nom % 10 == 0) sprintf(buf,"%d",status.lens_max_aperture.nom/10); else sprintf(buf,"%d.%d",status.lens_max_aperture.nom/10,status.lens_max_aperture.nom%10); } else { sprintf(buf,"%d/%d",status.lens_max_aperture.nom,status.lens_max_aperture.denom); } gp_widget_set_value (t, buf); gp_widget_set_readonly (t, 1); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TEXT, _("Zoom"), &t); gp_widget_set_name (t, "zoom"); sprintf(buf,"%d/%d",status.zoom.nom,status.zoom.denom); gp_widget_set_value (t, buf); gp_widget_set_readonly (t, 1); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RANGE, _("Exposure Compensation"), &t); gp_widget_set_name (t, "exposurecompensation"); fval = 1.0*status.ec.nom/status.ec.denom; gp_widget_set_range (t, -3.0, 3.0, (status.custom_ev_steps == PSLR_CUSTOM_EV_STEPS_1_2)? 0.5:0.333333); gp_widget_set_value (t, &fval); gp_widget_append (section, t); gp_widget_new (GP_WIDGET_RADIO, _("Shooting Mode"), &t); gp_widget_set_name (t, "shootingmode"); gp_widget_add_choice (t, _("GREEN")); gp_widget_add_choice (t, _("P")); gp_widget_add_choice (t, _("SV")); gp_widget_add_choice (t, _("TV")); gp_widget_add_choice (t, _("AV")); gp_widget_add_choice (t, _("TAV")); gp_widget_add_choice (t, _("M")); gp_widget_add_choice (t, _("B")); gp_widget_add_choice (t, _("X")); switch (status.exposure_mode) { case PSLR_GUI_EXPOSURE_MODE_GREEN: gp_widget_set_value (t, _("GREEN"));break; case PSLR_GUI_EXPOSURE_MODE_M: gp_widget_set_value (t, _("M"));break; case PSLR_GUI_EXPOSURE_MODE_P: gp_widget_set_value (t, _("P"));break; case PSLR_GUI_EXPOSURE_MODE_AV: gp_widget_set_value (t, _("AV"));break; case PSLR_GUI_EXPOSURE_MODE_TV: gp_widget_set_value (t, _("TV"));break; case PSLR_GUI_EXPOSURE_MODE_SV: gp_widget_set_value (t, _("SV"));break; case PSLR_GUI_EXPOSURE_MODE_TAV: gp_widget_set_value (t, _("TAV"));break; case PSLR_GUI_EXPOSURE_MODE_X: gp_widget_set_value (t, _("X"));break; case PSLR_GUI_EXPOSURE_MODE_B: gp_widget_set_value (t, _("B"));break; default: sprintf(buf, _("Unknown mode %d"), status.exposure_mode); gp_widget_set_value (t, buf); break; } gp_widget_append (section, t); gp_widget_new (GP_WIDGET_TOGGLE, _("Bulb"), &t); gp_widget_set_name (t, "bulb"); ival = 2; gp_widget_set_value (t, &ival); gp_widget_append (section, t); return GP_OK; } static int camera_set_config (Camera *camera, CameraWidget *window, GPContext *context) { CameraWidget *w = NULL; char *sval; pslr_status status; int ret; pslr_get_status(&camera->pl->pslr, &status); gp_log (GP_LOG_DEBUG, "pentax", "*** camera_set_config"); ret = gp_widget_get_child_by_label (window, _("Image Size"), &w); if ((ret == GP_OK) && (gp_widget_changed (w))) { int i, resolution = -1; int *valid_resolutions; gp_widget_set_changed (w, 0); valid_resolutions = pslr_get_model_jpeg_resolutions (&camera->pl->pslr); gp_widget_get_value (w, &sval); for (i = 0; i < MAX_RESOLUTION_SIZE; i++) { int foo; sscanf(sval, "%d", &foo); if (foo != valid_resolutions[i]) resolution = i; } if (resolution == -1) { gp_log (GP_LOG_ERROR, "pentax", "Could not decode image size %s", sval); } else { pslr_set_jpeg_resolution(&camera->pl->pslr, resolution); pslr_get_status(&camera->pl->pslr, &status); } } ret = gp_widget_get_child_by_label (window, _("Shooting Mode"), &w); if ((ret == GP_OK) && gp_widget_changed (w)) { pslr_gui_exposure_mode_t exposuremode; gp_widget_set_changed (w, 0); gp_widget_get_value (w, &sval); exposuremode = PSLR_GUI_EXPOSURE_MODE_MAX; if (!strcmp(sval,_("GREEN"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_GREEN; if (!strcmp(sval,_("M"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_M; if (!strcmp(sval,_("B"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_B; if (!strcmp(sval,_("P"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_P; if (!strcmp(sval,_("SV"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_SV; if (!strcmp(sval,_("TV"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_TV; if (!strcmp(sval,_("AV"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_AV; if (!strcmp(sval,_("TAV"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_TAV; if (!strcmp(sval,_("X"))) exposuremode = PSLR_GUI_EXPOSURE_MODE_TAV; if (exposuremode != PSLR_GUI_EXPOSURE_MODE_MAX) { pslr_set_exposure_mode(&camera->pl->pslr, exposuremode); pslr_get_status(&camera->pl->pslr, &status); } else { gp_log (GP_LOG_ERROR, "pentax", "Could not decode exposuremode %s", sval); } } ret = gp_widget_get_child_by_label (window, _("ISO"), &w); if ((ret == GP_OK) && gp_widget_changed (w)) { int iso; gp_widget_set_changed (w, 0); gp_widget_get_value (w, &sval); if (sscanf(sval, "%d", &iso)) { /* pslr_set_iso(&camera->pl->pslr, iso); */ pslr_set_iso(&camera->pl->pslr, iso, 0, 0); /* FIXME: check if 0 is ok */ pslr_get_status(&camera->pl->pslr, &status); // FIXME: K-30 iso doesn't get updated immediately } else gp_log (GP_LOG_ERROR, "pentax", "Could not decode iso %s", sval); } gp_widget_get_child_by_label (window, _("Exposure Compensation"), &w); if (gp_widget_changed (w)) { float fval; pslr_rational_t rational; gp_widget_get_value (w, &fval); rational.denom = 10; rational.nom = (int)(10 * fval); pslr_set_ec (&camera->pl->pslr, rational); } gp_widget_get_child_by_label (window, _("Image Quality"), &w); if (gp_widget_changed (w)) { int qual; /* FIXME: decoding is strange. the UI shows number of stars * on k20d: 4 stars = 3, 3 stars = 0, 2 stars = 1, 1 star = 2 */ gp_widget_set_changed (w, 0); gp_widget_get_value (w, &sval); if (sscanf(sval, "%d", &qual)) { pslr_set_jpeg_stars (&camera->pl->pslr, qual); pslr_get_status (&camera->pl->pslr, &status); } else gp_log (GP_LOG_ERROR, "pentax", "Could not decode image quality %s", sval); } ret = gp_widget_get_child_by_label (window, _("Shutter Speed"), &w); if ((ret == GP_OK) && gp_widget_changed (w)) { pslr_rational_t speed; gp_widget_set_changed (w, 0); gp_widget_get_value (w, &sval); if (sscanf(sval, "%d/%d", &speed.nom, &speed.denom)) { pslr_set_shutter(&camera->pl->pslr, speed); pslr_get_status(&camera->pl->pslr, &status); } else { char c; if (sscanf(sval, "%d%c", &speed.nom, &c) && (c=='s')) { speed.denom = 1; pslr_set_shutter(&camera->pl->pslr, speed); pslr_get_status(&camera->pl->pslr, &status); } else { gp_log (GP_LOG_ERROR, "pentax", "Could not decode shutterspeed %s", sval); } } /* parse more? */ } ret = gp_widget_get_child_by_label (window, _("Aperture"), &w); if ((ret == GP_OK) && gp_widget_changed (w)) { pslr_rational_t aperture; int apt1,apt2; gp_widget_set_changed (w, 0); gp_widget_get_value (w, &sval); if (sscanf(sval, "%d.%d", &apt1, &apt2)) { if (apt1<11) { aperture.nom = apt1*10+apt2; aperture.denom = 10; } else { /* apt2 not in use */ aperture.nom = apt1; aperture.denom = 1; } pslr_set_aperture(&camera->pl->pslr, aperture); pslr_get_status(&camera->pl->pslr, &status); } else if (sscanf(sval, "%d", &apt1)) { if (apt1<11) { aperture.nom = apt1*10; aperture.denom = 10; } else { aperture.nom = apt1; aperture.denom = 1; } pslr_set_aperture(&camera->pl->pslr, aperture); pslr_get_status(&camera->pl->pslr, &status); } else { gp_log (GP_LOG_ERROR, "pentax", "Could not decode aperture %s", sval); } } ret = gp_widget_get_child_by_label (window, _("Bulb"), &w); if ((ret == GP_OK) && gp_widget_changed (w)) { int bulb; if (status.exposure_mode != PSLR_GUI_EXPOSURE_MODE_B) { gp_context_error (context, _("You need to switch the shooting mode or the camera to 'B' for bulb exposure.")); return GP_ERROR; } gp_widget_set_changed (w, 0); gp_widget_get_value (w, &bulb); pslr_bulb (&camera->pl->pslr, bulb); if (bulb) /* also press the shutter */ pslr_shutter (&camera->pl->pslr); } return GP_OK; } static int camera_exit (Camera *camera, GPContext *context) { pslr_disconnect (&camera->pl->pslr); free (camera->pl); return GP_OK; } char ** get_drives(int *driveNum) { /* should not be called */ return NULL; } pslr_result get_drive_info(char* driveName, FDTYPE* hDevice, char* vendorId, int vendorIdSizeMax, char* productId, int productIdSizeMax) { /* should not be called */ return PSLR_NO_MEMORY; } int camera_init (Camera *camera, GPContext *context) { CameraPrivateLibrary *cpl; cpl = calloc (sizeof (CameraPrivateLibrary), 1); /* pslr = pslr_init (model, device); ... but it basically just opens the fd */ cpl->pslr.fd = camera->port; camera->pl = cpl; pslr_connect (&cpl->pslr); camera->functions->exit = camera_exit; camera->functions->summary = camera_summary; camera->functions->get_config = camera_get_config; camera->functions->set_config = camera_set_config; camera->functions->capture = camera_capture; camera->functions->trigger_capture = camera_trigger_capture; camera->functions->wait_for_event = camera_wait_for_event; return gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera); }