Source code upload
[framework/connectivity/libgphoto2.git] / camlibs / aox / library.c
1 /* library.c
2  *
3  * Copyright (C) 2003 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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, 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 #ifdef ENABLE_NLS
33 #  include <libintl.h>
34 #  undef _
35 #  define _(String) dgettext (PACKAGE, String)
36 #  ifdef gettext_noop
37 #    define N_(String) gettext_noop (String)
38 #  else
39 #    define N_(String) (String)
40 #  endif
41 #else
42 #  define _(String) (String)
43 #  define N_(String) (String)
44 #endif
45
46 #include "aox.h"
47 #include <gphoto2/gphoto2-port.h>
48
49 #define GP_MODULE "aox"
50
51 struct _CameraPrivateLibrary {
52         Model model;
53         Info info[2];
54 };
55
56 static struct {
57         char *name;
58         CameraDriverStatus status;
59         unsigned short idVendor;
60         unsigned short idProduct;
61 } models[] = {
62         {"Concord EyeQMini_1", GP_DRIVER_STATUS_EXPERIMENTAL, 0x03e8, 0x2182},
63         {"Concord EyeQMini_2", GP_DRIVER_STATUS_EXPERIMENTAL, 0x03e8, 0x2180},
64         {"D-MAX DM3588", GP_DRIVER_STATUS_EXPERIMENTAL, 0x03e8, 0x2130},        
65         {NULL,0,0,0}
66 };
67
68 int
69 camera_id (CameraText *id)
70 {
71         strcpy (id->text, "Aox chipset camera");
72         return GP_OK;
73 }
74
75 int
76 camera_abilities (CameraAbilitiesList *list)
77 {
78         int i;    
79         CameraAbilities a;
80
81         for (i = 0; models[i].name; i++) {
82                 memset (&a, 0, sizeof(a));
83                 strcpy (a.model, models[i].name);
84                 a.status = models[i].status;
85                 a.port   = GP_PORT_USB;
86                 a.speed[0] = 0;
87                 a.usb_vendor = models[i].idVendor;
88                 a.usb_product= models[i].idProduct;
89                 if (a.status == GP_DRIVER_STATUS_EXPERIMENTAL)
90                         a.operations = GP_OPERATION_NONE;
91                 else
92                         a.operations = GP_OPERATION_CAPTURE_IMAGE;
93                 a.folder_operations = GP_FOLDER_OPERATION_NONE;
94                 a.file_operations   = GP_FILE_OPERATION_PREVIEW; 
95                 gp_abilities_list_append (list, a);
96         }
97         return GP_OK;
98 }
99
100 static int
101 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
102 {
103
104         int num_lo_pics =aox_get_num_lo_pics(camera->pl->info);
105         int num_hi_pics =aox_get_num_hi_pics(camera->pl->info); 
106
107         sprintf (summary->text,_("Your USB camera has an Aox chipset.\n" 
108                         "Number of lo-res PICs = %i\n"
109                         "Number of hi-res PICs = %i\n"  
110                         "Number of PICs = %i\n"
111                         ), num_lo_pics, num_hi_pics, num_lo_pics+num_hi_pics);  
112
113         return GP_OK;
114 }
115
116
117 static int
118 camera_about (Camera *camera, CameraText *about, GPContext *context)
119 {
120         strcpy (about->text, _("Aox generic driver\n"
121                             "Theodore Kilgore <kilgota@auburn.edu>\n"));
122         return GP_OK;
123 }
124
125 /*************** File and Downloading Functions *******************/
126
127 static int
128 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
129                 void *data, GPContext *context)
130 {
131         Camera *camera = data; 
132         int num_lo_pics = aox_get_num_lo_pics (camera->pl->info);
133         int num_hi_pics = aox_get_num_hi_pics (camera->pl->info);
134         int n = num_hi_pics + num_lo_pics;
135         char name[20];
136         int i;  
137         /* Low-resolution pictures are always downloaded first. We do not know 
138          * yet how to process them, so they will remain in RAW format. */
139         
140         for (i=0; i< num_lo_pics; i++){
141                 snprintf( name, sizeof(name), "aox_pic%03i.raw", i+1 );
142                 gp_list_append(list, name, NULL);       
143         }
144
145         for (i = num_lo_pics; i < n; i++){
146                 snprintf( name, sizeof(name), "aox_pic%03i.ppm", i+1 );         
147                 gp_list_append(list, name, NULL);       
148         }
149         return GP_OK;
150 }
151
152 static int
153 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
154                CameraFileType type, CameraFile *file, void *user_data,
155                GPContext *context)
156 {
157         Camera *camera = user_data; 
158
159 /* The camera will always download the low-resolution pictures first, if any.
160  * As those are compressed, they are not of fixed size. Unfortunately, the 
161  * compression method is not known. 
162  * For a high-resolution picture, the size is always the same. 
163  * Every picture file has a header, which is of length 0x98. The high-
164  * resolution pictures are just Bayer data; their headers will be discarded.  
165  */
166
167         int i, j, k, n, num_lo_pics, num_hi_pics, w = 0, h = 0;         
168         unsigned char temp;
169         unsigned char *data;
170         unsigned char *p_data = NULL;
171         unsigned char *output = NULL;     
172         int len;
173         int header_len;
174         char header[128];       
175         unsigned char gtable[256];
176
177         k = gp_filesystem_number(camera->fs, "/", filename, context);
178
179
180         num_lo_pics = aox_get_num_lo_pics(camera->pl->info);
181         num_hi_pics = aox_get_num_hi_pics(camera->pl->info);
182
183
184         GP_DEBUG("There are %i compressed photos\n", num_lo_pics);
185         GP_DEBUG("There are %i hi-res photos\n", num_hi_pics);
186
187         if ( (k < num_lo_pics) ) { 
188                 n = k; 
189                 w = 320;
190                 h = 240;
191         } else {
192                 n = k - num_lo_pics;
193                 w = 640;        
194                 h = 480;
195         }
196
197         len = aox_get_picture_size (camera->port, num_lo_pics, 
198                                                 num_hi_pics, n, k);
199         GP_DEBUG("len = %i\n", len);
200         data = malloc(len);
201         if (!data) {
202                 printf("Malloc failed\n"); return 0;}
203         aox_read_picture_data (camera->port, (char *)data, len, n);
204
205         switch (type) {
206         case GP_FILE_TYPE_EXIF:
207                 return (GP_ERROR_FILE_EXISTS);
208
209         case GP_FILE_TYPE_PREVIEW:
210         case GP_FILE_TYPE_NORMAL:
211                 if ((w == 320)) {
212                         gp_file_detect_mime_type (file); /* Detected as "raw"*/
213                         gp_file_set_data_and_size (file, (char *)data, len);
214                         gp_file_adjust_name_for_mime_type (file);
215                 }
216                 if ((w == 640)){
217                         /* Stripping useless header */
218                         p_data = data + 0x98;
219                         /* Picture is mirror-imaged.*/
220                         for (i = 0; i < h; ++i) {
221                                 for (j = 0 ; j < w/2; j++) { 
222                                         temp = p_data[w*i +j];
223                                         p_data[w*i +j] = p_data[w*i+ w -1 -j];
224                                         p_data[w*i + w  - 1 - j] = temp;
225                                 }
226                         }       
227                         /* Not only this, but some columns are 
228                          * interchanged, too. */
229                         for (i = 0; i < w*h/4; i++) {
230                                 temp = p_data[4*i +1];
231                                 p_data[4*i + 1] = p_data[4*i+2];
232                                 p_data[4*i+2] = temp;
233                         }
234                         /* And now create a ppm file, with our own header */
235                         header_len = snprintf(header, 127, 
236                                 "P6\n" 
237                                 "# CREATOR: gphoto2, aox library\n" 
238                                 "%d %d\n" 
239                                 "255\n", w, h);
240
241                         output = malloc(3*w*h);
242                         if(!output) {
243                                 free(output);
244                                 return GP_ERROR_NO_MEMORY;
245                         }       
246                         if (camera->pl->model == AOX_MODEL_DMAX)
247                             gp_bayer_decode (p_data, w, h, 
248                                         output, BAYER_TILE_RGGB);
249                         else
250                             gp_bayer_decode (p_data, w, h, 
251                                         output, BAYER_TILE_GRBG);
252                         /* gamma correction of .70 may not be optimal. */
253                         gp_gamma_fill_table (gtable, .65);
254                         gp_gamma_correct_single (gtable, output, w * h);
255                         gp_file_set_mime_type (file, GP_MIME_PPM);
256                         gp_file_append (file, header, header_len);
257                         gp_file_append (file, (char *)output, 3*w*h);
258                 }
259                 free (output);
260                 return GP_OK;
261         case GP_FILE_TYPE_RAW:
262                 gp_file_set_data_and_size (file, (char *)data, len);
263                 gp_file_set_mime_type (file, GP_MIME_RAW);
264                 gp_file_adjust_name_for_mime_type(file);
265                 break;
266         default:
267                 return (GP_ERROR_NOT_SUPPORTED);        
268
269         }
270
271         return GP_OK;
272 }
273
274 /*************** Exit and Initialization Functions ******************/
275
276 static int
277 camera_exit (Camera *camera, GPContext *context)
278 {
279         GP_DEBUG ("Aox camera_exit");
280
281         if (camera->pl) {
282                 free (camera->pl);
283                 camera->pl = NULL;
284         }
285
286         return GP_OK;
287 }
288
289 static CameraFilesystemFuncs fsfuncs = {
290         .file_list_func = file_list_func,
291         .get_file_func = get_file_func
292 }; 
293
294 int
295 camera_init(Camera *camera, GPContext *context)
296 {
297         GPPortSettings settings;
298         CameraAbilities abilities;
299         int ret = 0;
300
301         /* First, set up all the function pointers */
302         camera->functions->summary      = camera_summary;
303         camera->functions->about        = camera_about;
304         camera->functions->exit     = camera_exit;
305
306         GP_DEBUG ("Initializing the camera\n");
307         ret = gp_port_get_settings(camera->port,&settings);
308         if (ret < 0) return ret; 
309
310         ret = gp_camera_get_abilities(camera,&abilities);                       
311         if (ret < 0) return ret;                                                
312         GP_DEBUG("product number is 0x%x\n", abilities.usb_product);
313
314         switch (camera->port->type) {
315                 case GP_PORT_SERIAL:
316                         return ( GP_ERROR );
317                 case GP_PORT_USB:
318                         settings.usb.config = 1;
319                         settings.usb.altsetting = 0;
320                         settings.usb.interface = 1;
321                         settings.usb.inep = 0x84;
322                         settings.usb.outep =0x05;
323                         break;
324                 default:
325                         return ( GP_ERROR );
326         }
327
328         ret = gp_port_set_settings(camera->port,settings);
329         if (ret < 0) return ret; 
330
331         GP_DEBUG("interface = %i\n", settings.usb.interface);
332         GP_DEBUG("inep = %x\n", settings.usb.inep);     
333         GP_DEBUG("outep = %x\n", settings.usb.outep);
334
335         /* Tell the CameraFilesystem where to get lists from */
336         gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
337
338         camera->pl = malloc (sizeof (CameraPrivateLibrary));
339         if (!camera->pl) return GP_ERROR_NO_MEMORY;
340         memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
341
342         switch(abilities.usb_product) {
343         case 0x2130:
344                 camera->pl->model = AOX_MODEL_DMAX;
345                 break;
346         default:
347                 camera->pl->model = AOX_MODEL_MINI;
348         }
349         /* Connect to the camera */
350         aox_init (camera->port, &camera->pl->model, camera->pl->info);
351
352         return GP_OK;
353 }