/* pdc640.c * * Copyright © 2001 Lutz Müller * Copyright © 2002 Marcus Meissner * * 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 */ #include "config.h" #include #include #include #include #include #include #include "jd350e.h" #include "dlink350f.h" #define GP_MODULE "pdc640" #define PDC640_PING "\x01" #define PDC640_SPEED "\x69\x0b" #define PDC640_MAXTRIES 3 #define CHECK_RESULT(result) {int __r = (result); if (__r < 0) return (__r);} #ifdef ENABLE_NLS # include # 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 typedef enum{ pdc640, jd350e, dlink350f } Model; typedef int postproc_func(int,int,unsigned char*); struct _CameraPrivateLibrary{ Model model; BayerTile bayer_tile; postproc_func* postprocessor; char* filespec; }; static int flip_vertical (int width, int height, unsigned char *rgb); static int flip_both (int width, int height, unsigned char *rgb); static struct { const char* model; int vendor,product; struct _CameraPrivateLibrary pl; } models[] = { {"Polaroid Fun Flash 640", 0, 0, { pdc640, BAYER_TILE_RGGB, NULL, /* add postprocessor here! */ "pdc640%04i.ppm" } }, {"Novatech Digital Camera CC30", 0, 0, { pdc640, BAYER_TILE_RGGB, NULL, /* add postprocessor here! */ "pdc640%04i.ppm" } }, {"Jenoptik JD350 entrance", 0x5da, 0x1006, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing, "jd350e%04i.ppm" } }, {"Jenoptik JD350 video", 0xd96, 0x0000, { jd350e, BAYER_TILE_BGGR, NULL /*&jd350e_postprocessing*/, "jd350v%04i.ppm" } }, {"ScanHex SX-35a", 0x797, 0x8901, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing, "jd350v%04i.ppm" } }, {"ScanHex SX-35b", 0x797, 0x8909, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing, "jd350v%04i.ppm" } }, {"ScanHex SX-35c", 0x797, 0x8911, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing, "jd350v%04i.ppm" } }, {"ScanHex SX-35d", 0x84d, 0x1001, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing, "jd350v%04i.ppm" } }, {"Typhoon StyloCam", 0x797, 0x801a, { jd350e, BAYER_TILE_BGGR, &flip_vertical, "stylo%04i.ppm" } }, {"Trust PowerC@m 350FS", 0x6d6, 0x002e, { jd350e, BAYER_TILE_RGGB, &trust350fs_postprocessing, "trust%04i.ppm" } }, {"Trust PowerC@m 350FT", 0x6d6, 0x002d, { jd350e, BAYER_TILE_RGGB, &trust350fs_postprocessing, "trust%04i.ppm" } }, {"Clever CAM 360", 0x797, 0x8001, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing_and_flip, "scope%04i.ppm" } }, /* http://www.meade.com/sportsoptics/catalog/captureview/index.html */ {"GrandTek ScopeCam", 0x797, 0x801c, { jd350e, BAYER_TILE_BGGR, &jd350e_postprocessing_and_flip, "scope%04i.ppm" } }, /* http://www.sipixdigital.com/cameras/stylecam/ */ /* Ids glanced from downloaded driver / .inf file. */ {"SiPix Stylecam", 0xd64, 0x1001, { jd350e, BAYER_TILE_BGGR, &flip_both, "style%04i.ppm" } }, /* http://www.umax.de/digicam/AstraPix320S.htm */ /* reportedly has same ids as SiPix StyleCam and also * looks identical. */ {"UMAX AstraPix 320s", 0xd64, 0x1001, { jd350e, BAYER_TILE_BGGR, &flip_both, "astra%04i.ppm" } }, /* http://www.dlink.com/products/usb/dsc350/ */ /* ids from driver download */ {"D-Link DSC 350F", 0xd64, 0x1021, { dlink350f, BAYER_TILE_BGGR, &dlink_dsc350f_postprocessing_and_flip_both, "dlink%04i.ppm" } }, {NULL,} }; static int pdc640_read_packet (GPPort *port, unsigned char *buf, int buf_size) { int i; char checksum, c; /* Calculate the checksum */ for (i = 0, checksum = 0; i < buf_size; i++) buf[i] = 0; /* Read the packet */ CHECK_RESULT (gp_port_read (port, (char*)buf, buf_size)); /* Calculate the checksum */ for (i = 0, checksum = 0; i < buf_size; i++) checksum += buf[i]; /* Read the checksum */ CHECK_RESULT (gp_port_read (port, &c, 1)); GP_DEBUG ("Checksum: %d calculated, %d received", checksum, c); if (checksum != c) return (GP_ERROR_CORRUPTED_DATA); return (GP_OK); } static int pdc640_transmit (GPPort *port, unsigned char *cmd, int cmd_size, unsigned char *buf, int buf_size) { int r, tries; if (port->type == GP_PORT_USB) { unsigned char xbuf[64]; unsigned char xcmd[4]; int checksum; /* USB has always just 3 bytes + 1 byte checksum */ memset(xcmd,0,4);memcpy(xcmd,cmd,cmd_size); checksum = (xcmd[0]^0x34)+(xcmd[1]^0xcb)+0x14f+(xcmd[2]^0x67); xcmd[3] = checksum & 0xff; /* Wait until we get back the echo of the command. */ r = gp_port_usb_msg_read( port, 0x10, xcmd[0]|(xcmd[1]<<8),xcmd[2]|(xcmd[3]<<8),(char*)xbuf,sizeof(xbuf)); /* Sometimes we want to read here, sometimes not. if (r < GP_OK) return r; */ if (buf && buf_size) { /* bulk read things. The JD350v can read in 1 block, * the Stylocam returns only 64byte blocks here. */ int curr = 0, readsize = (buf_size + 63) & ~63; while (curr < readsize) { r = gp_port_read( port, (char*)buf + curr, readsize - curr); if (r < GP_OK) break; curr += r; } } return r; } else { char c; /* In event of a checksum or timing failure, retry */ for (tries = 0; tries < PDC640_MAXTRIES; tries++) { /* * The first byte returned is always the same as the first byte * of the command. */ CHECK_RESULT (gp_port_write (port, (char*)cmd, cmd_size)); r = gp_port_read (port, &c, 1); if ((r < 0) || (c != cmd[0])) continue; if (buf) { r = pdc640_read_packet (port, buf, buf_size); if (r < 0) continue; } return (GP_OK); } return (GP_ERROR_CORRUPTED_DATA); } } static int pdc640_transmit_pic (GPPort *port, char cmd, int width, int thumbnail, unsigned char *buf, int buf_size) { unsigned char cmd1[] = {0x61, 0x00}; unsigned char cmd2[] = {0x15, 0x00, 0x00, 0x00, 0x00}; /* First send the command ... */ cmd1[1] = cmd; CHECK_RESULT (pdc640_transmit (port, cmd1, 2, NULL, 0)); if (port->type == GP_PORT_USB) { cmd2[1] = (buf_size + 63) >> 6; cmd2[2] = ((buf_size + 63) >> 6) >> 8; return pdc640_transmit (port, cmd2, 4, buf, buf_size); } else { int i, packet_size, result, size, ofs; unsigned char *data; /* Set how many scanlines worth of data to get at once */ cmd2[4] = 0x06; /* Packet size is a multiple of the image width */ packet_size = width * cmd2[4]; /* Allocate memory to temporarily store received data */ data = malloc (packet_size); if (!data) return (GP_ERROR_NO_MEMORY); /* Now get the packets */ ofs = 0; result = GP_OK; for (i = 0; i < buf_size; i += packet_size) { /* Read the packet */ result = pdc640_transmit (port, cmd2, 5, data, packet_size); if (result < 0) break; /* Copy from temp buffer -> actual */ size = packet_size; if (size > buf_size - i) size = buf_size - i; memcpy(buf + i, data, size); /* Move to next offset */ ofs += cmd2[4]; cmd2[2] = ofs & 0xFF; cmd2[1] = (ofs >> 8) & 0xFF; } free (data); return (result); } } static int pdc640_transmit_packet (GPPort *port, char cmd, unsigned char *buf, int buf_size) { unsigned char cmd1[] = {0x61, 0x00}; /* Send the command and get the packet */ cmd1[1] = cmd; CHECK_RESULT (pdc640_transmit (port, cmd1, 2, NULL, 0)); if (port->type == GP_PORT_USB) { unsigned char cmd2[] = {0x15, 0x00, 0x00, 0x00}; cmd2[1] = ((buf_size+63)/64) & 0xff; cmd2[2] = (((buf_size+63)/64) >> 8) & 0xff; return pdc640_transmit (port, cmd2, 4, buf, buf_size); } else { unsigned char cmd2[] = {0x15, 0x00, 0x00, 0x00, 0x01}; return pdc640_transmit (port, cmd2, 5, buf, buf_size); } } static int pdc640_ping_low (GPPort *port) { unsigned char cmd[] = {0x01}; CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0)); return (GP_OK); } #if 0 static int pdc640_push_button (GPPort *port) { char cmd[] = {0xfd}; CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0)); return (GP_OK); } #endif static int pdc640_ping_high (GPPort *port) { unsigned char cmd[] = {0x41}; CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0)); return (GP_OK); } static int pdc640_speed (GPPort *port, int speed) { unsigned char cmd[] = {0x69, 0x00}; cmd[1] = (speed / 9600) - 1; CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0)); return (GP_OK); } #if 0 /* read version I think */ static int pdc640_unknown5 (GPPort *port) { char cmd[] = {0x05}; char buf[3]; CHECK_RESULT (pdc640_transmit (port, cmd, 1, buf, 3)); if ((buf[0] != 0x33) || (buf[1] != 0x02) || (buf[2] != 0x35)) return (GP_ERROR_CORRUPTED_DATA); return (GP_OK); } #endif #if 0 /* get calibration param */ static int pdc640_unknown20 (GPPort* port) { unsigned char buf[128]; CHECK_RESULT (pdc640_transmit_packet (port, 0x20, buf, 128)); return (GP_OK); } #endif static int pdc640_caminfo (GPPort *port, int *numpic) { unsigned char buf[1280]; CHECK_RESULT (pdc640_transmit_packet (port, 0x40, buf, 1280)); *numpic = buf[2]; /* thats the only useful info :( */ return (GP_OK); } static int pdc640_setpic (GPPort *port, char n) { unsigned char cmd[2] = {0xf6, 0x00}; cmd[1] = n; if (port->type == GP_PORT_USB) { /* USB does not like a bulkread afterwards */ return pdc640_transmit (port, cmd, 2, NULL, 0); } else { unsigned char buf[8]; return pdc640_transmit (port, cmd, 2, buf, 7); } } static int pdc640_picinfo (GPPort *port, char n, int *size_pic, int *width_pic, int *height_pic, int *size_thumb, int *width_thumb, int *height_thumb, int *compression_type ) { unsigned char buf[64]; CHECK_RESULT (pdc640_setpic (port, n)); CHECK_RESULT (pdc640_transmit_packet (port, 0x80, buf, 32)); /* Check image number matches */ if (buf[0] != n) return (GP_ERROR_CORRUPTED_DATA); /* Picture size, width and height */ *size_pic = buf[2] | (buf[3] << 8) | (buf[4] << 16); *width_pic = buf[5] | (buf[6] << 8); *height_pic = buf[7] | (buf[8] << 8); /* Compression Type */ *compression_type = buf[9]; *size_thumb = buf[25] | (buf[26] << 8) | (buf[27] << 16); *width_thumb = buf[28] | (buf[29] << 8); *height_thumb = buf[30] | (buf[31] << 8); /* Even though it should the be the correct size, the Typhoon * Stylocam returns junk in there. So calculate for ourselves. */ if (*size_thumb > *width_thumb * *height_thumb) *size_thumb = *width_thumb * *height_thumb; return (GP_OK); } static int pdc640_processtn (int width, int height, unsigned char **data, int size) { unsigned char *newdata; int y; /* Sanity checks */ if ((data == NULL) || (size < width * height)) return (GP_ERROR_CORRUPTED_DATA); /* Allocate a new buffer */ newdata = malloc(size); if (!newdata) return (GP_ERROR_NO_MEMORY); /* Flip the thumbnail */ for (y = 0; y < height; y++) { memcpy(&newdata[(height - y - 1) * width], &((*data)[y * width]), width); } /* Set new buffer */ free (*data); *data = newdata; return (GP_OK); } static int pdc640_getbit (unsigned char *data, int *ofs, int size, int *bit) { static char c; int b; /* Check if next byte required */ if (*bit == 0) { if (*ofs >= size) return (-1); c = data[*ofs]; (*ofs)++; } /* Get current bit value */ b = (c >> *bit) & 1; /* Then move onto the next bit */ (*bit)++; if (*bit >= 8) *bit = 0; return (b); } static int pdc640_deltadecode (int width, int height, unsigned char **rawdata, int *rawsize) { char col1, col2; unsigned char *data; int rawofs, x, y, ofs, bit, ones; int size; int e, d, o, val; GP_DEBUG ("pdc640_deltacode ()"); /* Create a buffer to store RGB data in */ size = width * height; data = malloc (size * sizeof (char)); if (!data) return (GP_ERROR_NO_MEMORY); /* Delta decode scanline by scanline */ rawofs = 0; for (y = height-1; y >= 0; y--) { /* Word alignment */ if (rawofs & 1) rawofs++; /* Sanity check */ if (rawofs >= *rawsize) { free (data); return (GP_ERROR_CORRUPTED_DATA); } /* Offset into the uncompressed data */ ofs = y * width; /* Get the first two pixel values */ col1 = (*rawdata)[rawofs]; col2 = (*rawdata)[rawofs + 1]; rawofs += 2; data[ofs + 0] = col1 << 1; data[ofs + 1] = col2 << 1; /* Work out the remaining pixels */ bit = 0; for (x = 2; x < width; x++) { /* Count number of ones */ ones = 0; while (pdc640_getbit(*rawdata, &rawofs, *rawsize, &bit) == 1) ones++; /* * Get the delta value * (size dictated by number of ones) */ val = 0; for (o = 0, e = 0, d = 1; o < ones; o++, d <<= 1) { e = pdc640_getbit(*rawdata, &rawofs, *rawsize, &bit); if (e == 1) val += d; } if (e == 0) val += 1 - d; /* adjust for negatives */ /* Adjust the corresponding pixel value */ if (x & 1) val = (col2 += val); else val = (col1 += val); data[ofs + x] = val << 1; } } /* Set new buffer */ free (*rawdata); *rawdata = data; *rawsize = size; return (GP_OK); } static int pdc640_getpic (Camera *camera, int n, int thumbnail, int justraw, unsigned char **data, int *size) { char cmd, ppmheader[100]; int size_pic, width_pic, height_pic; int size_thumb, width_thumb, height_thumb; int height, width, outsize, result, pmmhdr_len; int compression_type; unsigned char *outdata; /* Get the size of the picture */ CHECK_RESULT (pdc640_picinfo (camera->port, n, &size_pic, &width_pic, &height_pic, &size_thumb, &width_thumb, &height_thumb, &compression_type)); /* Evaluate parameters */ if (thumbnail) { GP_DEBUG ("Size %d, width %d, height %d, comptype %d", size_thumb, width_thumb, height_thumb, (compression_type>>2) & 3); *size = size_thumb; width = width_thumb; height = height_thumb; if ((compression_type >> 2) & 3) cmd = 0x02; else cmd = 0x03; } else { GP_DEBUG ("Size %d, width %d, height %d, comptype %d", size_pic, width_pic, height_pic, compression_type & 3); *size = size_pic; width = width_pic; height = height_pic; switch (compression_type & 3) { case 1: case 2: cmd = 0x10; /* delta compressed */ break; case 0: cmd = 0x00; /* uncompressed */ break; default: /* unknown compression type */ GP_DEBUG ("Unknown compression type %d", compression_type & 3); return (GP_ERROR_CORRUPTED_DATA); } } /* Sanity check */ if ((*size <= 0) || (width <= 0) || (height <= 0)) return (GP_ERROR_CORRUPTED_DATA); /* Allocate the memory, including 64byte align */ *data = malloc ((*size + 64) * sizeof (char)); if (!*data) return (GP_ERROR_NO_MEMORY); /* Get the raw picture */ CHECK_RESULT (pdc640_setpic (camera->port, n)); CHECK_RESULT (pdc640_transmit_pic (camera->port, cmd, width, thumbnail, *data, *size)); if (thumbnail || (compression_type == 0 )) { /* Process uncompressed data */ CHECK_RESULT (pdc640_processtn (width, height, data, *size)); } else if (compression_type & 3) { /* Image data is delta encoded so decode it */ CHECK_RESULT (pdc640_deltadecode (width, height, data, size)); } /* Just wanted the raw camera data */ if (justraw) return(GP_OK); GP_DEBUG ("Bayer decode..."); sprintf (ppmheader, "P6\n" "# CREATOR: gphoto2, pdc640/jd350e library\n" "%d %d\n" "255\n", width, height); /* Allocate memory for Interpolated ppm image */ pmmhdr_len = strlen(ppmheader); outsize = width * height * 3 + pmmhdr_len + 1; outdata = malloc(outsize); if (!outdata) return (GP_ERROR_NO_MEMORY); /* Set header */ strcpy((char *)outdata, ppmheader); /* Decode and interpolate the Bayer Mask */ result = gp_bayer_decode(*data, width, height, &outdata[pmmhdr_len], camera->pl->bayer_tile ); if (result < 0) { free (outdata); return (result); } /* Call a specific postprocessor if available*/ if( camera->pl->postprocessor ){ result = camera->pl->postprocessor(width,height,&outdata[pmmhdr_len]); if (result < 0) { free (outdata); return (result); } } /* Fix up data pointers */ free (*data); *data = outdata; *size = outsize; return (GP_OK); } static int pdc640_delpic (GPPort *port) { unsigned char cmd[2] = {0x59, 0x01}; CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0)); return (GP_OK); } static int pdc640_takepic (GPPort *port) { unsigned char cmd[2] = {0x2D, 0x00}; CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0)); return (GP_OK); } int camera_id (CameraText *id) { strcpy (id->text, "pdc640/jd350e"); return (GP_OK); } int camera_abilities (CameraAbilitiesList *list) { int i; CameraAbilities a; for (i = 0; models[i].model; i++) { memset(&a, 0, sizeof(a)); strcpy (a.model, models[i].model); if (models[i].vendor) { a.status = GP_DRIVER_STATUS_TESTING; a.port = GP_PORT_USB | GP_PORT_SERIAL; a.usb_vendor = models[i].vendor; a.usb_product = models[i].product; a.speed[0] = 0; } else { a.status = GP_DRIVER_STATUS_EXPERIMENTAL; a.port = GP_PORT_SERIAL; a.speed[0] = 0; } a.operations = GP_OPERATION_CAPTURE_IMAGE; a.file_operations = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_PREVIEW; a.folder_operations = GP_FOLDER_OPERATION_NONE; CHECK_RESULT (gp_abilities_list_append (list, a)); } 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, size; unsigned char *data; /* * Get the number of the picture from the filesystem and increment * since we need a range starting with 1. */ CHECK_RESULT (n = gp_filesystem_number (camera->fs, folder, filename, context)); n++; /* Get the picture */ switch (type) { case GP_FILE_TYPE_NORMAL: CHECK_RESULT (pdc640_getpic (camera, n, 0, 0, &data, &size)); CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_PPM)); break; case GP_FILE_TYPE_RAW: CHECK_RESULT (pdc640_getpic (camera, n, 0, 1, &data, &size)); CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_RAW)); break; case GP_FILE_TYPE_PREVIEW: CHECK_RESULT (pdc640_getpic (camera, n, 1, 0, &data, &size)); CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_PPM)); break; default: return (GP_ERROR_NOT_SUPPORTED); } CHECK_RESULT (gp_file_set_data_and_size (file, (char*)data, size)); return (GP_OK); } static int delete_all_func (CameraFilesystem *fs, const char *folder, void *data, GPContext *context) { Camera *camera = data; unsigned char cmd[2] = {0x59, 0x00}; CHECK_RESULT (pdc640_transmit (camera->port, cmd, 2, NULL, 0)); return (GP_OK); } static int delete_file_func (CameraFilesystem *fs, const char *folder, const char *file, void *data, GPContext *context) { Camera *camera = data; int n, count; /* We can only delete the last picture */ CHECK_RESULT (n = gp_filesystem_number (camera->fs, folder, file, context)); n++; CHECK_RESULT (pdc640_caminfo (camera->port, &count)); if (count != n) return (GP_ERROR_NOT_SUPPORTED); CHECK_RESULT (pdc640_delpic (camera->port)); return (GP_OK); } static int camera_about (Camera *camera, CameraText *about, GPContext *context) { strcpy (about->text, _("Download program for GrandTek 98x based cameras. " "Originally written by Chris Byrne , " "and adapted for gphoto2 by Lutz Mueller " "." "Protocol enhancements and postprocessing " "for Jenoptik JD350e by Michael Trawny " ". " "Bugfixes by Marcus Meissner .")); return (GP_OK); } static int camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path, GPContext *context) { int num, numpic; if (type != GP_CAPTURE_IMAGE) return (GP_ERROR_NOT_SUPPORTED); /* First get the current number of images */ CHECK_RESULT (pdc640_caminfo (camera->port, &numpic)); /* Take a picture */ CHECK_RESULT (pdc640_takepic (camera->port)); /* Wait a bit for the camera */ sleep(4); /* Picture will be the last one in the camera */ CHECK_RESULT (pdc640_caminfo (camera->port, &num)); if (num <= numpic) return (GP_ERROR); /* Set the filename */ sprintf (path->name, camera->pl->filespec, num); strcpy (path->folder, "/"); CHECK_RESULT (gp_filesystem_append (camera->fs, "/", path->name, context)); return (GP_OK); } static int file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, void *data, GPContext *context) { int n; Camera *camera = data; /* Fill the list */ CHECK_RESULT (pdc640_caminfo (camera->port, &n)); CHECK_RESULT (gp_list_populate (list, camera->pl->filespec, n)); return (GP_OK); } static int get_info_func (CameraFilesystem *fs, const char *folder, const char *file, CameraFileInfo *info, void *data, GPContext *context) { Camera *camera = data; int n, dummy; int size_pic, size_thumb; int width_pic, width_thumb, height_pic, height_thumb; CHECK_RESULT (n = gp_filesystem_number (fs, folder, file, context)); n++; CHECK_RESULT (pdc640_picinfo (camera->port, n, &size_pic, &width_pic, &height_pic, &size_thumb, &width_thumb, &height_thumb, &dummy )); info->file.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE; info->file.width = width_pic; info->file.height = height_pic; /* info->file.size = size_pic; */ info->file.size = width_pic * height_pic * 3; strcpy (info->file.type, GP_MIME_PPM); info->preview.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE; info->preview.width = width_thumb; info->preview.height = height_thumb; info->preview.size = size_thumb * 3; strcpy (info->preview.type, GP_MIME_PPM); return (GP_OK); } static int camera_exit (Camera *camera, GPContext *context) { if (camera->pl) { free (camera->pl); camera->pl = NULL; } return (GP_OK); } static CameraFilesystemFuncs fsfuncs = { .file_list_func = file_list_func, .get_info_func = get_info_func, .get_file_func = get_file_func, .del_file_func = delete_file_func, .delete_all_func = delete_all_func, }; int camera_init (Camera *camera, GPContext *context) { int result, i; GPPortSettings settings; CameraAbilities abilities; /* * First of all, tell gphoto2 about the functions we * implement (especially camera_exit so that everything * gets correctly cleaned up even in case of error). */ camera->functions->about = camera_about; camera->functions->capture = camera_capture; camera->functions->exit = camera_exit; CHECK_RESULT (gp_camera_get_abilities(camera,&abilities) ); camera->pl = 0; for( i=0; models[i].model; i++ ){ if (!strcmp(models[i].model, abilities.model)) { GP_DEBUG ("Model: %s", abilities.model); camera->pl = malloc( sizeof(struct _CameraPrivateLibrary) ); if( camera->pl ){ *(camera->pl) = models[i].pl; break; } else{ return (GP_ERROR_NO_MEMORY); } } } if( ! camera->pl ){ return (GP_ERROR_NOT_SUPPORTED); } /* Tell the filesystem where to get lists and info */ CHECK_RESULT (gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera)); if (camera->port->type == GP_PORT_SERIAL) { /* Open the port */ CHECK_RESULT (gp_port_get_settings (camera->port, &settings)); settings.serial.speed = 9600; CHECK_RESULT (gp_port_set_settings (camera->port, settings)); /* Start with a low timeout (so we don't have to wait if already initialized) */ CHECK_RESULT (gp_port_set_timeout (camera->port, 1000)); /* Is the camera at 9600? */ result = pdc640_ping_low (camera->port); if (result == GP_OK) CHECK_RESULT (pdc640_speed (camera->port, 115200)); /* Switch to 115200 */ settings.serial.speed = 115200; CHECK_RESULT (gp_port_set_settings (camera->port, settings)); /* Is the camera at 115200? */ CHECK_RESULT (pdc640_ping_high (camera->port)); /* Switch to a higher timeout */ CHECK_RESULT (gp_port_set_timeout (camera->port, 5000)); } return (GP_OK); } static int flip_both (int width, int height, unsigned char *rgb) { unsigned char *end, c; end = rgb + ((width * height) * 3); while (rgb < end) { c = *rgb; *rgb++ = *--end; *end = c; } return GP_OK; } static int flip_vertical (int width, int height, unsigned char* rgb) { int i; unsigned char *buf; buf = malloc(width*3); if (!buf) return GP_ERROR_NO_MEMORY; for (i=0;i