Files
libgphoto2/camlibs/sipix/web2.c
axxel f41df32817 fix white-space and indentation inconsistencies (second round)
This is basically a continuation of the work from #1002 but her for the
camlibs directory. The purpose was to replace spaces as a means for
indentation with tab characters.

Note: there are some files which are still offending the general
rule but are (mostly) consistent within themselves. I let them be for
the moment. Fixing them would basically replace the whole file.

Also: there are still a ton of whitespace related inconsistencies like
"x=10" vs "x = 10" or "func(10)" vs "func (10)".

This is a whitespace only change (if you include newlines as whitespace).
2024-09-15 10:53:41 +02:00

686 lines
17 KiB
C

/* web2.c
*
* Copyright 2002 Marcus Meissner <marcus@jet.franken.de>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gphoto2/gphoto2-library.h>
#include <gphoto2/gphoto2-result.h>
#include "libgphoto2/i18n.h"
#define WEB2_SELECT_PICTURE 0xb2
#define WEB2_GET_NUMPICS 0xb6
#define WEB2_OPEN_CAMERA 0xd7
#define WEB2_CLOSE_CAMERA 0xd8
#define WEB2_GET_EXIF 0xe5
#define WEB2_GET_IMAGE 0x93
#define WEB2_GET_THUMBNAIL 0x9b
#define WEB2_GET_DIRENTRY 0xb9
#define WEB2_GET_PICINFO 0xad
static int
web2_command(
GPPort *port, int iswrite, int cmd, int param, int index, char *data, int datasize
) {
int ret;
if (iswrite)
ret = gp_port_usb_msg_write(port,0,(cmd<<8)|param,index,data,datasize);
else
ret = gp_port_usb_msg_read(port,0,(cmd<<8)|param,index,data,datasize);
#if 0
fprintf(stderr,"cmd %x, param %d, ret is %d\n",cmd, param, ret);
if ((ret > 0) && data) {
for (i=0;i<datasize;i++) { fprintf(stderr,"%02x ",data[i]); }
fprintf(stderr,"\n");
}
#endif
if (ret>=GP_OK)
ret=GP_OK;
return ret;
}
static int
web2_init(GPPort *port, GPContext *context) {
return web2_command(port, 1, WEB2_OPEN_CAMERA, 1, 0, NULL, 0);
}
static int
web2_exit(GPPort *port, GPContext *context) {
return web2_command(port, 1, WEB2_CLOSE_CAMERA, 0, 0, NULL, 0);
}
static int
web2_select_picture(GPPort *port, GPContext *context, int picnum) {
char cmdbuf[2];
picnum++;
cmdbuf[0] = picnum & 0xff;
cmdbuf[1] = (picnum>>8) & 0xff;
return web2_command(port, 1, WEB2_SELECT_PICTURE, 0, 0, cmdbuf, 2);
}
static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
static int
web2_getexif(GPPort *port, GPContext *context, CameraFile *file)
{
int ret, i;
char xbuf[16384];
ret = web2_command(port, 1, WEB2_GET_EXIF, 0x00, 0, NULL, 0);
if (ret!=GP_OK)
return ret;
gp_file_append(file, (char*)ExifHeader, sizeof(ExifHeader));
ret = gp_port_read(port, xbuf, sizeof(xbuf));
if (ret < GP_OK) {
gp_file_clean(file);
return ret;
}
for (i=0;i<ret;i+=2) {
unsigned char tmp = xbuf[i];
xbuf[i] = xbuf[i+1];
xbuf[i+1] = tmp;
}
gp_file_append(file, xbuf, ret);
return GP_OK;
}
static int
web2_getthumb(GPPort *port, GPContext *context, CameraFile *file)
{
int ret, i;
unsigned char buf[16384];
ret = web2_command(port, 1, WEB2_GET_THUMBNAIL, 0x00, 0, NULL, 0);
if (ret!=GP_OK)
return ret;
ret = gp_port_read(port, (char*)buf, sizeof(buf));
if (ret < GP_OK)
return ret;
for (i=0;i<ret;i+=2) {
unsigned char tmp = buf[i];
buf[i] = buf[i+1];
buf[i+1] = tmp;
}
gp_file_append(file, (char*)buf, ret);
return GP_OK;
}
static int
web2_get_file_info(GPPort *port, GPContext *context, char *name, int *filesize) {
unsigned char cmdbuf[26];
int i, ret;
ret = web2_command(port, 0, WEB2_GET_DIRENTRY, 0, 0, (char*)cmdbuf, 26);
/* flip filename bytes to be in correct order */
for (i=2;i<16;i++)
name[i-2] = cmdbuf[i^1];
name[14] = 0;
*filesize = (cmdbuf[18] ) | (cmdbuf[19] << 8) | \
(cmdbuf[20] << 16) | (cmdbuf[21] << 24);
/* 22-25 unused? */
return ret;
}
static int
web2_getpicture(GPPort *port, GPContext *context, CameraFile *file)
{
char xbuf[8192];
int wascanceled = 0, id, ret, curread = 0, size;
char fn[20];
ret = web2_get_file_info(port, context, fn, &size);
if (ret!=GP_OK)
return ret;
id = gp_context_progress_start(context, size, _("Downloading image..."));
size++; /* sometimes we need to read a byte more to settle the camera */
/* can be called with 0x10 and 0x1 flag. But what do these do? */
ret = web2_command(port, 1, WEB2_GET_IMAGE, 0, 0, 0, 0);
if (ret!=GP_OK)
return ret;
while (curread < size) {
int toread = size-curread;
if ((unsigned int)toread > sizeof(xbuf))
toread = sizeof(xbuf);
ret = gp_port_read(port, xbuf, toread);
if (ret < GP_OK)
return ret;
gp_file_append(file,xbuf,ret);
curread+=ret;
gp_context_progress_update(context, id, curread);
if (toread!=ret)
break;
if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
/* We need to read the rest too or the communication is in
* an undefined state. */
wascanceled = 1;
}
}
gp_context_progress_stop(context, id);
if (wascanceled)
return GP_ERROR_CANCEL;
return GP_OK;
}
static int
web2_get_picture_info(
GPPort *port, GPContext *context,
int picnum,
int *perc, int *incamera, int *flags, int *unk
) {
char cmdbuf[8];
int ret;
/* picnum is not in param, but in the control message index! */
ret = web2_command(port, 0, WEB2_GET_PICINFO, 0, picnum+1, cmdbuf, 8);
if (ret != GP_OK)
return ret;
*perc = cmdbuf[0] | (cmdbuf[1] << 8);
*incamera = cmdbuf[2] | (cmdbuf[3] << 8);
*flags = cmdbuf[4] | (cmdbuf[5] << 8);
*unk = cmdbuf[6] | (cmdbuf[7] << 8);
return GP_OK;
}
/********************** Unknown and/or incomplete ******************/
/* Called after 0xad and 0xb2 , with 0, 1, 2, or similar x values
* Seems to global, not picture based. (Select storage? Select camera access
* mode?) Not clear. You need to set it correctly before download or delete
* thought
*/
static int
web2_set_xx_mode(GPPort *port, GPContext *context, int mode) {
char cmdbuf[2];
cmdbuf[0] = mode & 0xff;
cmdbuf[1] = (mode>>8) & 0xff;
return web2_command(port, 1, 0xae, 0, 0, cmdbuf, 2);
}
static int
web2_getnumpics(
GPPort *port, GPContext *context,
int *x1, int *numpics, int *x3, int *freemem
) {
char cmdbuf[10];
int ret;
ret = web2_command(port, 0, WEB2_GET_NUMPICS, 0x00, 0, cmdbuf, 10);
if (ret!=GP_OK)
return ret;
*x1 = cmdbuf[0] | (cmdbuf[1] << 8); /* unclear */
*numpics = cmdbuf[2] | (cmdbuf[3] << 8);
*x3 = cmdbuf[4] | (cmdbuf[5] << 8); /* unclear */
/* sometimes looks like mem, sometimes it doesn't */
*freemem = cmdbuf[6] | (cmdbuf[7] << 8) | (cmdbuf[8] << 16) | (cmdbuf[9] << 24);
return GP_OK;
}
/* called with 0x00, 0x20, or 0x40 */
/* 0x40 is 'delete selected picture' */
/* the others are unknown */
static int
web2_set_picture_attribute(GPPort *port, GPContext *context, int x, int *y) {
char cmdbuf[2];
int ret;
ret = web2_command(port, 0, 0xba, x, 0, cmdbuf, 2);
if (ret!=GP_OK)
return ret;
*y = cmdbuf[0] | (cmdbuf[1] << 8);
return GP_OK;
}
#if 0
/* gets 7 shorts */
static int
_cmd_e6(GPPort *port, GPContext *context, short *arr) {
char cmdbuf[14];
int i;
int ret;
ret = web2_command(port, 0, 0xe6, 0, 0, cmdbuf, 14);
if (ret!=GP_OK)
return ret;
for (i=0;i<7;i++)
arr[i] = cmdbuf[2*i+0] | (cmdbuf[2*i+1]<<8);
return GP_OK;
}
int
_cmd_d0(GPPort *port, GPContext *context, int flag, short *retval) {
char buf[4];
int ret;
ret = web2_command(port, 0, 0xd0, 0, 0, buf, 4);
if (ret < 0)
return GP_ERROR_IO;
*retval = buf[flag*2] | (buf[flag*2+1]<<8);
return GP_OK;
}
int /* change mode? args are 30,40,50 ... they will appear in d0 later */
_cmd_1f(GPPort *port, GPContext *context, int x) {
return web2_command(port, 1, 0x1f, x, 0, NULL, 0);
}
int
_cmd_07(GPPort *port, GPContext *context, int *x) {
char cmdbuf[2];
int ret;
ret = web2_command(port, 0, 0x07, 0, 0, cmdbuf, 2);
if (ret < 0)
return GP_ERROR_IO;
*x = cmdbuf[0] | (cmdbuf[1]<<8);
return GP_OK;
}
int
_cmd_0a(GPPort *port, GPContext *context, int x1, int x2) {
char buf[80], cmdbuf[2];
int ret, i;
cmdbuf[0] = x2&0xff;
cmdbuf[1] = (x2>>8)&0xff;
ret = web2_command(port, 1, 0x0a, x1, 0, cmdbuf, 2);
if (ret < 0) {
fprintf(stderr,"0a failed\n");
return GP_ERROR_IO;
}
ret = gp_port_read(port, buf, 80);
if (ret<80)
return ret;
for (i=0;i<sizeof(buf);i++) { fprintf(stderr,"%02x ",buf[i]); }
fprintf(stderr,"\n");
return GP_OK;
}
/* similar to 0a, writes the 80 byte table */
int
_cmd_0b(GPPort *port, GPContext *context, int x1, int x2) {
char cmdbuf[2];
int ret;
cmdbuf[0] = x2&0xff;
cmdbuf[1] = (x2>>8)&0xff;
ret = web2_command(port, 1, 0x0b, x1, 0, cmdbuf, 2);
if (ret < 0)
return GP_ERROR_IO;
/* Bulk writes stuff */
return GP_OK;
}
int
_cmd_eb(GPPort *port, GPContext *context, int x) {
char cmdbuf[2];
cmdbuf[0] = x & 0xff;
cmdbuf[1] = (x>>8) & 0xff;
/* Only 1 is passed as param, and x appears to be a BOOL */
return web2_command(port, 1, 0xeb, 1, 0, cmdbuf, 2);
}
int
_cmd_11(GPPort *port, GPContext *context, int x) {
return web2_command(port, 1, 0x11, x|0x20, 0, NULL, 0);
}
/* gets 1 shorts */
int
_cmd_bf(GPPort *port, GPContext *context, int x, short *val) {
char cmdbuf[2];
int ret;
ret = web2_command(port, 0, 0xbf, x, 0, cmdbuf, 2);
if (ret!=GP_OK)
return ret;
*val = cmdbuf[0] | (cmdbuf[1]<<8);
return GP_OK;
}
int
_cmd_20(GPPort *port, GPContext *context, int x) {
return web2_command(port, 1, 0x20, x, 0, NULL, 0);
}
int
_cmd_60(GPPort *port, GPContext *context, int x) {
return web2_command(port, 1, 0x60, x, 0, NULL, 0);
}
int
_cmd_20_0(GPPort *port, GPContext *context) {
return _cmd_20(port,context,0);
}
int
_cmd_e1(GPPort *port, GPContext *context, int x) {
switch (x) {
case 0: /* keep 0 */
break;
case 1: x = 0xe;
break;
default: x = 0xe + 0x19;
break;
}
return web2_command(port, 1, 0xe1, x, 0, NULL, 0);
}
static short xshort[3];
int
_cmd_26(GPPort *port, GPContext *context, int x) {
char cmdbuf[6];
int i;
switch (x) {
case 0:
for (i=0;i<3;i++) {
cmdbuf[2*i+0] = xshort[i] & 0xff;
cmdbuf[2*i+1] = (xshort[i] >> 8) & 0xff;
}
return web2_command(port, 1, 0x26, 0x10, 0, cmdbuf, 6);
case 1: xshort[0] = 364; /* 16c */
xshort[1] = 256; /* 100 */
xshort[2] = 596; /* 254 */
break;
case 2: xshort[0] = 998; /* 3e6 */
xshort[1] = 256; /* 100 */
xshort[2] = 259; /* 103 */
break;
default: xshort[0] = 625; /* 271 */
xshort[1] = 256; /* 100 */
xshort[2] = 607; /* 25f */
break;
}
for (i=0;i<3;i++) {
cmdbuf[2*i+0] = xshort[i] & 0xff;
cmdbuf[2*i+1] = (xshort[i] >> 8) & 0xff;
}
return web2_command(port, 1, 0x26, 0x00, 0, cmdbuf, 6);
}
int
_cmd_75(GPPort *port, GPContext *context, int x) {
switch (x) {
case 0: x = 1;break;
case 1: x = 2;break;
case 2: x = 0;break;
default:x = 1;break;
}
return web2_command(port, 1, 0x75, x, 0, NULL, 0);
}
int
_cmd_fb(GPPort *port, GPContext *context, int *y) {
char cmdbuf[2];
int ret;
ret = web2_command(port, 0, 0xfb, 0, 0xa2b8, cmdbuf, 2);
if (ret != GP_OK)
return ret;
*y = cmdbuf[0] | (cmdbuf[1] << 8);
return GP_OK;
}
#endif
int
camera_id (CameraText *id)
{
strcpy(id->text, "SiPix Web2");
return (GP_OK);
}
int
camera_abilities (CameraAbilitiesList *list)
{
CameraAbilities a;
memset(&a, 0, sizeof(a));
strcpy(a.model, "SiPix:Web2");
a.status = GP_DRIVER_STATUS_EXPERIMENTAL;
a.port = GP_PORT_USB;
a.speed[0] = 0;
a.usb_vendor = 0x0c77;
a.usb_product = 0x1001;
a.operations = GP_OPERATION_NONE;
a.file_operations = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_PREVIEW | GP_FILE_OPERATION_EXIF;
a.folder_operations = GP_FOLDER_OPERATION_NONE;
gp_abilities_list_append(list, a);
/* reported by Terry Lewis <mrkennie@amscomputers.biz> */
strcpy(a.model, "SiPix:SC2100");
a.usb_product = 0x1002;
gp_abilities_list_append(list, a);
return (GP_OK);
}
static int
camera_exit (Camera *camera, GPContext *context)
{
return web2_exit(camera->port, context);
}
static int
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
CameraFileType type, CameraFile *file, void *data,
GPContext *context)
{
Camera *camera = data;
int image_no, result, flags, aeflag, junk;
if (strcmp(folder,"/"))
return GP_ERROR_BAD_PARAMETERS;
image_no = gp_filesystem_number(fs, folder, filename, context);
if (image_no < GP_OK)
return image_no;
result = web2_get_picture_info(camera->port, context, image_no, &junk, &junk, &flags, &junk);
if (result != GP_OK)
return result;
if (flags & 1) {
aeflag = 1;
} else {
if (flags & 2) {
aeflag = 2;
} else {
fprintf(stderr,"Oops , 0xAD returned flags %x?!\n",flags);
return GP_ERROR;
}
}
result = web2_select_picture(camera->port, context, image_no);
if (result != GP_OK)
return result;
result = web2_set_xx_mode(camera->port, context, aeflag);
if (result != GP_OK)
return result;
/*
result = _cmd_e6(camera->port, context, fupp);
if (result != GP_OK)
return result;
for (i=0;i<7;i++)
fprintf(stderr,"%d (%x)",fupp[i],fupp[i]);
fprintf(stderr,"\n");
*/
gp_file_set_mime_type (file, GP_MIME_JPEG);
switch (type) {
case GP_FILE_TYPE_NORMAL:
/*result = _cmd_ae(camera->port, context, 1);
if (result != GP_OK)
fprintf(stderr,"ae 1 failed with %d\n",result);
*/
result = web2_getpicture(camera->port,context,file);
break;
case GP_FILE_TYPE_PREVIEW:
result = web2_getthumb (camera->port,context,file);
break;
case GP_FILE_TYPE_EXIF:
result = web2_getexif(camera->port,context,file);
break;
default:
return (GP_ERROR_NOT_SUPPORTED);
}
if (result < 0)
return result;
return (GP_OK);
}
static int
delete_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, void *data, GPContext *context)
{
Camera *camera = data;
int aeflag, flags, junk, result, image_no;
image_no = gp_filesystem_number(fs, folder, filename, context);
if (image_no < GP_OK)
return image_no;
result = web2_get_picture_info(camera->port, context, image_no, &junk, &junk, &flags, &junk);
if (result != GP_OK)
return result;
if (flags & 1) {
aeflag = 1;
} else {
if (flags & 2) {
aeflag = 2;
} else {
fprintf(stderr,"Oops , 0xAD returned flags %x?!\n",flags);
return GP_ERROR;
}
}
result = web2_select_picture(camera->port, context, image_no);
if (result != GP_OK)
return result;
result = web2_set_xx_mode(camera->port, context, aeflag);
if (result != GP_OK)
return result;
/* Delete the file from the camera. */
result = web2_set_picture_attribute(camera->port, context, 0x40, &junk);
if (result!= GP_OK)
return result;
/* fprintf(stderr,"ba 0x40 returns %d\n",junk);*/
return (GP_OK);
}
static int
camera_about (Camera *camera, CameraText *about, GPContext *context)
{
strcpy (about->text, _("SiPix Web2\n"
"Marcus Meissner <marcus@jet.franken.de>\n"
"Driver for accessing the SiPix Web2 camera."));
return (GP_OK);
}
/*
* This function makes sure that the <index in folder> is <picture index in
* camera>. Even delete should keep that relation.
*/
static int
file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
void *data, GPContext *context)
{
Camera *camera = data;
int i, count, result, junk, flags, aeflag;
result = web2_getnumpics(camera->port, context, &junk, &count, &junk, &junk);
if (result != GP_OK)
return result;
for (i=0;i<count;i++) {
char fn[20];
int size;
result = web2_get_picture_info(camera->port, context, i, &junk, &junk, &flags, &junk);
if (result != GP_OK)
return result;
if (flags & 1) {
aeflag = 1;
} else {
if (flags & 2) {
aeflag = 2;
} else {
fprintf(stderr,"Oops , 0xAD returned flags %x?!\n",flags);
return GP_ERROR;
}
}
result = web2_select_picture(camera->port, context, i);
if (result != GP_OK)
return result;
result = web2_set_xx_mode(camera->port, context, aeflag);
if (result != GP_OK)
return result;
result = web2_get_file_info(camera->port, context, fn, &size);
if (result != GP_OK)
return result;
gp_list_append(list, fn, NULL);
}
return (GP_OK);
}
static CameraFilesystemFuncs fsfuncs = {
.file_list_func = file_list_func,
.get_file_func = get_file_func,
.del_file_func = delete_file_func
};
int
camera_init (Camera *camera, GPContext *context)
{
camera->functions->exit = camera_exit;
camera->functions->about = camera_about;
gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
return web2_init(camera->port, context);
}