1 /* library.c
2 *
3 * Copyright (C) 2006 Theodore Kilgore <kilgota@auburn.edu>
4 *
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.
9 *
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.
14 *
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., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
19 */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <bayer.h>
28 #include <gamma.h>
29
30 #include <gphoto2/gphoto2.h>
31
32
33
34 #ifdef ENABLE_NLS
35 # include <libintl.h>
36 # undef _
37 # define _(String) dgettext (PACKAGE, String)
38 # ifdef gettext_noop
39 # define N_(String) gettext_noop (String)
40 # else
41 # define N_(String) (String)
42 # endif
43 #else
44 # define _(String) (String)
45 # define N_(String) (String)
46 #endif
47
48 #include "jl2005a.h"
49 #include <gphoto2/gphoto2-port.h>
50
51 #define GP_MODULE "jl2005a"
52
53 struct {
54 char *name;
55 CameraDriverStatus status;
56 unsigned short idVendor;
57 unsigned short idProduct;
58 } models[] = {
59 {"American Idol Keychain Camera", GP_DRIVER_STATUS_TESTING,
60 0x0979, 0x0224},
61 {"NogaNet TDC-15", GP_DRIVER_STATUS_TESTING, 0x0979, 0x0224},
62 {"Cobra DC125", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0224},
63 {NULL,0,0,0}
64 };
65
66 int
camera_id(CameraText * id)67 camera_id (CameraText *id)
68 {
69 strcpy (id->text, "JL2005A camera");
70 return GP_OK;
71 }
72
73 int
camera_abilities(CameraAbilitiesList * list)74 camera_abilities (CameraAbilitiesList *list)
75 {
76 int i;
77 CameraAbilities a;
78
79 for (i = 0; models[i].name; i++) {
80 memset (&a, 0, sizeof(a));
81 strcpy (a.model, models[i].name);
82 a.status = models[i].status;
83 a.port = GP_PORT_USB;
84 a.speed[0] = 0;
85 a.usb_vendor = models[i].idVendor;
86 a.usb_product= models[i].idProduct;
87 if (a.status == GP_DRIVER_STATUS_EXPERIMENTAL)
88 a.operations = GP_OPERATION_NONE;
89 else
90 a.operations = GP_OPERATION_CAPTURE_IMAGE;
91 a.folder_operations = GP_FOLDER_OPERATION_NONE;
92 a.file_operations = GP_FILE_OPERATION_PREVIEW
93 + GP_FILE_OPERATION_RAW;
94 gp_abilities_list_append (list, a);
95 }
96 return GP_OK;
97 }
98
99 static int
camera_summary(Camera * camera,CameraText * summary,GPContext * context)100 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
101 {
102 int num_pics;
103 num_pics = camera->pl->nb_entries;
104 GP_DEBUG("camera->pl->nb_entries = %i\n",camera->pl->nb_entries);
105 sprintf (summary->text,_("This camera contains a Jeilin JL2005A chipset.\n"
106 "The number of photos in it is %i. \n"), num_pics);
107 return GP_OK;
108 }
109
110
camera_manual(Camera * camera,CameraText * manual,GPContext * context)111 static int camera_manual (Camera *camera, CameraText *manual, GPContext *context)
112 {
113 strcpy(manual->text,
114 _(
115 "This driver supports cameras with Jeilin jl2005a chip \n"
116 "These cameras do not support deletion of photos, nor uploading\n"
117 "of data. \n"
118 "Decoding of compressed photos may or may not work well\n"
119 "and does not work equally well for all supported cameras.\n"
120 "If present on the camera, video clip frames are downloaded \n"
121 "as consecutive still photos.\n"
122 "For further details please consult libgphoto2/camlibs/README.jl2005a\n"
123 ));
124
125 return (GP_OK);
126 }
127
128
129 static int
camera_about(Camera * camera,CameraText * about,GPContext * context)130 camera_about (Camera *camera, CameraText *about, GPContext *context)
131 {
132 strcpy (about->text, _("jl2005a camera library\n"
133 "Theodore Kilgore <kilgota@auburn.edu>\n"));
134 return GP_OK;
135 }
136
137 /*************** File and Downloading Functions *******************/
138
139 static int
file_list_func(CameraFilesystem * fs,const char * folder,CameraList * list,void * data,GPContext * context)140 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
141 void *data, GPContext *context)
142 {
143 Camera *camera = data;
144 int n;
145 n = camera->pl->nb_entries;
146 gp_list_populate (list, "jl_%03i.ppm", n);
147 return GP_OK;
148 }
149
150 static int
get_info_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileInfo * info,void * data,GPContext * context)151 get_info_func (CameraFilesystem *fs, const char *folder, const char *filename,
152 CameraFileInfo *info, void *data, GPContext *context)
153 {
154 info->file.fields = GP_FILE_INFO_TYPE;
155 strcpy (info->file.type, GP_MIME_PPM);
156
157 return (GP_OK);
158 }
159
160 static int
get_file_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileType type,CameraFile * file,void * user_data,GPContext * context)161 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
162 CameraFileType type, CameraFile *file, void *user_data,
163 GPContext *context)
164 {
165 Camera *camera = user_data;
166 int status = GP_OK;
167 unsigned int w, h = 0;
168 unsigned int i, j;
169 int k;
170 unsigned int b = 0;
171 int compressed = 0;
172 unsigned char header[5] = "\xff\xff\xff\xff\x55";
173 unsigned int size;
174 unsigned char *data;
175 unsigned char *image_start;
176 unsigned char *p_data=NULL;
177 unsigned char *ppm=NULL, *ptr=NULL;
178 unsigned char gtable[256];
179 unsigned char temp;
180
181 GP_DEBUG ("Downloading pictures!\n");
182
183 /* These are cheap cameras. There ain't no EXIF data. So kill this. */
184 if (GP_FILE_TYPE_EXIF == type) return GP_ERROR_FILE_EXISTS;
185 /* Get the number of the photo on the camera */
186 k = gp_filesystem_number (camera->fs, "/", filename, context);
187 GP_DEBUG ("Filesystem number is %i\n",k);
188 b = jl2005a_get_pic_data_size(camera->port, k);
189 GP_DEBUG("b = %i = 0x%x bytes\n", b,b);
190 w = jl2005a_get_pic_width(camera->port);
191 GP_DEBUG ("width is %i\n", w);
192 h = jl2005a_get_pic_height(camera->port);
193 GP_DEBUG ("height is %i\n", h);
194
195 /* sanity check against bad usb devices */
196 if ((w ==0) || (w > 1024) || (h == 0) || (h > 1024)) {
197 GP_DEBUG ("width / height not within sensible range");
198 return GP_ERROR_CORRUPTED_DATA;
199 }
200
201 if (b < w*h+5) {
202 GP_DEBUG ("b is %i, while w*h+5 is %i\n", b, w*h+5);
203 return GP_ERROR_CORRUPTED_DATA;
204 }
205
206 /* Image data to be downloaded contains header and footer bytes */
207 data = malloc (b+14);
208 if (!data) return GP_ERROR_NO_MEMORY;
209
210 jl2005a_read_picture_data (camera, camera->port, data, b+14);
211 if (memcmp(header,data,5) != 0)
212 /* Image data is corrupted! Repeat the operation. */
213 jl2005a_read_picture_data (camera, camera->port, data, b+14);
214
215 if (GP_FILE_TYPE_RAW == type) {
216 gp_file_set_mime_type(file, GP_MIME_RAW);
217 gp_file_set_data_and_size(file, (char *)data , b+14 );
218 return GP_OK;
219 }
220
221 /* Now get ready to put the data into a PPM image file. */
222 image_start=data+5;
223 if (w == 176) {
224 for (i=1; i < h-1; i +=4){
225 for (j=1; j< w; j ++){
226 temp=image_start[i*w+j];
227 image_start[i*w+j] = image_start[(i+1)*w+j];
228 image_start[(i+1)*w+j] = temp;
229 }
230 }
231 if (h == 72) {
232 compressed = 1;
233 h = 144;
234 }
235 } else
236 if (h == 144) {
237 compressed = 1;
238 h = 288;
239 }
240
241 /* sanity check the sizes, as the ahd bayer algorithm does not like very small height / width */
242 if ((h < 72) || (w < 176)) {
243 status = GP_ERROR_CORRUPTED_DATA;
244 goto end;
245 }
246 p_data = malloc( w*h );
247 if (!p_data) {
248 status = GP_ERROR_NO_MEMORY;
249 goto end;
250 }
251 if (compressed) {
252 /* compressed seems to mean half the lines */
253 if (w/2*h > b+14) {
254 free(p_data);
255 status = GP_ERROR_CORRUPTED_DATA;
256 goto end;
257 }
258 jl2005a_decompress (image_start, p_data, w, h);
259 } else {
260 if (w*h > b+14) {
261 free(p_data);
262 status = GP_ERROR_CORRUPTED_DATA;
263 goto end;
264 }
265 memcpy(p_data, image_start, w*h);
266 }
267 ppm = malloc (w * h * 3 + 256); /* room for data and header */
268 if (!ppm) {
269 free(p_data);
270 status = GP_ERROR_NO_MEMORY;
271 goto end;
272 }
273 sprintf ((char *)ppm,
274 "P6\n"
275 "# CREATOR: gphoto2, JL2005A library\n"
276 "%d %d\n"
277 "255\n", w, h);
278 size = strlen ((char *)ppm);
279 ptr = ppm + size;
280 size = size + (w * h * 3);
281 GP_DEBUG ("size = %i, w = %d, h = %d\n", size, w,h );
282 gp_ahd_decode (p_data, w , h, ptr, BAYER_TILE_BGGR);
283
284 free(p_data);
285 gp_gamma_fill_table (gtable, .65);
286 gp_gamma_correct_single (gtable, ptr, w * h);
287 gp_file_set_mime_type (file, GP_MIME_PPM);
288 gp_file_set_data_and_size (file, (char *)ppm, size);
289 end:
290 free(data);
291 return status;
292 }
293
294
295 /*************** Exit and Initialization Functions ******************/
296
297 static int
camera_exit(Camera * camera,GPContext * context)298 camera_exit (Camera *camera, GPContext *context)
299 {
300 GP_DEBUG ("jl2005a camera_exit");
301 jl2005a_reset(camera, camera->port);
302 gp_port_close(camera->port);
303 if (camera->pl) {
304 free (camera->pl);
305 camera->pl = NULL;
306 }
307 return GP_OK;
308 }
309
310 static CameraFilesystemFuncs fsfuncs = {
311 .file_list_func = file_list_func,
312 .get_file_func = get_file_func,
313 .get_info_func = get_info_func
314 };
315
316 int
camera_init(Camera * camera,GPContext * context)317 camera_init(Camera *camera, GPContext *context)
318 {
319 GPPortSettings settings;
320 int ret = 0;
321
322 /* First, set up all the function pointers */
323 camera->functions->manual = camera_manual;
324 camera->functions->summary = camera_summary;
325 camera->functions->about = camera_about;
326 camera->functions->exit = camera_exit;
327
328 GP_DEBUG ("Initializing the camera\n");
329 ret = gp_port_get_settings(camera->port,&settings);
330 if (ret < 0) return ret;
331
332 switch (camera->port->type) {
333 case GP_PORT_SERIAL:
334 return ( GP_ERROR );
335 case GP_PORT_USB:
336 settings.usb.config = 1;
337 settings.usb.altsetting = 0;
338 settings.usb.interface = 0;
339 /* inep 0x84 used for commands, 0x81 for data. */
340 settings.usb.inep = 0x84;
341 settings.usb.outep = 0x03;
342 break;
343 default:
344 return ( GP_ERROR );
345 }
346
347 ret = gp_port_set_settings(camera->port,settings);
348 if (ret < 0) return ret;
349
350 GP_DEBUG("interface = %i\n", settings.usb.interface);
351 GP_DEBUG("inep = %x\n", settings.usb.inep);
352 GP_DEBUG("outep = %x\n", settings.usb.outep);
353
354 /* Tell the CameraFilesystem where to get lists from */
355 gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
356
357 camera->pl = malloc (sizeof (CameraPrivateLibrary));
358 if (!camera->pl) return GP_ERROR_NO_MEMORY;
359 memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
360 /* Connect to the camera */
361 camera->pl->data_reg_accessed = 0;
362 camera->pl->data_to_read = 0;
363 camera->pl->data_used_from_block = 0;
364 camera->pl->data_cache = NULL;
365 jl2005a_init (camera,camera->port, camera->pl);
366
367 return GP_OK;
368 }
369