1405 lines
37 KiB
C
1405 lines
37 KiB
C
/* library.c
|
|
*
|
|
* Copyright (C) 2002 Michel Koltan <koltan@gmx.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.h>
|
|
|
|
#include "dc210.h"
|
|
#include "library.h"
|
|
|
|
#ifdef ENABLE_NLS
|
|
# include <libintl.h>
|
|
# 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
|
|
|
|
static int dc210_cmd_error = 0;
|
|
static const char ppmheader[] = "P6\n96 72\n255\n";
|
|
|
|
#ifdef DEBUG
|
|
static int firststatus = 1;
|
|
static char oldstatus[DC210_STATUS_SIZE];
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
|
|
Global in- and output procedures
|
|
|
|
****************************************************************************/
|
|
|
|
static void cfa2ppm
|
|
(CameraFile * file)
|
|
{
|
|
/* this is a very quick and dirty hack to convert cfa into ppm */
|
|
unsigned char buf[THUMBHEIGHT][THUMBWIDTH];
|
|
unsigned char rgb[THUMBHEIGHT][THUMBWIDTH][3];
|
|
unsigned char val;
|
|
unsigned int addval;
|
|
const char * data;
|
|
unsigned long datasize;
|
|
int i, x, y;
|
|
|
|
/* get data */
|
|
|
|
DC210_DEBUG("Converting CFA to PPM\n");
|
|
|
|
gp_file_get_data_and_size(file, &data, &datasize);
|
|
|
|
/* split 8 bit values into to 4 bit values and blow up again to 8 bit*/
|
|
|
|
i = 0;
|
|
for(y = 0; y < THUMBHEIGHT; y++ )
|
|
for(x = 0; x < THUMBWIDTH; x+=2 ){
|
|
val = (unsigned char) data[i] >> 4;
|
|
buf[y][x] = (val << 4) | val;
|
|
val = (unsigned char) data[i++] & 0x0F;
|
|
buf[y][x+1] = (val << 4) | val;
|
|
};
|
|
|
|
/* fill in the exact values */
|
|
for( y = 0; y < THUMBHEIGHT; y += 2 )
|
|
for( x = 0; x < THUMBWIDTH; x += 2 )
|
|
{
|
|
rgb[y][x][GREEN] = buf[y][x];
|
|
rgb[y][x+1][GREEN] = buf[y][x];
|
|
rgb[y+1][x][GREEN] = buf[y+1][x+1];
|
|
rgb[y+1][x+1][GREEN] = buf[y+1][x+1];
|
|
rgb[y][x][RED] = buf[y][x+1];
|
|
rgb[y][x+1][RED] = buf[y][x+1];
|
|
rgb[y+1][x][RED] = buf[y][x+1];
|
|
rgb[y+1][x+1][RED] = buf[y][x+1];
|
|
rgb[y][x][BLUE] = buf[y+1][x];
|
|
rgb[y][x+1][BLUE] = buf[y+1][x];
|
|
rgb[y+1][x][BLUE] = buf[y+1][x];
|
|
rgb[y+1][x+1][BLUE] = buf[y+1][x];
|
|
};
|
|
|
|
/* fill in the interpolated values, don't care about borders */
|
|
for ( y = 1; y < THUMBHEIGHT - 2; y+= 2)
|
|
for ( x = 0; x < THUMBWIDTH - 2; x +=2){
|
|
/* 2 missing green values */
|
|
addval = rgb[y][x][GREEN] + rgb[y][x+2][GREEN]
|
|
+ rgb[y-1][x+1][GREEN] + rgb[y+1][x+1][GREEN];
|
|
rgb[y][x+1][GREEN] = addval / 4;
|
|
|
|
addval = rgb[y+1][x-1][GREEN] + rgb[y+1][x+1][GREEN]
|
|
+ rgb[y][x][GREEN] + rgb[y+2][x][GREEN];
|
|
rgb[y+1][x][GREEN] = addval / 4;
|
|
|
|
/* 3 missing red values */
|
|
addval = rgb[y-1][x][RED] + rgb[y+1][x][RED];
|
|
rgb[y][x][RED] = addval / 2;
|
|
|
|
addval = rgb[y-1][x][RED] + rgb[y-1][x+2][RED]
|
|
+ rgb[y+1][x][RED] + rgb[y+1][x+2][RED];
|
|
rgb[y][x+1][RED] = addval / 4;
|
|
|
|
addval = rgb[y+1][x][RED] + rgb[y+1][x+2][RED];
|
|
rgb[y+1][x+1][RED] = addval / 2;
|
|
|
|
/* 3 missing blue values */
|
|
addval = rgb[y][x-1][BLUE] + rgb[y][x+1][BLUE];
|
|
rgb[y][x][BLUE] = addval / 2;
|
|
|
|
addval = rgb[y][x-1][BLUE] + rgb[y][x+1][BLUE]
|
|
+ rgb[y+2][x-1][BLUE] + rgb[y+2][x+1][BLUE];
|
|
rgb[y+1][x][BLUE] = addval / 4;
|
|
|
|
addval = rgb[y][x+1][BLUE] + rgb[y+2][x+1][BLUE];
|
|
rgb[y+1][x+1][BLUE] = addval / 2;
|
|
};
|
|
|
|
gp_file_clean(file);
|
|
gp_file_append(file, ppmheader, sizeof(ppmheader) - 1);
|
|
gp_file_append(file, (char *) rgb, THUMBWIDTH * THUMBHEIGHT * 3);
|
|
gp_file_set_mime_type(file, GP_MIME_PPM);
|
|
|
|
};
|
|
|
|
/* Utility procedures for command execution */
|
|
|
|
static void dc210_cmd_init
|
|
(char * cmd, unsigned char command_byte)
|
|
{
|
|
/* utility procedure to initalize a command string */
|
|
|
|
memset (cmd, 0, 8);
|
|
|
|
cmd[0] = command_byte;
|
|
cmd[7] = 0x1a;
|
|
|
|
};
|
|
|
|
static void dc210_cmd_packet_init
|
|
(char * cmd_packet, const char * filename)
|
|
{
|
|
/* prepare command packet */
|
|
memset (cmd_packet, 0x00, DC210_CMD_DATA_SIZE);
|
|
memset (cmd_packet + 48, 0xFF, 8);
|
|
strcpy(cmd_packet, "\\PCCARD\\DCIMAGES\\");
|
|
strcpy(cmd_packet + 17, filename);
|
|
|
|
DC210_DEBUG("Complete filename is %s\n", cmd_packet);
|
|
|
|
};
|
|
|
|
static int dc210_write_single_char
|
|
(Camera *camera, unsigned char response)
|
|
{
|
|
/* utility procedure to write a single character */
|
|
|
|
int i;
|
|
|
|
for (i=0; i< RETRIES; i++){
|
|
if (gp_port_write(camera->port, (char *)&response, 1) >= 0)
|
|
return (GP_OK);
|
|
};
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
static int dc210_read_single_char
|
|
(Camera *camera, unsigned char * response)
|
|
{
|
|
|
|
/* utility procedure to read a single character */
|
|
|
|
int i;
|
|
signed char error;
|
|
|
|
for (i = 0; i < RETRIES; i++){
|
|
|
|
error = gp_port_read(camera->port, (char *)response, 1);
|
|
|
|
if (error < 0){
|
|
if (error == GP_ERROR_TIMEOUT)
|
|
continue;
|
|
else{
|
|
DC210_DEBUG("Real bad error reading single character. Errornumber: %d\n", error);
|
|
return GP_ERROR;
|
|
};
|
|
};
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
return GP_ERROR_TIMEOUT;
|
|
|
|
};
|
|
|
|
/* Command execution */
|
|
|
|
static int dc210_execute_command
|
|
(Camera *camera, char *cmd)
|
|
{
|
|
|
|
/* This procedure sends a command to the camera and
|
|
waits for acknowledgement. Calling procedures have
|
|
to check the returncode; if the command succeeded
|
|
there are three possible follow ups:
|
|
- Read a DC210_COMMAND_COMPLETE in case of
|
|
simple commands
|
|
- Send an additional command package in case of
|
|
sophisticated commands
|
|
- Read data from the camera
|
|
But all this depends on the command and should not
|
|
be mixed in this procedure. */
|
|
|
|
int i,k ;
|
|
unsigned char response;
|
|
signed char error;
|
|
|
|
dc210_cmd_error = DC210_CMD_OKAY;
|
|
|
|
for (i = 0; i < RETRIES; i++){
|
|
|
|
/* write command */
|
|
if (gp_port_write(camera->port, cmd, 8) < 0){
|
|
DC210_DEBUG("Could not write to port.\n");
|
|
dc210_cmd_error = DC210_WRITE_ERROR;
|
|
continue; /* try again */
|
|
};
|
|
|
|
for (k = 0; k < RETRIES; k++){
|
|
error = gp_port_read(camera->port, (char *)&response, 1);
|
|
if (error != 1){
|
|
if (error == GP_ERROR_TIMEOUT){
|
|
dc210_cmd_error = DC210_TIMEOUT_ERROR;
|
|
continue; /* wait a little bit longer */
|
|
}
|
|
else{
|
|
DC210_DEBUG("Real bad error reading answer. Errornumber: %d\n", error);
|
|
dc210_cmd_error = DC210_READ_ERROR;
|
|
return error;
|
|
};
|
|
};
|
|
|
|
switch (response){
|
|
case DC210_COMMAND_ACK:
|
|
DC210_DEBUG("Command 0x%02X acknowledged.\n", (unsigned char) cmd[0]);
|
|
return GP_OK; break; /* that's fine, just what we expected */
|
|
case DC210_COMMAND_NAK:
|
|
DC210_DEBUG("Sorry, but the camera seems not to understand the command 0x%02X\n", (unsigned char) cmd[0]);
|
|
dc210_cmd_error = DC210_NAK_ERROR;
|
|
break; /* anyway, send the command again */
|
|
default:
|
|
DC210_DEBUG("Strange. Unexpected response for command 0x%02X: 0x%02X\n", (unsigned char) cmd[0], response);
|
|
dc210_cmd_error = DC210_GARBAGE_ERROR;
|
|
return GP_ERROR;
|
|
break;
|
|
};
|
|
break;
|
|
};
|
|
|
|
};
|
|
|
|
/* command does definitely not work */
|
|
|
|
DC210_DEBUG("Command definitely didn't work.\n");
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
/* appropriate actions to a command */
|
|
|
|
static int dc210_write_command_packet
|
|
(Camera * camera, char * data)
|
|
{
|
|
|
|
unsigned char checksum;
|
|
int i, error;
|
|
unsigned char answer;
|
|
|
|
/* calculating checksum */
|
|
checksum = 0;
|
|
for (i = 0; i < DC210_CMD_DATA_SIZE; i ++){
|
|
checksum ^= data[i];
|
|
};
|
|
|
|
for (i = 0; i < RETRIES; i++){
|
|
|
|
/* write the startbyte */
|
|
dc210_write_single_char(camera, DC210_CMD_PACKET_FOLLOWING);
|
|
|
|
/* write packet */
|
|
gp_port_write(camera->port, data, DC210_CMD_DATA_SIZE);
|
|
|
|
/* write checksum */
|
|
dc210_write_single_char(camera, checksum);
|
|
|
|
/* read answer */
|
|
|
|
error = gp_port_read(camera->port, (char *)&answer, 1);
|
|
|
|
if (error < 0) return GP_ERROR;
|
|
|
|
if (answer == DC210_CORRECT_PACKET) return GP_OK;
|
|
|
|
if (answer != DC210_ILLEGAL_PACKET) {
|
|
DC210_DEBUG("Strange answer to command packet: 0x%02X.\n", answer);
|
|
return GP_ERROR;
|
|
};
|
|
|
|
};
|
|
|
|
DC210_DEBUG("Could not send command packet.\n");
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
static int dc210_wait_for_response
|
|
(Camera *camera, int expect_busy, GPContext *context)
|
|
{
|
|
/* Waits for a command to finish.
|
|
Expects either a timeout, a DC210_BUSY,
|
|
a DC210_COMMAND_COMPLETE or a
|
|
DC210_PACKET_FOLLOWING; all other answers
|
|
are considered errors */
|
|
|
|
unsigned char response;
|
|
int error = 0;
|
|
int counter = 0;
|
|
int progress_id = 0;
|
|
|
|
if (context)
|
|
progress_id = gp_context_progress_start (context, expect_busy, _("Waiting..."));
|
|
|
|
while (1){
|
|
|
|
error = dc210_read_single_char(camera, &response);
|
|
if (error < 0){
|
|
if (context)
|
|
gp_context_progress_stop (context, progress_id);
|
|
return error;
|
|
};
|
|
|
|
switch (response){
|
|
case DC210_BUSY:
|
|
/* wait a little bit longer */
|
|
if (context && counter <= expect_busy)
|
|
gp_context_progress_update (context, progress_id, counter++);
|
|
break;
|
|
case DC210_COMMAND_COMPLETE:
|
|
case DC210_PACKET_FOLLOWING:
|
|
if (context)
|
|
gp_context_progress_stop (context, progress_id);
|
|
return response;
|
|
break;
|
|
default:
|
|
if (context)
|
|
gp_context_progress_stop (context, progress_id);
|
|
DC210_DEBUG("Command terminated with errorcode 0x%02X.\n", response);
|
|
return GP_ERROR;
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
static int dc210_read_single_block
|
|
(Camera *camera, unsigned char * b, int blocksize)
|
|
{
|
|
|
|
int i, k, error;
|
|
char cs_read, cs_computed;
|
|
|
|
for (i = 0; i < RETRIES; i++){
|
|
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_PACKET_FOLLOWING)
|
|
return GP_ERROR;
|
|
|
|
error = 1;
|
|
for (k = 0; k < RETRIES; k++){
|
|
if (gp_port_read(camera->port, (char *)b, blocksize) < 0){
|
|
continue;
|
|
};
|
|
error = 0;
|
|
break;
|
|
};
|
|
|
|
if (error) return GP_ERROR;
|
|
|
|
if (dc210_read_single_char(camera, (unsigned char *)&cs_read) < 0)
|
|
return GP_ERROR;
|
|
|
|
cs_computed = 0;
|
|
for (k = 0 ; k < blocksize; k++)
|
|
cs_computed ^= b[k];
|
|
if (cs_computed == cs_read){
|
|
dc210_write_single_char(camera, DC210_CORRECT_PACKET);
|
|
return GP_OK;
|
|
};
|
|
|
|
dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);
|
|
|
|
};
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
static int dc210_read_to_file
|
|
(Camera *camera, CameraFile * f, int blocksize, long int expectsize, GPContext *context)
|
|
{
|
|
|
|
int packets, k, l, fatal_error, packet_following;
|
|
unsigned int progress_id = 0;
|
|
unsigned char cs_read, cs_computed;
|
|
unsigned char * b;
|
|
|
|
int blocks = expectsize / blocksize;
|
|
int remaining = expectsize % blocksize;
|
|
|
|
if (NULL == (b = malloc(blocksize))) return GP_ERROR;
|
|
|
|
if (remaining) blocks++;
|
|
|
|
if (context)
|
|
progress_id = gp_context_progress_start (context, blocks, _("Getting data..."));
|
|
|
|
fatal_error = 0;
|
|
packets = 0;
|
|
|
|
packet_following = dc210_wait_for_response(camera, 0, NULL);
|
|
while (DC210_PACKET_FOLLOWING == packet_following){
|
|
fatal_error = 1;
|
|
for (k = 0; k < RETRIES; k++){
|
|
/* read packet */
|
|
if (gp_port_read(camera->port, (char *)b, blocksize) < 0){
|
|
dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);
|
|
packet_following = dc210_wait_for_response(camera, 0, NULL);
|
|
continue;
|
|
};
|
|
/* read checksum */
|
|
if (dc210_read_single_char(camera, &cs_read) == GP_ERROR){
|
|
free(b);
|
|
return GP_ERROR;
|
|
};
|
|
/* test checksum */
|
|
cs_computed = 0;
|
|
for (l = 0 ; l < blocksize; l++)
|
|
cs_computed ^= b[l];
|
|
if (cs_computed != cs_read){
|
|
dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);
|
|
packet_following = dc210_wait_for_response(camera, 0, NULL);
|
|
continue;
|
|
};
|
|
/* append to file */
|
|
if (packets == blocks - 1 && remaining)
|
|
gp_file_append(f, (char *)b, remaining);
|
|
else
|
|
gp_file_append(f, (char *)b, blocksize);
|
|
/* request next packet */
|
|
dc210_write_single_char(camera, DC210_CORRECT_PACKET);
|
|
packet_following = dc210_wait_for_response(camera, 0, NULL);
|
|
fatal_error = 0;
|
|
if (context)
|
|
gp_context_progress_update (context, progress_id, packets);
|
|
packets++;
|
|
break;
|
|
};
|
|
if (fatal_error) break;
|
|
};
|
|
|
|
if (packet_following < 0)
|
|
fatal_error = 1;
|
|
|
|
if (context)
|
|
gp_context_progress_stop (context, progress_id);
|
|
|
|
free(b);
|
|
|
|
if (fatal_error) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
/***************************************************************************
|
|
|
|
Working procedures
|
|
|
|
****************************************************************************/
|
|
|
|
/***** Set procedures *****/
|
|
|
|
static int dc210_set_option (Camera * camera, char command, unsigned int value, int valuesize){
|
|
|
|
char cmd[8];
|
|
dc210_cmd_init(cmd, command);
|
|
|
|
switch(valuesize){
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
cmd[2] = value & 0xFF;
|
|
break;
|
|
case 2:
|
|
cmd[3] = value & 0xFF;
|
|
cmd[2] = (value >> 8) & 0xFF;
|
|
break;
|
|
case 4:
|
|
cmd[5] = value & 0xFF;
|
|
cmd[4] = (value >> 8) & 0xFF;
|
|
cmd[3] = (value >> 16) & 0xFF;
|
|
cmd[2] = (value >> 24) & 0xFF;
|
|
break;
|
|
default:
|
|
return GP_ERROR;
|
|
};
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_set_compression (Camera * camera, dc210_compression_type compression){
|
|
|
|
return dc210_set_option(camera, DC210_SET_QUALITY, compression, 1);
|
|
|
|
};
|
|
|
|
int dc210_set_flash (Camera * camera, dc210_flash_type flash, char preflash){
|
|
|
|
if (flash != DC210_FLASH_NONE && preflash){
|
|
return dc210_set_option(camera, DC210_SET_FLASH, flash + 3, 1);
|
|
}
|
|
else
|
|
return dc210_set_option(camera, DC210_SET_FLASH, flash, 1);
|
|
|
|
};
|
|
|
|
int dc210_set_zoom (Camera * camera, dc210_zoom_type zoom){
|
|
|
|
return dc210_set_option(camera, DC210_SET_ZOOM, zoom, 1);
|
|
|
|
};
|
|
|
|
int dc210_set_file_type (Camera * camera, dc210_file_type_type file_type){
|
|
|
|
return dc210_set_option(camera, DC210_SET_FILE_TYPE, file_type, 1);
|
|
|
|
};
|
|
|
|
int dc210_set_resolution (Camera * camera, dc210_resolution_type res){
|
|
|
|
return dc210_set_option(camera, DC210_SET_RESOLUTION, res, 1);
|
|
|
|
};
|
|
|
|
int dc210_set_delay (Camera * camera){
|
|
|
|
/* This function works, but I do no have the slightest idea,
|
|
what the effect is / should be.
|
|
There is *no* delay, when you execute this function before
|
|
capturing. */
|
|
|
|
return dc210_set_option(camera, DC210_SET_DELAY, 10, 4);
|
|
|
|
};
|
|
|
|
int dc210_set_exp_compensation (Camera * camera, signed int compensation){
|
|
|
|
unsigned char param = abs(compensation);
|
|
|
|
if (compensation < 0) param |= 0x80;
|
|
|
|
return dc210_set_option(camera, DC210_SET_EXPOSURE, param, 1);
|
|
|
|
};
|
|
|
|
int dc210_system_time_callback (Camera * camera, CameraWidget * widget, GPContext * context){
|
|
|
|
return dc210_set_option(camera, DC210_SET_TIME, (time(NULL) - CAMERA_SET_EPOC) << 1, 4);
|
|
|
|
};
|
|
|
|
static int dc210_format_card (Camera * camera, char * album_name, GPContext * context){
|
|
|
|
char data[DC210_CMD_DATA_SIZE];
|
|
char cmd[8];
|
|
char * subst;
|
|
unsigned char answer[16];
|
|
unsigned char checksum_read, checksum;
|
|
int i;
|
|
|
|
memset (data, 0, DC210_CMD_DATA_SIZE);
|
|
|
|
/* Make the album name acceptable - we need at least 8 characters
|
|
which are not blank and there are no blanks allowed before the
|
|
last character.
|
|
*/
|
|
if (album_name != NULL && strlen(album_name) > 0){
|
|
strncpy(data, album_name, 11);
|
|
/* substitute blanks in the first 8 characters*/
|
|
while (NULL != (subst = strchr(data, ' '))) *subst = '_';
|
|
if (strlen(data) < 8) strncat(data, "________", 8 - strlen(data));
|
|
};
|
|
|
|
DC210_DEBUG("Album name is '%s'\n", data);
|
|
|
|
dc210_cmd_init(cmd, DC210_CARD_FORMAT);
|
|
|
|
dc210_execute_command(camera, cmd);
|
|
dc210_write_command_packet(camera, data);
|
|
if (dc210_wait_for_response(camera, 3, context) != DC210_PACKET_FOLLOWING) return GP_ERROR;
|
|
|
|
gp_port_read(camera->port, (char *)answer, 16);
|
|
gp_port_read(camera->port, (char *)&checksum_read, 1);
|
|
checksum = 0;
|
|
|
|
for (i = 0; i < 16; i++) checksum ^= answer[i];
|
|
if (checksum_read != checksum) return GP_ERROR;
|
|
|
|
DC210_DEBUG("Flash card formatted.\n");
|
|
|
|
if (dc210_write_single_char(camera, DC210_CORRECT_PACKET) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
gp_filesystem_reset(camera->fs);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
static int dc210_get_card_status (Camera * camera, dc210_card_status * card_status){
|
|
|
|
char cmd[8];
|
|
unsigned char answer[16];
|
|
unsigned char checksum_read, checksum;
|
|
int i;
|
|
|
|
card_status->open = 0;
|
|
card_status->program = 0;
|
|
card_status->space = 0;
|
|
|
|
dc210_cmd_init(cmd, DC210_CARD_STATUS);
|
|
dc210_execute_command(camera, cmd);
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_PACKET_FOLLOWING) return GP_ERROR;
|
|
|
|
gp_port_read(camera->port, (char *)answer, 16);
|
|
gp_port_read(camera->port, (char *)&checksum_read, 1);
|
|
|
|
checksum = 0;
|
|
for (i = 0; i < 16; i++) checksum ^= answer[i];
|
|
|
|
if (checksum_read != checksum)
|
|
DC210_DEBUG("Error reading card status.\n");
|
|
else
|
|
DC210_DEBUG("Card status correctly read.\n");
|
|
|
|
if (answer[0] & 0x08) card_status->open = 1;
|
|
DC210_DEBUG("Card status open is %d\n", card_status->open);
|
|
card_status->program = answer[1] * 0x100 + answer[2];
|
|
/* set the space in kb */
|
|
card_status->space = (answer[3] * 0x1000000 + answer[4] * 0x10000 + answer[5] * 0x100 + answer[6]) / 1024;
|
|
|
|
if (dc210_write_single_char(camera, DC210_CORRECT_PACKET) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_format_callback(Camera * camera, CameraWidget * widget, GPContext * context){
|
|
|
|
CameraWidget * window;
|
|
char * album_name;
|
|
|
|
gp_widget_get_root(widget, &window);
|
|
|
|
gp_widget_get_child_by_label (window, _("Album name"), &widget);
|
|
gp_widget_get_value (widget, &album_name);
|
|
|
|
return dc210_format_card(camera, album_name, context);
|
|
|
|
};
|
|
|
|
static int dc210_check_battery (Camera *camera){
|
|
|
|
char cmd[8];
|
|
dc210_cmd_init(cmd, DC210_CHECK_BATTERY);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_init_port (Camera *camera){
|
|
|
|
/* sending a break command resets the
|
|
speed to 9600 */
|
|
int camera_speeds[] = {115200, 19200, 38400, 57600};
|
|
int i, desired_speed;
|
|
GPPortSettings settings;
|
|
|
|
gp_port_get_settings (camera->port, &settings);
|
|
gp_port_set_timeout (camera->port, TIMEOUT);
|
|
settings.serial.bits = 8;
|
|
settings.serial.parity = 0;
|
|
settings.serial.stopbits = 1;
|
|
|
|
desired_speed = settings.serial.speed;
|
|
if (! desired_speed) desired_speed = 115200;
|
|
|
|
DC210_DEBUG("Desired port speed is %d.\n", desired_speed);
|
|
|
|
/* only set the speed if nothing was specified on the command line */
|
|
if (! settings.serial.speed) settings.serial.speed = 9600;
|
|
gp_port_set_settings (camera->port, settings);
|
|
|
|
/* ok, run a dummy command; if the camera was off,
|
|
this will activate it and set the speed to 9600;
|
|
but the command will return an error;
|
|
It makes no sense to shorten the timout time,
|
|
because the camera may need up to 10 seconds (information
|
|
of the manual) to startup */
|
|
if (dc210_check_battery(camera) == GP_OK) return GP_OK;
|
|
|
|
/* Fine, the last command didn't work, but we are now
|
|
sure, the camera is working, if it is connected
|
|
and has enough power.
|
|
This is the time to send a break to reset the speed
|
|
to 9600 */
|
|
|
|
gp_camera_set_port_speed(camera, 9600);
|
|
gp_port_send_break(camera->port, 300);
|
|
usleep(300 * 1000);
|
|
|
|
/* Excellent. Now our dummy command should work */
|
|
|
|
if (dc210_check_battery(camera) == GP_OK){
|
|
return dc210_set_speed(camera, desired_speed);
|
|
};
|
|
|
|
/* My, my, this is not nice. We change the timeout
|
|
and try other speeds as last resort */
|
|
|
|
gp_port_set_timeout (camera->port, 100);
|
|
|
|
for (i = 0; i < 4; i++){
|
|
settings.serial.speed = camera_speeds[i];
|
|
gp_port_set_settings (camera->port, settings);
|
|
|
|
if (dc210_check_battery(camera) == GP_OK){
|
|
gp_port_set_timeout (camera->port, TIMEOUT);
|
|
return dc210_set_speed(camera, desired_speed);
|
|
};
|
|
|
|
DC210_DEBUG("What a pity. Speed %d does not work.\n", camera_speeds[i]);
|
|
};
|
|
|
|
/* reset the timeout */
|
|
gp_port_set_timeout (camera->port, TIMEOUT);
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
int dc210_set_speed (Camera *camera, int speed) {
|
|
|
|
unsigned char cmd[8];
|
|
GPPortSettings settings;
|
|
|
|
dc210_cmd_init((char*)cmd, DC210_SET_SPEED);
|
|
|
|
switch (speed) {
|
|
case 9600:
|
|
cmd[2] = 0x96; cmd[3] = 0x00; break;
|
|
case 19200:
|
|
cmd[2] = 0x19; cmd[3] = 0x20; break;
|
|
case 38400:
|
|
cmd[2] = 0x38; cmd[3] = 0x40; break;
|
|
case 57600:
|
|
cmd[2] = 0x57; cmd[3] = 0x60; break;
|
|
case 115200:
|
|
cmd[2] = 0x11; cmd[3] = 0x52; break;
|
|
default:
|
|
return (GP_ERROR);
|
|
};
|
|
|
|
if (dc210_execute_command(camera, (char*)cmd) == GP_ERROR) return GP_ERROR;
|
|
|
|
gp_port_get_settings (camera->port, &settings);
|
|
settings.serial.speed = speed;
|
|
gp_port_set_settings (camera->port, settings);
|
|
|
|
DC210_DEBUG("Port speed set to %d.\n", speed);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
/****** Picture actions *****/
|
|
|
|
int dc210_take_picture
|
|
(Camera * camera, GPContext * context)
|
|
{
|
|
char cmd[8];
|
|
dc210_cmd_init(cmd, DC210_TAKE_PICTURE);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
switch (dc210_wait_for_response(camera, 5, context)){
|
|
/* we allow a timeout error here and check the result via status */
|
|
case DC210_COMMAND_COMPLETE:
|
|
case GP_ERROR_TIMEOUT: return GP_OK; break;
|
|
default: return GP_ERROR; break;
|
|
};
|
|
|
|
return GP_ERROR;
|
|
|
|
};
|
|
|
|
int dc210_delete_picture
|
|
(Camera * camera, unsigned int picno)
|
|
{
|
|
|
|
char cmd[8];
|
|
unsigned int pic_offset = picno - 1;
|
|
|
|
dc210_cmd_init(cmd, DC210_DELETE_PICTURE);
|
|
cmd[3] = pic_offset & 0xFF;
|
|
cmd[2] = (pic_offset >> 8) & 0xFF;
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_delete_last_picture
|
|
(Camera * camera )
|
|
{
|
|
|
|
dc210_status status;
|
|
|
|
if (dc210_get_status(camera, &status) == GP_ERROR)
|
|
return GP_ERROR;
|
|
|
|
if (0 == status.numPicturesInCamera)
|
|
return GP_ERROR;
|
|
|
|
return dc210_delete_picture(camera, status.numPicturesInCamera);
|
|
|
|
};
|
|
|
|
int dc210_delete_picture_by_name
|
|
(Camera * camera, const char * filename )
|
|
{
|
|
|
|
char cmd[8];
|
|
char cmd_packet[DC210_CMD_DATA_SIZE];
|
|
|
|
dc210_cmd_init(cmd, DC210_CARD_FILE_DEL);
|
|
dc210_cmd_packet_init(cmd_packet, filename);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_download_last_picture
|
|
(Camera * camera, CameraFile *file, dc210_picture_type type, GPContext *context)
|
|
{
|
|
|
|
dc210_status status;
|
|
dc210_picture_info picinfo;
|
|
|
|
if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
|
|
if (status.numPicturesInCamera == 0) return GP_ERROR;
|
|
|
|
if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR)
|
|
return GP_ERROR;
|
|
|
|
if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR)
|
|
return GP_ERROR;
|
|
|
|
return dc210_download_picture_by_name(camera, file, picinfo.image_name, type, context);
|
|
|
|
};
|
|
|
|
int dc210_open_card
|
|
(Camera * camera)
|
|
{
|
|
|
|
char cmd[8];
|
|
dc210_card_status card_status;
|
|
|
|
/* check if card is already opened */
|
|
dc210_get_card_status(camera, &card_status);
|
|
if (card_status.open) return GP_OK;
|
|
|
|
dc210_cmd_init(cmd, DC210_OPEN_CARD);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
};
|
|
|
|
#if 0 /* This function is not used by anybody */
|
|
static int dc210_close_card
|
|
(Camera * camera)
|
|
{
|
|
|
|
char cmd[8];
|
|
dc210_cmd_init(cmd, DC210_CLOSE_CARD);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
return GP_OK;
|
|
};
|
|
#endif
|
|
|
|
int dc210_download_picture_by_name
|
|
(Camera * camera, CameraFile *file, const char *filename, dc210_picture_type type, GPContext *context)
|
|
{
|
|
|
|
char cmd[8];
|
|
char cmd_packet[DC210_CMD_DATA_SIZE];
|
|
dc210_picture_info picinfo;
|
|
|
|
/* prepare command */
|
|
if (type == DC210_FULL_PICTURE){
|
|
/* we need the file size for the progress bar */
|
|
if (dc210_get_picture_info_by_name(camera, &picinfo, filename) == GP_ERROR)
|
|
return GP_ERROR;
|
|
DC210_DEBUG("Picture size is %d\n", picinfo.picture_size);
|
|
dc210_cmd_init(cmd, DC210_CARD_READ_FILE);
|
|
}
|
|
else
|
|
dc210_cmd_init(cmd, DC210_CARD_READ_THUMB);
|
|
|
|
if (type == DC210_RGB_THUMB) cmd[4] = 1;
|
|
|
|
dc210_cmd_packet_init(cmd_packet, filename);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;
|
|
|
|
switch (type){
|
|
case DC210_FULL_PICTURE:
|
|
if (picinfo.file_type == DC210_FILE_TYPE_JPEG)
|
|
gp_file_set_mime_type(file, GP_MIME_JPEG);
|
|
if (dc210_read_to_file(camera, file,
|
|
DC210_CARD_BLOCK_SIZE,
|
|
picinfo.picture_size, context) == GP_ERROR)
|
|
return GP_ERROR;
|
|
break;
|
|
case DC210_CFA_THUMB:
|
|
/* this thumb type is much faster to download, because it has just
|
|
a 6th of the size of rgb data */
|
|
if (dc210_read_to_file(camera, file,
|
|
DC210_DOWNLOAD_BLOCKSIZE, 48 * 72, NULL) == GP_ERROR)
|
|
return GP_ERROR;
|
|
/* convert cfa data to rgb: */
|
|
cfa2ppm(file);
|
|
break;
|
|
break;
|
|
case DC210_RGB_THUMB:
|
|
/* if you really need nice thumbs, you can use this, but I don't think it's
|
|
worth the 6 times longer download time */
|
|
gp_file_set_mime_type(file, GP_MIME_PPM);
|
|
gp_file_append(file, ppmheader, sizeof(ppmheader) - 1);
|
|
if (dc210_read_to_file(camera, file,
|
|
DC210_DOWNLOAD_BLOCKSIZE, 96 * 72 * 3, NULL) == GP_ERROR)
|
|
return GP_ERROR;
|
|
break;
|
|
};
|
|
|
|
return GP_OK;
|
|
};
|
|
|
|
int dc210_capture (Camera *camera, CameraFilePath *path, GPContext *context)
|
|
{
|
|
|
|
dc210_status status;
|
|
dc210_picture_info picinfo;
|
|
int pictures_in_camera;
|
|
|
|
/* dc210_take_picture no longer returns an error on timeout; check
|
|
the working of the command via status */
|
|
|
|
if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
|
|
pictures_in_camera = status.numPicturesInCamera;
|
|
|
|
if (dc210_take_picture(camera, context) == GP_ERROR) return GP_ERROR;
|
|
|
|
if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
|
|
if (pictures_in_camera == status.numPicturesInCamera) return GP_ERROR;
|
|
|
|
if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR) return GP_ERROR;
|
|
|
|
strcpy(path->folder, "/");
|
|
strcpy(path->name, picinfo.image_name);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
/***** Retrieve information *****/
|
|
|
|
int dc210_get_picture_number (Camera *camera, const char * filename){
|
|
|
|
/* This function is terrible slow if you have a lot of pictures
|
|
in the camera; therefor it should not be used */
|
|
|
|
dc210_status status;
|
|
dc210_picture_info picinfo;
|
|
int i;
|
|
|
|
if (dc210_get_status(camera, &status) == GP_ERROR) return -1;
|
|
|
|
for (i = 1; i <= status.numPicturesInCamera; i++){
|
|
|
|
if (dc210_get_picture_info(camera, &picinfo, i) == GP_ERROR) return -1;
|
|
|
|
if (strcmp(picinfo.image_name, filename) == 0){
|
|
return i;
|
|
};
|
|
|
|
};
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int dc210_get_filenames (Camera *camera, CameraList *list, GPContext *context)
|
|
{
|
|
char cmd[8];
|
|
CameraFile *file;
|
|
char filename[13];
|
|
const char * data;
|
|
unsigned long datasize;
|
|
int pictures, i;
|
|
|
|
gp_file_new(&file);
|
|
|
|
dc210_cmd_init(cmd, DC210_GET_ALBUM_FILENAMES);
|
|
|
|
dc210_execute_command(camera, cmd);
|
|
|
|
dc210_read_to_file(camera, file, DC210_DIRLIST_SIZE, 0, NULL);
|
|
|
|
gp_file_get_data_and_size(file, &data, &datasize);
|
|
|
|
pictures = (unsigned char) data[0] * 0x100 + (unsigned char) data[1];
|
|
DC210_DEBUG("There are %d pictures in the camera\n", pictures);
|
|
|
|
filename[8] = '.';
|
|
filename[12] = '\0';
|
|
for (i = 0; i < pictures; i++){
|
|
strncpy(filename, data + 2 + i*20, 8);
|
|
strncpy(filename + 9, data + 10 + i*20, 3);
|
|
DC210_DEBUG("Adding filename %s to list\n", filename);
|
|
gp_list_append(list, filename, NULL);
|
|
};
|
|
|
|
gp_file_free(file);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
static void dc210_picinfo_from_block (dc210_picture_info * picinfo, unsigned char * data){
|
|
|
|
picinfo->camera_type = data[1];
|
|
picinfo->file_type = data[2];
|
|
picinfo->resolution = data[3];
|
|
picinfo->compression = data[4];
|
|
picinfo->picture_number = data[6] * 0x100 + data[7];
|
|
picinfo->picture_size = data[8] * 0x1000000 + data[9] * 0x10000 + data[10] * 0x100 + data[11];
|
|
picinfo->preview_size = 96 * 72 * 3 + sizeof(ppmheader);
|
|
picinfo->picture_time = CAMERA_GET_EPOC + ((data[12] * 0x1000000 +
|
|
data[13] * 0x10000 +
|
|
data[14] * 0x100 +
|
|
data[15]) >> 1);
|
|
picinfo->flash_used = data[16];
|
|
picinfo->flash = data[17];
|
|
picinfo->preflash = (data[17] > 2);
|
|
if (picinfo->preflash) picinfo->flash -= 3;
|
|
picinfo->zoom = data[21];
|
|
picinfo->f_number = data[26];
|
|
picinfo->battery = data[27];
|
|
picinfo->exposure_time = data[28] * 0x1000000 + data[29] * 0x10000 + data[30] * 0x100 + data[31];
|
|
strncpy(picinfo->image_name, (char *)&data[32], 12);
|
|
picinfo->image_name[12] = 0;
|
|
|
|
}
|
|
|
|
int dc210_get_picture_info (Camera *camera, dc210_picture_info *picinfo, unsigned int picno) {
|
|
|
|
char cmd[8];
|
|
unsigned char data[DC210_PICINFO_SIZE];
|
|
unsigned int pic_offset = picno - 1;
|
|
|
|
dc210_cmd_init(cmd, DC210_GET_PICINFO);
|
|
cmd[3] = pic_offset & 0xFF;
|
|
cmd[2] = (pic_offset >> 8) & 0xFF;
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_read_single_block(camera, data, DC210_PICINFO_SIZE) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
dc210_picinfo_from_block(picinfo, data);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_get_picture_info_by_name (Camera *camera, dc210_picture_info *picinfo, const char * filename) {
|
|
|
|
char cmd[8];
|
|
char cmd_packet[DC210_CMD_DATA_SIZE];
|
|
unsigned char data[DC210_CARD_BLOCK_SIZE];
|
|
|
|
dc210_cmd_init(cmd, DC210_CARD_GET_PICINFO);
|
|
dc210_cmd_packet_init(cmd_packet, filename);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_read_single_block(camera, data, DC210_CARD_BLOCK_SIZE) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
dc210_picinfo_from_block(picinfo, data);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
int dc210_get_status (Camera *camera, dc210_status *status) {
|
|
|
|
#ifdef DEBUG
|
|
int i;
|
|
#endif
|
|
|
|
char data[DC210_STATUS_SIZE];
|
|
char cmd[8];
|
|
|
|
/* you have to check the battery status explicitely
|
|
before reading the status table*/
|
|
dc210_check_battery(camera);
|
|
|
|
/* check the card */
|
|
dc210_get_card_status(camera, &(status->card_status));
|
|
|
|
dc210_cmd_init(cmd, DC210_GET_STATUS);
|
|
|
|
if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_read_single_block(camera, (unsigned char *)data, DC210_STATUS_SIZE) == GP_ERROR) return GP_ERROR;
|
|
if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
|
|
|
|
#ifdef DEBUG
|
|
if (firststatus){
|
|
firststatus = 0;
|
|
}
|
|
else{
|
|
for (i = 0; i < DC210_STATUS_SIZE; i++){
|
|
if (oldstatus[i] != data[i] && (i < 12 || i > 15)){
|
|
DC210_DEBUG("Statusdata differs at offset %03d (old: 0x%02X, new: 0x%02X)\n",
|
|
i, (unsigned char) oldstatus[i], (unsigned char) data[i]);
|
|
};
|
|
};
|
|
};
|
|
memcpy(oldstatus, data, DC210_STATUS_SIZE);
|
|
#endif
|
|
|
|
status->firmwareMajor = data[2];
|
|
status->firmwareMinor = data[3];
|
|
status->battery = data[8];
|
|
status->acstatus = data[9];
|
|
|
|
/* seconds since unix epoc */
|
|
status->time = CAMERA_GET_EPOC + ((unsigned char) data[12] * 0x1000000 +
|
|
(unsigned char) data[13] * 0x10000 +
|
|
(unsigned char) data[14] * 0x100 +
|
|
(unsigned char) data[15]) / 2;
|
|
|
|
status->zoom = data[16];
|
|
status->compression_type = data[19];
|
|
status->flash = data[20];
|
|
status->exp_compensation = data[21] & 0x7F;
|
|
if (data[21] & 0x80) status->exp_compensation *= -1;
|
|
status->preflash = (data[20] > 2);
|
|
if (status->preflash) status->flash -= 3;
|
|
status->resolution = data[22];
|
|
status->file_type = data[23];
|
|
status->totalPicturesTaken = (unsigned char) data[25] * 0x100 + (unsigned char) data[26];
|
|
status->totalFlashesFired = (unsigned char) data[27] * 0x100 + (unsigned char) data[28];
|
|
status->numPicturesInCamera = (unsigned char) data[56] * 0x100 + (unsigned char) data[57];
|
|
status->remainingLow = (unsigned char) data[68] * 0x100 + (unsigned char) data[69];
|
|
status->remainingMedium = (unsigned char) data[70] * 0x100 + (unsigned char) data[71];
|
|
status->remainingHigh = (unsigned char) data[72] * 0x100 + (unsigned char) data[73];
|
|
strncpy(status->album_name, &data[77], 11);
|
|
status->album_name[11] = 0;
|
|
|
|
return GP_OK;
|
|
|
|
}
|
|
|
|
/* Debugging stuff, not really needed in the driver */
|
|
|
|
#ifdef DEBUG
|
|
|
|
static int dc210_read_dummy_packet(Camera * camera){
|
|
|
|
int i;
|
|
signed char error;
|
|
unsigned char answer, lastanswer, checksum;
|
|
|
|
checksum = 0;
|
|
lastanswer = 0;
|
|
for ( i = 0; i < 2048; i++){
|
|
|
|
error = gp_port_read(camera->port, &answer, 1);
|
|
|
|
if (error < 0){
|
|
DC210_DEBUG("Packet read exhausted. Packet size: %d\n", i-1);
|
|
if (checksum == lastanswer)
|
|
DC210_DEBUG("Checksum is okay. Sending okay.\n");
|
|
else
|
|
DC210_DEBUG("Checksum is not okay. Sending correct packet anyway.\n");
|
|
answer = DC210_CORRECT_PACKET;
|
|
gp_port_write(camera->port, &answer, 1);
|
|
return GP_OK;
|
|
};
|
|
DC210_DEBUG(" Byte %03d: 0x%02X", i, answer);
|
|
if (answer > 32)
|
|
DC210_DEBUG(" (%c)", answer);
|
|
DC210_DEBUG("\n");
|
|
checksum ^= lastanswer;
|
|
lastanswer = answer;
|
|
};
|
|
|
|
DC210_DEBUG("Packet too long. Sending cancel.\n");
|
|
answer = DC210_CANCEL;
|
|
gp_port_write(camera->port, &answer, 1);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
static int dc210_test_command
|
|
(Camera * camera, unsigned char cmdbyte, unsigned char *databytes){
|
|
|
|
/* this is a debug command to test the behaviour
|
|
of certain camera commands */
|
|
unsigned char cmd[8];
|
|
unsigned char answer;
|
|
signed char error;
|
|
int packetcount = 0;
|
|
char dummy_cmd_packet[DC210_CMD_DATA_SIZE];
|
|
|
|
memset (dummy_cmd_packet, 0, DC210_CMD_DATA_SIZE);
|
|
|
|
dc210_cmd_init(cmd, cmdbyte);
|
|
|
|
memcpy(cmd + 2, databytes, 4);
|
|
|
|
/* okay, write the command and wait for acknowledge */
|
|
|
|
gp_port_write(camera->port, cmd, 8);
|
|
|
|
error = gp_port_read(camera->port, &answer, 1);
|
|
|
|
if (error < 0){
|
|
DC210_DEBUG("Command 0x%02X produced port read error %d",
|
|
cmdbyte, error);
|
|
return GP_OK;
|
|
};
|
|
|
|
switch (answer){
|
|
case DC210_COMMAND_ACK:
|
|
DC210_DEBUG("Okay, command 0x%02X acknowledged.\n", cmdbyte);
|
|
break;
|
|
case DC210_COMMAND_NAK:
|
|
DC210_DEBUG("Sorry, command 0x%02X not acknowledged.\n", cmdbyte);
|
|
return GP_OK;
|
|
default:
|
|
DC210_DEBUG("Unexpected response 0x%02X to command 0x%02X.\n",
|
|
answer, cmdbyte);
|
|
return GP_OK;
|
|
};
|
|
|
|
wait_finish:
|
|
error = gp_port_read(camera->port, &answer, 1);
|
|
|
|
if (error < 0){
|
|
DC210_DEBUG("Command 0x%02X produced port read error %d\n",
|
|
cmdbyte, error);
|
|
DC210_DEBUG("Probably the command expects a command package.\n");
|
|
DC210_DEBUG("Sending one...\n");
|
|
dc210_write_command_packet(camera, dummy_cmd_packet);
|
|
goto wait_finish;
|
|
};
|
|
|
|
switch(answer){
|
|
case DC210_COMMAND_COMPLETE:
|
|
DC210_DEBUG("Okay. Command has been accepted and executed.\n");
|
|
return GP_OK;
|
|
case DC210_EXECUTION_ERROR:
|
|
DC210_DEBUG("Sorry. An error occurred while executing command.\n");
|
|
return GP_OK;
|
|
case DC210_CORRECT_PACKET:
|
|
DC210_DEBUG("Okay. Packet successfully received.\n");
|
|
goto wait_finish;
|
|
case DC210_PACKET_FOLLOWING:
|
|
DC210_DEBUG("My, my, you got more than you bargained for. ");
|
|
DC210_DEBUG("Awaiting packet...\n");
|
|
dc210_read_dummy_packet(camera);
|
|
DC210_DEBUG("Read %d packets.\n", ++packetcount);
|
|
goto wait_finish;
|
|
case DC210_BUSY:
|
|
DC210_DEBUG("Camera is busy.\n");
|
|
goto wait_finish;
|
|
default:
|
|
DC210_DEBUG("Unexpected response 0x%02X to command 0x%02X.\n",
|
|
answer, cmdbyte);
|
|
return GP_OK;
|
|
};
|
|
};
|
|
|
|
int dc210_debug_callback(Camera * camera, CameraWidget * widget, GPContext * context){
|
|
|
|
/*CameraFile *file;*/
|
|
CameraWidget * window;
|
|
char * s_param1, *s_param2, *s_param3;
|
|
int param1, param2, param3;
|
|
int value;
|
|
unsigned char params[4];
|
|
dc210_status status;
|
|
|
|
memset(params, 0, 4);
|
|
|
|
gp_widget_get_root(widget, &window);
|
|
|
|
gp_widget_get_child_by_label (window, _("Parameter 1"), &widget);
|
|
gp_widget_get_value (widget, &s_param1);
|
|
param1 = atoi(s_param1);
|
|
|
|
gp_widget_get_child_by_label (window, _("Parameter 2"), &widget);
|
|
gp_widget_get_value (widget, &s_param2);
|
|
param2 = atoi(s_param2);
|
|
|
|
gp_widget_get_child_by_label (window, _("Parameter 3"), &widget);
|
|
gp_widget_get_value (widget, &s_param3);
|
|
param3 = atoi(s_param3);
|
|
|
|
/* Put the stuff you want to test here */
|
|
dc210_get_status(camera, &status);
|
|
dc210_test_command(camera, 0x85, params);
|
|
dc210_get_status(camera, &status);
|
|
|
|
return GP_OK;
|
|
|
|
};
|
|
|
|
#endif
|