1 /* library.c for libgphoto2/camlibs/digigr8
3 * Copyright (C) 2005 - 2010 Theodore Kilgore <kilgota@auburn.edu>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
31 #include <gphoto2/gphoto2.h>
36 # define _(String) dgettext (PACKAGE, String)
38 # define N_(String) gettext_noop (String)
40 # define N_(String) (String)
43 # define _(String) (String)
44 # define N_(String) (String)
49 #include <gphoto2/gphoto2-port.h>
51 #define GP_MODULE "digigr8"
55 CameraDriverStatus status;
56 unsigned short idVendor;
57 unsigned short idProduct;
59 {"Digigr8", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
60 {"Che-Ez Snap SNAP-U", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
61 {"DC-N130t", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905C},
62 {"Soundstar TDC-35", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
63 {"Nexxtech Mini Digital Camera", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770,
65 {"Vivitar Vivicam35", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
66 {"Praktica Slimpix", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
67 {"ZINA Mini Digital Keychain Camera", GP_DRIVER_STATUS_EXPERIMENTAL,
69 {"Pixie Princess Jelly-Soft", GP_DRIVER_STATUS_EXPERIMENTAL,
71 {"Sakar Micro Digital 2428x", GP_DRIVER_STATUS_EXPERIMENTAL,
73 {"Stop & Shop 87096", GP_DRIVER_STATUS_EXPERIMENTAL,
75 {"Jazz JDC9", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x905c},
76 {"Disney pix micro", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x9050},
77 {"Lego Bionicle", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x9051},
78 /* from IRC reporter, adam@piggz.co.uk */
79 {"Disney pix micro 2", GP_DRIVER_STATUS_EXPERIMENTAL, 0x2770, 0x9052},
80 {"Suprema Digital Keychain Camera", GP_DRIVER_STATUS_EXPERIMENTAL,
82 {"Sakar 28290 and 28292 Digital Concepts Styleshot",
83 GP_DRIVER_STATUS_EXPERIMENTAL,
85 {"Sakar 23070 Crayola Digital Camera", GP_DRIVER_STATUS_EXPERIMENTAL,
87 {"Sakar 92045 Spiderman", GP_DRIVER_STATUS_EXPERIMENTAL,
93 camera_id (CameraText *id)
95 strncpy (id->text, "SQ905C chipset camera",32);
101 camera_abilities (CameraAbilitiesList *list)
106 for (i = 0; models[i].name; i++) {
107 memset (&a, 0, sizeof(a));
108 strncpy (a.model, models[i].name,32);
109 a.status = models[i].status;
110 a.port = GP_PORT_USB;
112 a.usb_vendor = models[i].idVendor;
113 a.usb_product= models[i].idProduct;
114 if (a.status == GP_DRIVER_STATUS_EXPERIMENTAL)
115 a.operations = GP_OPERATION_NONE;
117 a.operations = GP_OPERATION_CAPTURE_PREVIEW;
118 a.folder_operations = GP_FOLDER_OPERATION_DELETE_ALL;
119 a.file_operations = GP_FILE_OPERATION_PREVIEW
120 + GP_FILE_OPERATION_RAW;
121 gp_abilities_list_append (list, a);
127 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
129 if(!camera->pl->init_done)
130 digi_init (camera->port, camera->pl);
131 snprintf (summary->text, 100,
132 ("Your USB camera seems to have an SQ905C chipset.\n"
133 "The total number of pictures in it is %i\n"),
134 camera->pl->nb_entries);
138 static int camera_manual(Camera *camera, CameraText *manual,
141 strncpy(manual->text,
143 "For cameras with insides from S&Q Technologies, which have the \n"
144 "USB Vendor ID 0x2770 and Product ID 0x905C, 0x9050, 0x9051,\n"
145 "0x9052, or 0x913D. Photos are saved in PPM format.\n\n"
146 "Some of these cameras allow software deletion of all photos.\n"
147 "Others do not. No supported camera can do capture-image. All\n"
148 "can do capture-preview (image captured and sent to computer).\n"
149 "If delete-all does work for your camera, then capture-preview will\n"
150 "have the side-effect that it also deletes what is on the camera.\n\n"
151 "File uploading is not supported for these cameras. Also, none of the\n"
152 "supported cameras allow deletion of individual photos by use of a\n"
153 "software command.\n"
160 camera_about (Camera *camera, CameraText *about, GPContext *context)
162 strncpy (about->text, _("sq905C generic driver\n"
163 "Theodore Kilgore <kilgota@auburn.edu>\n"),64);
167 /*************** File and Downloading Functions *******************/
171 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
172 void *data, GPContext *context)
174 Camera *camera = data;
176 if(!camera->pl->init_done)
177 digi_init (camera->port, camera->pl);
178 GP_DEBUG ("List files in %s\n", folder);
179 n = camera->pl->nb_entries;
180 gp_list_populate(list, "pict%03i.ppm", n);
186 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
187 CameraFileType type, CameraFile *file, void *user_data,
191 Camera *camera = user_data;
194 unsigned char comp_ratio;
195 unsigned char lighting;
196 unsigned char *data = NULL;
197 unsigned char *p_data = NULL;
200 unsigned char gtable[256];
203 if(!camera->pl->init_done)
204 digi_init (camera->port, camera->pl);
206 /* Get the entry number of the photo on the camera */
207 k = gp_filesystem_number (camera->fs, "/", filename, context);
209 if (GP_FILE_TYPE_EXIF ==type) return GP_ERROR_FILE_EXISTS;
211 if (GP_FILE_TYPE_RAW!=type && GP_FILE_TYPE_NORMAL
212 !=type && GP_FILE_TYPE_PREVIEW!=type) {
213 return GP_ERROR_NOT_SUPPORTED;
216 next = camera->pl->last_fetched_entry +1;
218 b = digi_get_data_size (camera->pl, next);
220 if(!data) return GP_ERROR_NO_MEMORY;
221 digi_read_picture_data (camera->port, data, b, next);
226 comp_ratio = digi_get_comp_ratio (camera->pl, k);
227 w = digi_get_picture_width (camera->pl, k);
229 case 176: h = 144; break;
230 case 640: h = 480; break;
231 case 320: h = 240; break;
232 default: h = 288; break;
234 lighting = camera->pl->catalog[k*0x10+0x0b];
235 b = digi_get_data_size (camera->pl, k);
237 GP_DEBUG("Photo number %i deleted?\n",k+1);
238 camera->pl->last_fetched_entry = k;
242 if(!data) return GP_ERROR_NO_MEMORY;
244 GP_DEBUG("Fetch entry %i\n", k);
245 digi_read_picture_data (camera->port, data, b, k);
246 camera->pl->last_fetched_entry = k;
248 if (GP_FILE_TYPE_RAW == type) { /* type is GP_FILE_TYPE_RAW */
250 gp_file_set_mime_type (file, GP_MIME_RAW);
251 gp_file_set_name (file, filename);
252 gp_file_append(file, (char *)data, size);
253 /* Save photo's catalog entry as a footer for the raw file */
254 gp_file_append(file, (char *)camera->pl->catalog + k*0x10, 0x10);
255 /* Reset camera when done, for more graceful exit. */
256 if (k +1 == camera->pl->nb_entries) {
257 digi_rewind (camera->port, camera->pl);
264 * Now put the data into a PPM image file.
267 ppm = malloc (w * h * 3 + 256); /* room for data + header */
269 status = GP_ERROR_NO_MEMORY;
272 snprintf ((char *)ppm, 64,
274 "# CREATOR: gphoto2, SQ905C library\n"
277 size = strlen ((char *)ppm);
279 size = size + (w * h * 3);
280 GP_DEBUG ("size = %i\n", size);
281 p_data = malloc( w*h );
283 status = GP_ERROR_NO_MEMORY;
287 digi_decompress (p_data, data, w, h);
289 memcpy(p_data, data, w*h);
290 gp_ahd_decode (p_data, w , h , ptr, BAYER_TILE_BGGR);
292 digi_postprocess (w, h, ptr);
293 if (lighting < 0x40) {
295 "Low light condition. Using default gamma. \
296 No white balance.\n");
297 gp_gamma_fill_table (gtable, .65);
298 gp_gamma_correct_single(gtable,ptr,w*h);
300 white_balance (ptr, w*h, 1.1);
301 gp_file_set_mime_type (file, GP_MIME_PPM);
302 gp_file_set_name (file, filename);
303 gp_file_set_data_and_size (file, (char *)ppm, size);
304 /* Reset camera when done, for more graceful exit. */
305 if (k +1 == camera->pl->nb_entries) {
306 digi_rewind (camera->port, camera->pl);
314 delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
317 Camera *camera = data;
318 if(!camera->pl->delete_all)
319 return GP_ERROR_NOT_SUPPORTED;
320 if(!camera->pl->init_done)
321 digi_init (camera->port, camera->pl);
322 digi_delete_all (camera->port, camera->pl);
327 camera_capture_preview (Camera *camera, CameraFile *file, GPContext *context)
330 unsigned char get_size[0x50];
331 unsigned char *raw_data;
332 unsigned char *frame_data;
333 unsigned char *ppm, *ptr;
335 unsigned char gtable[256];
336 char filename[14] = "digi_cap.ppm";
342 digi_reset (camera->port);
343 gp_port_usb_msg_write (camera->port, 0x0c, 0x1440, 0x110f, NULL, 0);
344 gp_port_read(camera->port, (char *)get_size, 0x50);
345 GP_DEBUG("get_size[0x40] = 0x%x\n", get_size[0x40]);
346 lighting = get_size[0x48];
347 b = get_size[0x40] | get_size[0x41] << 8 | get_size[0x42] << 16
348 | get_size[0x43]<<24;
349 GP_DEBUG("b = 0x%x\n", b);
350 raw_data = malloc(b);
353 return GP_ERROR_NO_MEMORY;
355 if (!((gp_port_read(camera->port, (char *)raw_data, b)==b))) {
356 GP_DEBUG("Error in reading data\n");
359 frame_data = malloc(w*h);
362 return GP_ERROR_NO_MEMORY;
364 digi_decompress (frame_data, raw_data, w, h);
366 /* Now put the data into a PPM image file. */
367 ppm = malloc (w * h * 3 + 256);
369 return GP_ERROR_NO_MEMORY;
370 snprintf ((char *)ppm, 64,
372 "# CREATOR: gphoto2, SQ905C library\n"
375 ptr = ppm + strlen ((char*)ppm);
376 size = strlen ((char*)ppm) + (w * h * 3);
377 GP_DEBUG ("size = %i\n", size);
378 gp_ahd_decode (frame_data, w , h , ptr, BAYER_TILE_BGGR);
380 if (lighting < 0x40) {
382 "Low light condition. Default gamma. No white balance.\n");
383 gp_gamma_fill_table (gtable, .65);
384 gp_gamma_correct_single(gtable,ptr,w*h);
386 white_balance (ptr, w*h, 1.1);
387 gp_file_set_mime_type (file, GP_MIME_PPM);
388 gp_file_set_name (file, filename);
389 gp_file_set_data_and_size (file, (char *)ppm, size);
390 digi_reset(camera->port);
394 /*************** Exit and Initialization Functions ******************/
397 camera_exit (Camera *camera, GPContext *context)
399 GP_DEBUG ("SQ camera_exit");
400 digi_reset (camera->port);
403 free (camera->pl->catalog);
410 static CameraFilesystemFuncs fsfuncs = {
411 .file_list_func = file_list_func,
412 .get_file_func = get_file_func,
413 .delete_all_func = delete_all_func
417 camera_init(Camera *camera, GPContext *context)
419 GPPortSettings settings;
420 CameraAbilities abilities;
423 ret = gp_camera_get_abilities(camera,&abilities);
424 if (ret < 0) return ret;
425 GP_DEBUG("product number is 0x%x\n", abilities.usb_product);
427 /* Now, set up all the function pointers */
428 camera->functions->summary = camera_summary;
429 camera->functions->manual = camera_manual;
430 camera->functions->about = camera_about;
431 camera->functions->capture_preview
432 = camera_capture_preview;
433 camera->functions->exit = camera_exit;
435 GP_DEBUG ("Initializing the camera\n");
437 ret = gp_port_get_settings(camera->port,&settings);
440 ret = gp_port_set_settings(camera->port,settings);
444 /* Tell the CameraFilesystem where to get lists from */
445 gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
446 camera->pl = malloc (sizeof (CameraPrivateLibrary));
448 return GP_ERROR_NO_MEMORY;
449 camera->pl->catalog = NULL;
450 camera->pl->nb_entries = 0;
451 switch (abilities.usb_product) {
455 camera->pl->delete_all = 1;
458 camera->pl->delete_all = 0;
460 camera->pl->init_done=0;
462 /* Do digi_init() only if needed for the requested operation. */