Files
libgphoto2/camlibs/sierra/library.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

1556 lines
40 KiB
C

/* library.c
*
* Copyright 2001 Lutz Mueller <lutz@users.sf.net>
*
* 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
*/
#define _DARWIN_C_SOURCE
#include "config.h"
#include "library.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <gphoto2/gphoto2-port-log.h>
#include "libgphoto2/i18n.h"
#include "sierra.h"
#include "sierra-usbwrap.h"
#define GP_MODULE "sierra"
enum _SierraPacket {
NUL = 0x00,
SIERRA_PACKET_DATA = 0x02,
SIERRA_PACKET_DATA_END = 0x03,
SIERRA_PACKET_ENQ = 0x05,
ACK = 0x06,
SIERRA_PACKET_INVALID = 0x11,
SIERRA_PACKET_NAK = 0x15,
SIERRA_PACKET_CANCEL = 0x18,
SIERRA_PACKET_COMMAND = 0x1b,
SIERRA_PACKET_WRONG_SPEED = 0x8c,
SIERRA_PACKET_SESSION_ERROR = 0xfc,
SIERRA_PACKET_SESSION_END = 0xff
};
typedef enum _SierraPacket SierraPacket;
/* Size of requested packet */
#define SIERRA_PACKET_SIZE 32774
/* Sub-types */
#define SUBSIERRA_PACKET_COMMAND_FIRST 0x53
#define SUBSIERRA_PACKET_COMMAND 0x43
/* Maximum length of the data field within a packet */
#define MAX_DATA_FIELD_LENGTH 2048
#define RETRIES 10
#define QUICKSLEEP 5
int sierra_change_folder (Camera *camera, const char *folder, GPContext *context)
{
int st = 0, i;
char target[128];
GP_DEBUG ("*** sierra_change_folder");
GP_DEBUG ("*** folder: %s", folder);
/*
* Do not issue the command if the camera doesn't support folders
* or if the folder is the current working folder
*/
if (!camera->pl->folders || !strcmp (camera->pl->folder, folder))
return GP_OK;
/* We will later need a path ending with '/'. */
memset (target, 0, sizeof (target));
if (folder[0])
strncpy (target, folder, sizeof (target) - 1);
if (target[strlen (target) - 1] != '/')
strcat (target, "/");
/* If the given path is absolute, we need to start in '/'. */
if (target[0] == '/') {
CHECK (sierra_set_string_register (camera, 84, "\\", 1,
context));
i = 1;
} else
i = 0;
st = i;
for (; target[i]; i++) {
if (target[i] == '/') {
target[i] = '\0';
if (st == i - 1)
break;
CHECK (sierra_set_string_register (camera, 84,
target + st, strlen (target + st), context));
st = i + 1;
target[i] = '/';
}
}
strcpy (camera->pl->folder, folder);
return GP_OK;
}
int sierra_list_files (Camera *camera, const char *folder, CameraList *list, GPContext *context)
{
int count, i, r;
unsigned int len = 0;
char filename[1024];
GP_DEBUG ("Listing files in folder '%s'", folder);
/*
* This is a non-fatal check if a memory card is present. Some
* cameras don't understand this command and error out here.
* Since some cameras do not like it at all, do not send it for those.
*/
if (!(camera->pl->flags & SIERRA_NO_51)) {
r = sierra_get_int_register (camera, 51, &i, NULL);
if ((r >= 0) && (i == 1)) {
gp_context_error (context, _("No memory card present"));
return GP_ERROR_NOT_SUPPORTED;
}
}
/* We need to change to the folder first */
CHECK (sierra_change_folder (camera, folder, context));
/* Then, we count the files */
GP_DEBUG ("Counting files in '%s'...", folder);
CHECK (sierra_get_int_register (camera, 10, &count, context));
GP_DEBUG ("... done. Found %i file(s).", count);
/* No files? Then, we are done. */
if (!count)
return GP_OK;
/*
* Get the filename of the first picture. Note that some cameras
* that don't support filenames return 8 blanks instead of
* reporting an error. If this is indeed the case, just fill
* the list with dummy entries and return.
*/
GP_DEBUG ("Getting filename of first file");
r = sierra_get_string_register (camera, 79, 1, NULL,
(unsigned char *)filename,
&len, context);
if ((r < 0) || (len <= 0) || !strcmp (filename, " ")) {
CHECK (gp_list_populate (list, "P101%04i.JPG", count));
return GP_OK;
}
/*
* The camera supports filenames. Append the first one to the list
* and get the remaining ones.
*/
CHECK (gp_list_append (list, filename, NULL));
for (i = 1; i < count; i++) {
GP_DEBUG ("Getting filename of file %i...", i + 1);
CHECK (sierra_get_string_register (camera, 79, i + 1, NULL,
(unsigned char *)filename,
&len, context));
if ((len <= 0) || !strcmp (filename, " "))
snprintf (filename, sizeof (filename),
"P101%04i.JPG", i + 1);
GP_DEBUG ("... done ('%s').", filename);
CHECK (gp_list_append (list, filename, NULL));
}
return GP_OK;
}
int sierra_list_folders (Camera *camera, const char *folder, CameraList *list,
GPContext *context)
{
int i, j, count;
unsigned int bsize;
char buf[1024];
/* List the folders only if the camera supports them */
if (!camera->pl->folders)
return GP_OK;
CHECK (sierra_change_folder (camera, folder, context));
GP_DEBUG ("*** counting folders in '%s'...", folder);
CHECK (sierra_get_int_register (camera, 83, &count, context));
GP_DEBUG ("*** found %i folders", count);
for (i = 0; i < count; i++) {
CHECK (sierra_change_folder (camera, folder, context));
CHECK (sierra_set_int_register (camera, 83, i + 1, context));
bsize = 1024;
GP_DEBUG ("*** getting name of folder %i", i + 1);
CHECK (sierra_get_string_register (camera, 84, 0,
NULL, (unsigned char *)buf,
&bsize, context));
/* Remove trailing spaces */
for (j = strlen (buf) - 1; j >= 0 && buf[j] == ' '; j--)
buf[j] = '\0';
gp_list_append (list, buf, NULL);
}
return GP_OK;
}
/**
* sierra_get_picture_folder:
* @camera : camera data structure
* @folder : folder name (to be freed by the caller)
*
* Return the name of the folder that stores pictures. It is assumed that
* the camera conforms with the JEIDA standard. Thus, look for the picture
* folder into the /DCIM directory.
*
* Returns: a gphoto2 error code
*/
int sierra_get_picture_folder (Camera *camera, char **folder)
{
int i;
CameraList *list;
const char *name = NULL;
GP_DEBUG ("* sierra_get_picture_folder");
*folder = NULL;
/* If the camera does not support folders, the picture
folder is the root folder */
if (!camera->pl->folders) {
*folder = (char*) calloc(2, sizeof(char));
strcpy(*folder, "/");
return GP_OK;
}
CHECK (gp_list_new (&list));
/* It is assumed that the camera conforms with the JEIDA standard .
Thus, look for the picture folder into the /DCIM directory */
CHECK (gp_filesystem_list_folders (camera->fs, "/DCIM", list, NULL) );
for(i=0 ; i < gp_list_count (list) ; i++) {
CHECK (gp_list_get_name (list, i, &name) );
GP_DEBUG ("* check folder %s", name);
if (isdigit(name[0]) && isdigit(name[1]) && isdigit(name[2]))
break;
name = NULL;
}
if (name) {
*folder = (char*) calloc(strlen(name)+7, sizeof(char));
strcpy(*folder, "/DCIM/");
strcat(*folder, name);
gp_list_free (list);
return GP_OK;
} else {
gp_list_free (list);
return GP_ERROR_DIRECTORY_NOT_FOUND;
}
}
/**
* sierra_check_battery_capacity:
* @camera : camera data structure
*
* Check if the battery capacity is high enough.
*
* Returns: a gphoto2 error code
*/
int sierra_check_battery_capacity (Camera *camera, GPContext *context)
{
int ret, capacity;
GP_DEBUG ("* sierra_check_battery_capacity");
if ((ret = sierra_get_int_register(camera, 16, &capacity, context)) != GP_OK) {
gp_context_error (context,
_("Cannot retrieve the battery capacity"));
return ret;
}
if (!capacity) /* 0% is unlikely */
return GP_OK;
if (capacity < 5) {
gp_context_error (context,
_("The battery level of the camera is too low (%d%%). "
"The operation is aborted."), capacity);
return GP_ERROR;
}
return GP_OK;
}
/**
* sierra_get_memory_left:
* @camera : camera data structure
* @memory : memory left
*
* Provide the available memory left
*
* Returns: a gphoto2 error code
*/
int
sierra_get_memory_left (Camera *camera, int *memory, GPContext *context)
{
int ret;
ret = sierra_get_int_register (camera, 28, memory, context);
if (ret < 0) {
gp_context_error (context, _("Cannot retrieve the available "
"memory left"));
return ret;
}
return GP_OK;
}
static int
sierra_check_connection (Camera *camera, GPContext *context)
{
int r = 0, ret, timeout;
unsigned char c;
/* Only serial cameras close the connection after some timeout. */
if (camera->port->type != GP_PORT_SERIAL)
return GP_OK;
GP_DEBUG ("Checking if connection is still open");
while (1) {
/*
* Do like the Windows driver - check for 20ms if something
* has been sent by the camera.
*/
CHECK (gp_port_get_timeout (camera->port, &timeout));
CHECK (gp_port_set_timeout (camera->port, 20));
ret = gp_port_read (camera->port, (char *)&c, 1);
CHECK (gp_port_set_timeout (camera->port, timeout));
switch (ret) {
case GP_ERROR_TIMEOUT:
case GP_ERROR_IO_READ:
/*
* If we got GP_ERROR_TIMEOUT or GP_ERROR_IO_READ,
* everything's just fine.
*/
return GP_OK;
default:
/*
* If any error (except timeout) has occurred,
* report it.
*/
CHECK (ret);
}
/*
* We have received something. This is not good. Check if
* the camera has closed the connection and told us about
* that by sending SIERRA_PACKET_SESSION_END.
*/
if (c == SIERRA_PACKET_SESSION_END) {
if (++r > 2) {
gp_context_error (context, _("Camera refused "
"3 times to keep a connection open."));
return GP_ERROR;
}
CHECK (sierra_init (camera, context));
CHECK (sierra_set_speed (camera, SIERRA_SPEED_19200,
context));
continue;
}
/*
* The camera sends us unexpected data. Dump it and assume
* that everything's just fine.
*/
while (gp_port_read (camera->port, (char *)&c, 1) >= 0);
return GP_OK;
}
}
static int
sierra_write_packet (Camera *camera, char *packet, GPContext *context)
{
int x, checksum=0, length;
CHECK (sierra_check_connection (camera, context));
/*
* We need to check if this is the first packet. Note that USB
* cameras don't care.
*/
switch (packet[0]) {
case SIERRA_PACKET_COMMAND:
switch (camera->port->type) {
case GP_PORT_SERIAL:
packet[1] = (camera->pl->first_packet ?
SUBSIERRA_PACKET_COMMAND_FIRST :
SUBSIERRA_PACKET_COMMAND);
camera->pl->first_packet = 0;
break;
default:
packet[1] = SUBSIERRA_PACKET_COMMAND;
break;
}
break;
default:
break;
}
/* Determining packet length */
if ((packet[0] == SIERRA_PACKET_COMMAND) ||
(packet[0] == SIERRA_PACKET_DATA) ||
(packet[0] == SIERRA_PACKET_DATA_END)) {
length = ((unsigned char)packet[2]) +
((unsigned char)packet[3] * 256);
length += 6;
} else {
length = 1;
}
/* Generate the checksum */
if (length > 1) {
for (x = 4; x < length - 2; x++)
checksum += (unsigned char)packet[x];
packet[length-2] = checksum & 0xff;
packet[length-1] = (checksum >> 8) & 0xff;
}
if (camera->pl->flags & SIERRA_WRAP_USB_MASK) {
CHECK (usb_wrap_write_packet (camera->port,
(camera->pl->flags & SIERRA_WRAP_USB_MASK),
packet, length));
} else {
if (camera->pl->flags & SIERRA_NO_BLOCK_WRITE) {
for (x = 0; x < length; x++)
CHECK (gp_port_write(camera->port, &packet[x], 1));
} else {
CHECK (gp_port_write (camera->port, packet, length));
}
}
return GP_OK;
}
static int
sierra_clear_usb_halt(Camera *camera)
{
if ((camera->port->type == GP_PORT_USB) &&
!(camera->pl->flags & SIERRA_WRAP_USB_MASK) &&
!(camera->pl->flags & SIERRA_NO_USB_CLEAR))
gp_port_usb_clear_halt(camera->port, GP_PORT_USB_ENDPOINT_IN);
return (GP_OK);
}
static int
sierra_write_nak (Camera *camera, GPContext *context)
{
char buf[4096];
int ret;
GP_DEBUG ("* sierra_write_nack");
buf[0] = SIERRA_PACKET_NAK;
ret = sierra_write_packet (camera, buf, context);
sierra_clear_usb_halt(camera);
return (ret);
}
/**
* sierra_read_packet:
* @camera : camera data structure
* @packet : to return the read packet
*
* Read a data packet from the camera.
*
* Method:
* Two kinds of packet may be received from the camera :
* - either single byte length packet,
* - or several byte length packet.
*
* Structure of the several byte length packet is the following :
* Offset Length Meaning
* 0 1 Packet type
* 1 1 Packet subtype/sequence
* 2 2 Length of data
* 4 variable Data
* -2 2 Checksum
*
* The operation is successful when the packet is recognised
* and is completely retrieved without IO errors.
*
* Returns: error code
* - GP_OK if the operation is successful (see description),
* - GP_ERROR_UNKNOWN_PORT if no port was specified within
* the camera data structure,
* - GP_ERROR_CORRUPTED_DATA if the received data are invalid,
* - GP_ERROR_IO_* on other IO error.
*/
static int
sierra_read_packet (Camera *camera, unsigned char *packet, GPContext *context)
{
int result;
unsigned int i, c, r = 0, length, blocksize = 1, br;
GP_DEBUG ("Reading packet...");
switch (camera->port->type) {
case GP_PORT_USB_SCSI:
case GP_PORT_USB:
blocksize = SIERRA_PACKET_SIZE;
break;
case GP_PORT_SERIAL:
blocksize = 1;
break;
default:
return (GP_ERROR_UNKNOWN_PORT);
}
/* Try several times before leaving on error... */
while (1) {
/* Clear the USB bus
(what about the SERIAL bus : do we need to flush it?) */
sierra_clear_usb_halt(camera);
/*
* Read data through the bus. If an error occurred,
* try again.
*/
if ((camera->port->type & (GP_PORT_USB_SCSI|GP_PORT_USB)) && (camera->pl->flags & SIERRA_WRAP_USB_MASK))
result = usb_wrap_read_packet (camera->port,
(camera->pl->flags & SIERRA_WRAP_USB_MASK),
(char *)packet, blocksize);
else
result = gp_port_read (camera->port, (char *)packet, blocksize);
if (result < 0) {
GP_DEBUG ("Read failed (%i: '%s').", result,
gp_result_as_string (result));
if (++r > 2) {
sierra_clear_usb_halt(camera);
GP_DEBUG ("Giving up...");
return (result);
}
GP_DEBUG ("Retrying...");
continue;
}
if (result == 0) {
GP_DEBUG ("Read got 0 bytes..");
if (++r > 2) {
sierra_clear_usb_halt(camera);
GP_DEBUG ("Giving up...");
return GP_ERROR_IO_READ;
}
GP_DEBUG ("Retrying...");
continue;
}
br = result;
/*
* If the first read byte is not known,
* report an error and exit the processing.
*/
switch (packet[0]) {
case NUL:
case SIERRA_PACKET_ENQ:
case ACK:
case SIERRA_PACKET_INVALID:
case SIERRA_PACKET_NAK:
case SIERRA_PACKET_CANCEL:
case SIERRA_PACKET_SESSION_ERROR:
case SIERRA_PACKET_SESSION_END:
case SIERRA_PACKET_WRONG_SPEED:
/* Those are all single byte packets. */
sierra_clear_usb_halt(camera);
GP_DEBUG ("Packet type 0x%02x read. Returning GP_OK.", packet[0]);
return GP_OK;
case SIERRA_PACKET_DATA:
case SIERRA_PACKET_DATA_END:
case SIERRA_PACKET_COMMAND:
/* Those are packets with more than one byte. */
break;
default:
/*
* This byte is not valid. Dump everything that
* coming in.
*/
gp_context_error (context, _("The first byte "
"received (0x%x) is not valid."), packet[0]);
while (gp_port_read (camera->port, (char *)packet, 1) > 0)
;
sierra_clear_usb_halt(camera);
return (GP_ERROR_CORRUPTED_DATA);
}
/*
* We've got a packet containing several bytes.
* The data packet size is not known yet if the communication
* is performed through the serial bus : read it then.
*/
if (br < 4) {
result = gp_port_read (camera->port,
(char *)packet + br, 4 - br);
if (result < 0) {
sierra_clear_usb_halt(camera);
GP_DEBUG ("Could not read length of "
"packet (%i: '%s'). Giving up...",
result, gp_result_as_string (result));
return (result);
}
br += result;
}
/*
* Determine the packet length: 2 for packet type and
* subtype or sequence number, 2 for length, the actual
* data, and 2 for the checksum.
*/
length = packet[2] + (packet[3] * 256) + 6;
if (length > SIERRA_PACKET_SIZE) {
GP_DEBUG ("Packet too long (%d)!", length);
return GP_ERROR_IO;
}
/*
* Read until the end of the packet is reached
* or an error occurred.
*/
while (br < length) {
result = gp_port_read (camera->port, (char *)packet + br,
length - br);
if (result == GP_ERROR_TIMEOUT) {
/* We will retry later on. */
GP_DEBUG ("Timeout!");
break;
} else if (result < 0) {
GP_DEBUG ("Could not read remainder of "
"packet (%i: '%s'). Giving up...",
result, gp_result_as_string (result));
return (result);
} else
br += result;
}
/*
* If we have, at this point, received the full packet,
* check the checksum. If the checksum is correct, we are
* done.
*/
if (br == length) {
for (c = 0, i = 4; i < br - 2; i++)
c += packet[i];
c &= 0xffff;
if (c == ((unsigned int)packet[br - 2] + ((unsigned int)packet[br - 1] * 256)))
break;
/*
* At least the Nikon CoolPix 880 sets the checksum
* always to 0xffff. In that case, we can't check it
* and return successfully.
*/
if ((packet[br - 2] == 0xff) &&
(packet[br - 1] == 0xff))
break;
/*
* The checksum for the Toshiba PDR-M6X cameras is
* almost always set to 0x00 0x00.
*/
if ((packet[br - 2] == 0x00) &&
(packet[br - 1] == 0x00))
break;
GP_DEBUG ("Checksum wrong (calculated 0x%x, "
"found 0x%x)!", c,
packet[br - 2] + (packet[br - 1] * 256));
}
/*
* We will retry if we couldn't receive the full packet
* (GP_ERROR_TIMEOUT) or if the checksum is wrong.
*/
r++;
if (r + 1 >= RETRIES) {
sierra_clear_usb_halt(camera);
GP_DEBUG ("Giving up...");
return ((br == length) ? GP_ERROR_CORRUPTED_DATA :
GP_ERROR_TIMEOUT);
}
GP_DEBUG ("Retrying...");
sierra_write_nak (camera, context);
usleep (10 * 1000);
}
sierra_clear_usb_halt(camera);
return GP_OK;
}
static int
sierra_read_packet_wait (Camera *camera, char *buf, GPContext *context)
{
int result, r = 0;
while (1) {
if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)
return (GP_ERROR_CANCEL);
result = sierra_read_packet (camera, (unsigned char *)buf, context);
if (result == GP_ERROR_TIMEOUT) {
if (++r > 2) {
gp_context_error (context, _("Transmission "
"of packet timed out even after "
"%i retries. Please contact "
"%s."), r, MAIL_GPHOTO_DEVEL);
return GP_ERROR;
}
GP_DEBUG ("Retrying...");
usleep (QUICKSLEEP * 1000);
continue;
}
CHECK (result);
GP_DEBUG ("Packet successfully read.");
return GP_OK;
}
}
static int
sierra_transmit_ack (Camera *camera, char *packet, GPContext *context)
{
int r = 0, result;
unsigned char buf[SIERRA_PACKET_SIZE];
while (1) {
if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)
return (GP_ERROR_CANCEL);
/* Write packet and read the answer */
CHECK (sierra_write_packet (camera, packet, context));
buf[0] = 0;
result = sierra_read_packet_wait (camera, (char *)buf, context);
switch (result) {
case GP_ERROR_CORRUPTED_DATA:
if (++r > 2) {
gp_context_error (context, _("Could not "
"transmit packet even after several "
"retries."));
return (result);
}
continue;
default:
CHECK (result);
}
switch (buf[0]) {
case SIERRA_PACKET_ENQ:
case ACK:
GP_DEBUG ("Transmission successful.");
return GP_OK;
case SIERRA_PACKET_INVALID:
case SIERRA_PACKET_CANCEL:
gp_context_error (context, _("Packet was rejected "
"by camera. Please contact "
"%s."), MAIL_GPHOTO_DEVEL);
return GP_ERROR;
case SIERRA_PACKET_SESSION_END:
case SIERRA_PACKET_SESSION_ERROR:
case SIERRA_PACKET_WRONG_SPEED:
if (++r > 2) {
gp_context_error (context, _("Could not "
"transmit packet even after several "
"retries."));
return GP_ERROR;
}
/*
* The camera has ended this session and
* reverted the speed back to 19200. Reinitialize
* the connection.
*/
CHECK (sierra_init (camera, context));
CHECK (sierra_set_speed (camera, SIERRA_SPEED_19200,
context));
continue;
default:
if (++r > 2) {
gp_context_error (context, _("Could not "
"transmit packet (error code %i). "
"Please contact "
"%s."), buf[0], MAIL_GPHOTO_DEVEL);
return GP_ERROR;
}
GP_DEBUG ("Did not receive ACK. Retrying...");
continue;
}
}
}
static int
sierra_build_packet (Camera *camera, char type, char subtype,
int data_length, char *packet)
{
packet[0] = type;
switch (type) {
case SIERRA_PACKET_COMMAND:
/* sierra_write_packet will check for the first packet */
packet[1] = SUBSIERRA_PACKET_COMMAND;
break;
case SIERRA_PACKET_DATA:
case SIERRA_PACKET_DATA_END:
packet[1] = subtype;
break;
default:
GP_DEBUG ("* unknown packet type!");
}
packet[2] = data_length & 0xff;
packet[3] = (data_length >> 8) & 0xff;
return GP_OK;
}
static int
sierra_write_ack (Camera *camera, GPContext *context)
{
char buf[4096];
int ret;
GP_DEBUG ("Writing acknowledgement...");
buf[0] = ACK;
ret = sierra_write_packet (camera, buf, context);
sierra_clear_usb_halt(camera);
CHECK (ret);
GP_DEBUG ("Successfully wrote acknowledgement.");
return GP_OK;
}
int
sierra_init (Camera *camera, GPContext *context)
{
unsigned char buf[SIERRA_PACKET_SIZE], packet[4096];
int ret, r = 0;
GPPortSettings settings;
GP_DEBUG ("Sending initialization sequence to the camera");
/* Only serial connections need to be initialized. */
if (camera->port->type != GP_PORT_SERIAL)
return GP_OK;
/*
* It seems that the initialization sequence needs to be sent at
* 19200.
*/
CHECK (gp_port_get_settings (camera->port, &settings));
if (settings.serial.speed != 19200) {
settings.serial.speed = 19200;
CHECK (gp_port_set_settings (camera->port, settings));
}
CHECK (gp_port_set_pin (camera->port, GP_PIN_DTR, GP_LEVEL_HIGH));
packet[0] = NUL;
while (1) {
/* Send NUL */
CHECK (sierra_write_packet (camera, (char *)packet, context));
/* Read the response */
ret = sierra_read_packet (camera, buf, context);
if (ret == GP_ERROR_TIMEOUT) {
if (++r > 2) {
gp_context_error (context,
_("Transmission timed out even after "
"2 retries. Giving up..."));
return (GP_ERROR_TIMEOUT);
}
GP_DEBUG ("Retrying...");
continue;
}
CHECK (ret);
switch (buf[0]) {
case SIERRA_PACKET_NAK:
/* Everything is fine. */
return GP_OK;
case SIERRA_PACKET_SESSION_END:
default:
if (++r > 3) {
gp_context_error (context,
_("Got unexpected result "
"0x%x. Please contact "
"%s."),
buf[0], MAIL_GPHOTO_DEVEL);
return GP_ERROR;
}
break;
}
}
}
static struct {
SierraSpeed speed;
int bit_rate;
} SierraSpeeds[] = {
{SIERRA_SPEED_9600 , 9600},
{SIERRA_SPEED_19200 , 19200},
{SIERRA_SPEED_38400 , 38400},
{SIERRA_SPEED_57600 , 57600},
{SIERRA_SPEED_115200, 115200},
{0, 0}
};
int
sierra_set_speed (Camera *camera, SierraSpeed speed, GPContext *context)
{
GPPortSettings settings;
unsigned int i, bit_rate;
/* Only serial connections have different speeds. */
if (camera->port->type != GP_PORT_SERIAL)
return GP_OK;
/*
* Check that the requested speed is valid. We don't want to bug
* the user with our coding errors, therefore if the requested
* speed is invalid, we use 19200.
*/
for (i = 0; SierraSpeeds[i].bit_rate; i++)
if (SierraSpeeds[i].speed == speed)
break;
if (SierraSpeeds[i].bit_rate)
bit_rate = SierraSpeeds[i].bit_rate;
else {
GP_DEBUG ("Invalid speed %i. Using %i (19200, default).",
speed, SIERRA_SPEED_19200);
speed = SIERRA_SPEED_19200;
bit_rate = 19200;
}
/*
* Check if we need to change the speed or if we are currently
* using the requested speed. The reason why we are doing that is
* that (at least some) cameras reject the request for a speed if
* they are currently operating at that speed.
*/
CHECK (gp_port_get_settings (camera->port, &settings));
if ((unsigned int)settings.serial.speed == bit_rate)
return GP_OK;
/*
* Tell the camera about the new speed. Note that a speed change
* automatically starts a new session.
*/
GP_DEBUG ("Setting speed to %i (%i bps)", speed, bit_rate);
camera->pl->first_packet = 1;
CHECK (sierra_set_int_register (camera, 17, speed, context));
/* Now switch the port to the new speed. */
CHECK (gp_port_get_settings (camera->port, &settings));
settings.serial.speed = bit_rate;
CHECK (gp_port_set_settings (camera->port, settings));
CHECK (gp_port_set_pin (camera->port, GP_PIN_DTR, GP_LEVEL_HIGH));
usleep (10 * 1000);
return GP_OK;
}
int sierra_sub_action (Camera *camera, SierraAction action, int sub_action,
GPContext *context)
{
char buf[SIERRA_PACKET_SIZE];
CHECK (sierra_build_packet (camera, SIERRA_PACKET_COMMAND, 0, 3, buf));
buf[4] = 0x02;
buf[5] = action;
buf[6] = sub_action;
GP_DEBUG ("sierra_sub_action: action %d, sub action %d", action,
sub_action);
CHECK (sierra_transmit_ack (camera, buf, context));
GP_DEBUG ("Waiting for acknowledgement...");
CHECK (sierra_read_packet_wait (camera, buf, context));
switch (buf[0]) {
case ACK: /* reported on capture on Olympus 4040 */
case SIERRA_PACKET_ENQ:
return (GP_OK);
default:
gp_context_error (context, _("Received unexpected answer "
"(%i). Please contact %s."), buf[0], MAIL_GPHOTO_DEVEL);
return (GP_ERROR);
}
return GP_OK;
}
static int
sierra_action (Camera *camera, SierraAction action, GPContext *context)
{
return(sierra_sub_action (camera, action, 0, context));
}
int
sierra_set_int_register (Camera *camera, int reg, int value,
GPContext *context)
{
char p[4096];
GP_DEBUG ("sierra_set_int_register: register %i value %i", reg, value);
CHECK (sierra_build_packet (camera, SIERRA_PACKET_COMMAND, 0,
(value < 0) ? 2 : 6, p));
/* Fill in the data */
p[4] = 0x00;
p[5] = reg;
if (value >= 0) {
p[6] = (value) & 0xff;
p[7] = (value>>8) & 0xff;
p[8] = (value>>16) & 0xff;
p[9] = (value>>24) & 0xff;
}
/* Send packet */
CHECK (sierra_transmit_ack (camera, p, context));
return GP_OK;
}
int sierra_get_int_register (Camera *camera, int reg, int *value, GPContext *context)
{
int r = 0;
unsigned char p[4096], buf[SIERRA_PACKET_SIZE];
GP_DEBUG ("sierra_get_int_register: register 0x%02x...", reg);
/* Build and send the packet. */
CHECK (sierra_build_packet (camera, SIERRA_PACKET_COMMAND, 0, 2, (char *)p));
p[4] = 0x01;
p[5] = reg;
CHECK (sierra_write_packet (camera, (char *)p, context));
while (1) {
/* Read the response */
buf[0] = 0;
CHECK (sierra_read_packet_wait (camera, (char *)buf, context));
GP_DEBUG ("Successfully read packet. Interpreting result "
"(0x%02x)", buf[0]);
switch (buf[0]) {
case SIERRA_PACKET_INVALID:
gp_context_error (context, _("Could not get "
"register %i. Please contact "
"%s."), reg, MAIL_GPHOTO_DEVEL);
return GP_ERROR;
case SIERRA_PACKET_DATA_END:
r = ((unsigned char) buf[4]) +
((unsigned char) buf[5] * 256) +
((unsigned char) buf[6] * 65536) +
((unsigned char) buf[7] * 16777216);
*value = r;
GP_DEBUG ("Value of register 0x%02x: 0x%02x. ", reg, r);
CHECK (sierra_write_ack (camera, context));
GP_DEBUG ("Read value of register 0x%02x and wrote "
"acknowledgement. Returning.", reg);
return GP_OK;
case SIERRA_PACKET_SESSION_END:
case SIERRA_PACKET_SESSION_ERROR:
case SIERRA_PACKET_WRONG_SPEED:
if (++r > 2) {
gp_context_error (context, _("Too many "
"retries failed."));
return GP_ERROR;
}
/*
* The camera has ended this session and
* reverted the speed back to 19200. Reinitialize
* the connection and resend the packet. We use the
* default speed from now on.
*/
CHECK (sierra_init (camera, context));
CHECK (sierra_set_speed (camera, SIERRA_SPEED_19200,
context));
CHECK (sierra_write_packet (camera, (char *)p, context));
break;
default:
if (++r > 2) {
gp_context_error (context, _("Too many "
"retries failed."));
return GP_ERROR;
}
/* Tell the camera to send again. */
CHECK (sierra_write_nak (camera, context));
break;
}
}
return GP_ERROR_IO;
}
int
sierra_set_string_register (Camera *camera, int reg, const char *s,
long int length, GPContext *context)
{
char packet[4096];
char type;
long int x=0;
int seq=0, size=0;
int do_percent;
unsigned int id = 0;
GP_DEBUG ("sierra_set_string_register: reg %i, value '%s'", reg, s);
/* Make use of the progress bar when the packet is "large enough" */
if (length > MAX_DATA_FIELD_LENGTH) {
do_percent = 1;
/*
* This code can lead to recursive calls in gtkam - the
* main problem is when thumbnails are being downloaded,
* gtkam tries to download another thumbnail when
* gp_context_progress_update() is called. There are also
* other areas in gtkam that can recursively call into
* this function.
*/
id = gp_context_progress_start (context, length,
_("Sending data..."));
}
else
do_percent = 0;
while (x < length) {
if (x == 0) {
type = SIERRA_PACKET_COMMAND;
size = (length + 2 - x) > MAX_DATA_FIELD_LENGTH
? MAX_DATA_FIELD_LENGTH : length + 2;
} else {
size = (length - x) > MAX_DATA_FIELD_LENGTH
? MAX_DATA_FIELD_LENGTH : length-x;
if (x + size < length)
type = SIERRA_PACKET_DATA;
else
type = SIERRA_PACKET_DATA_END;
}
CHECK (sierra_build_packet (camera, type, seq, size, packet));
if (type == SIERRA_PACKET_COMMAND) {
packet[4] = 0x03;
packet[5] = reg;
memcpy (&packet[6], &s[x], size-2);
x += size - 2;
} else {
packet[1] = seq++;
memcpy (&packet[4], &s[x], size);
x += size;
}
/* Transmit packet */
CHECK (sierra_transmit_ack (camera, packet, context));
if (do_percent)
gp_context_progress_update (context, id, x);
}
if (do_percent)
gp_context_progress_stop (context, id);
return GP_OK;
}
int sierra_get_string_register (Camera *camera, int reg, int fnumber,
CameraFile *file, unsigned char *b,
unsigned int *b_len, GPContext *context)
{
unsigned char p[34816];
unsigned int packlength, total = (b_len) ? *b_len : 0;
int retries, r;
unsigned int min_progress_bytes;
static int in_function = 0;
unsigned int id = 0;
GP_DEBUG ("sierra_get_string_register: reg %i, file number %i, "
" total %d, flags 0x%x", reg, fnumber, total,
camera->pl->flags);
if (in_function != 0) {
gp_context_error (context, _("recursive calls are not"
" supported by the sierra driver! Please contact"
" %s."), MAIL_GPHOTO_DEVEL);
return GP_ERROR;
}
in_function = 1;
/* Set the current picture number */
if (fnumber >= 0)
CHECK (sierra_set_int_register (camera, 4, fnumber, context));
/* Build and send the request */
CHECK (sierra_build_packet (camera, SIERRA_PACKET_COMMAND, 0, 2, (char *)p));
/*
* If the extended protocol is enabled, use code 0x06 so we can send
* and receive 32k size packages, otherwise code 0x04 is used and
* we have 2k size packages.
*/
if (camera->pl->flags & SIERRA_EXT_PROTO) {
p[4] = 0x06;
min_progress_bytes = 32 * 1024;
} else {
p[4] = 0x04;
min_progress_bytes = 2 * 1024;
}
p[5] = reg;
CHECK (sierra_write_packet (camera, (char *)p, context));
if (file && total > min_progress_bytes) {
id = gp_context_progress_start (context, total, _("Downloading data..."));
}
/* Read all the data packets */
*b_len = 0;
retries = 0;
do {
/* Read one packet and retry on timeout. */
r = sierra_read_packet (camera, p, context);
if (r == GP_ERROR_TIMEOUT) {
if (++retries > RETRIES) {
in_function = 0;
return (r);
}
GP_DEBUG ("Timeout! Retrying (%i of %i)...",
retries, RETRIES);
CHECK (sierra_write_nak (camera, context));
continue;
}
CHECK (r);
GP_DEBUG ("sierra_get_string_register p[0] is %d", p[0]);
switch (p[0]) {
case SIERRA_PACKET_INVALID:
gp_context_error (context, _("Could not get "
"string register %i. Please contact "
"%s."), reg, MAIL_GPHOTO_DEVEL);
in_function = 0;
return GP_ERROR;
default:
break;
}
CHECK (sierra_write_ack (camera, context));
packlength = p[2] | (p[3] << 8);
GP_DEBUG ("Packet length: %d", packlength);
if (b)
memcpy (&b[*b_len], &p[4], packlength);
*b_len += packlength;
if (file) {
CHECK (gp_file_append (file, (char *)&p[4], packlength));
if (total > min_progress_bytes)
gp_context_progress_update (context, id, *b_len);
}
} while (p[0] != SIERRA_PACKET_DATA_END);
if (file && total > min_progress_bytes)
gp_context_progress_stop (context, id);
GP_DEBUG ("sierra_get_string_register: completed OK, *b_len %d",
*b_len);
in_function = 0;
return GP_OK;
}
int
sierra_delete_all (Camera *camera, GPContext *context)
{
CHECK (sierra_action (camera, SIERRA_ACTION_DELETE_ALL, context));
return GP_OK;
}
int
sierra_delete (Camera *camera, int picture_number, GPContext *context)
{
/* Tell the camera which picture to delete and execute command. */
CHECK (sierra_set_int_register (camera, 4, picture_number, context));
CHECK (sierra_action (camera, SIERRA_ACTION_DELETE, context));
return GP_OK;
}
int
sierra_end_session (Camera *camera, GPContext *context)
{
CHECK (sierra_action (camera, SIERRA_ACTION_END, context));
return GP_OK;
}
int
sierra_capture_preview (Camera *camera, CameraFile *file, GPContext *context)
{
unsigned int size;
/* Send to the camera the capture request and wait
for the completion */
CHECK (sierra_action (camera, SIERRA_ACTION_PREVIEW, context));
/* Retrieve the preview and set the MIME type */
CHECK (sierra_get_int_register (camera, 12, (int *)&size, context));
CHECK (sierra_get_string_register (camera, 14, 0, file, NULL, &size,
context));
CHECK (gp_file_set_mime_type (file, GP_MIME_JPEG));
return GP_OK;
}
int
sierra_capture (Camera *camera, CameraCaptureType type,
CameraFilePath *filepath, GPContext *context)
{
int n, r;
unsigned int len = 0;
char filename[128];
char *folder;
int timeout;
GP_DEBUG ("* sierra_capture");
/* We can only capture images */
if (type != GP_CAPTURE_IMAGE)
return GP_ERROR_NOT_SUPPORTED;
/*
* This is a non-fatal check if a memory card is present. Some
* cameras don't understand this command and error out here.
* Since some cameras do not like it at all, do not send it for those.
*/
if (!(camera->pl->flags & SIERRA_NO_51)) {
r = sierra_get_int_register (camera, 51, &n, context);
if ((r >= 0) && (n == 1)) {
gp_context_error (context, _("No memory card present"));
return GP_ERROR_NOT_SUPPORTED;
}
}
/*
* Raise the timeout before the capture, since it can take longer,
* the shutter speed alone could push us over 10 seconds.
*/
CHECK (gp_port_get_timeout (camera->port, &timeout));
CHECK (gp_port_set_timeout (camera->port, 20000)); /* 20 seconds */
/* Send to the camera the capture request and wait
for the completion */
CHECK (sierra_action (camera, SIERRA_ACTION_CAPTURE, context));
CHECK (gp_port_set_timeout (camera->port, timeout));
if (filepath != NULL) {
/*
* After the picture is taken, register 4 is set to the
* current picture.
*/
GP_DEBUG ("Getting picture number.");
r = sierra_get_int_register (camera, 4, &n, context);
if (r == GP_OK) {
GP_DEBUG ("Getting filename of file %i.", n);
}
/*
* We need to tell the frontend where the new image can be
* found. Unfortunately, we can only figure out the
* filename. Therefore, reset the CameraFilesystem and let
* it search for the filename.
*
* If you know how to figure out where the image gets
* saved, please submit a patch.
*
* Not that some cameras that don't support filenames will
* return 8 blanks instead of reporting an error.
*
* Some newer cameras (Nikon*) do not return register 4, so
* ignore errors from that.
*/
CHECK (sierra_get_string_register (camera, 79, 0, NULL,
(unsigned char *)filename,
&len, context));
if ((len <= 0) || !strcmp (filename, " "))
snprintf (filename, sizeof (filename), "P101%04i.JPG", n);
GP_DEBUG ("... done ('%s')", filename);
CHECK (gp_filesystem_reset (camera->fs));
CHECK (gp_filesystem_get_folder (camera->fs, filename,
&folder, context));
strncpy (filepath->folder, folder, sizeof (filepath->folder));
strncpy (filepath->name, filename, sizeof (filepath->name));
}
GP_DEBUG ("* sierra_capture completed OK");
return GP_OK;
}
int sierra_upload_file (Camera *camera, CameraFile *file, GPContext *context)
{
const char *data;
long unsigned int data_size;
/* Put the "magic spell" in register 32 */
CHECK (sierra_set_int_register (camera, 32, 0x0FEC000E, context));
/* Upload the file */
CHECK (gp_file_get_data_and_size (file, &data, &data_size));
CHECK (sierra_set_string_register (camera, 29, data, data_size, context));
/* Send command to order the transfer into NVRAM and wait
for the completion */
CHECK (sierra_action (camera, SIERRA_ACTION_UPLOAD, context));
return GP_OK;
}
static unsigned int
get_int (const unsigned char b[])
{
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
}
int sierra_get_pic_info (Camera *camera, unsigned int n,
SierraPicInfo *pic_info, GPContext *context)
{
unsigned char buf[1024];
unsigned int buf_len = 0;
int value, audio_info[8];
CHECK (sierra_get_string_register (camera, 47, n, NULL, buf,
&buf_len, context));
if (buf_len == 0) {
/*
* Many (older) serial cameras seem to return 0 bytes back
* and effectively do not support register 47. Try using
* other registers to get the data.
*
* Don't fail on error so unsupported or semi-broken
* behaviour does not prevent downloads or other use.
*/
memset(pic_info, 0, sizeof(*pic_info));
if (sierra_get_size(camera, 12, n, &value, context) == GP_OK) {
pic_info->size_file = value;
}
if (sierra_get_size(camera, 13, n, &value, context) == GP_OK) {
pic_info->size_preview = value;
}
/*
* If the following hangs any cameras, just delete this
* code, and assume that cameras with audio will get audio
* file information via reg 47.
*
* Note that the value variable as used here is number of
* bytes transferred, not the returned data. Some
* unsupported sierra commands return zero bytes.
*/
if ((sierra_get_string_register (camera, 43, n, NULL,
(unsigned char *) &audio_info,
(unsigned int *)&value,
context) == GP_OK) && (value != 0)) {
pic_info->size_audio = audio_info[0];
}
if (sierra_get_int_register (camera, 39, &value, context)
== GP_OK) {
pic_info->locked = value;
} else {
/*
* Default to marking as locked (not-deletable).
* It looks the file can still be deleted if the
* file is not really locked.
*/
pic_info->locked = SIERRA_LOCKED_YES;
}
return (GP_OK);
}
if (buf_len != 32) {
gp_context_error (context, _("Expected 32 bytes, got %i. "
"Please contact %s."), buf_len, MAIL_GPHOTO_DEVEL);
return (GP_ERROR_CORRUPTED_DATA);
}
pic_info->size_file = get_int (buf);
pic_info->size_preview = get_int (buf + 4);
pic_info->size_audio = get_int (buf + 8);
pic_info->resolution = get_int (buf + 12);
pic_info->locked = get_int (buf + 16);
pic_info->date = get_int (buf + 20);
pic_info->animation_type = get_int (buf + 28);
/* Make debugging easier */
GP_DEBUG ("sierra_get_pic_info ");
GP_DEBUG ("File size: %d", pic_info->size_file);
GP_DEBUG ("Preview size: %i", pic_info->size_preview);
GP_DEBUG ("Audio size: %i", pic_info->size_audio);
GP_DEBUG ("Resolution: %i", pic_info->resolution);
GP_DEBUG ("Locked: %i", pic_info->locked);
GP_DEBUG ("Date: %i", pic_info->date);
GP_DEBUG ("Animation type: %i", pic_info->animation_type);
return GP_OK;
}
int sierra_set_locked (Camera *camera, unsigned int n, SierraLocked locked,
GPContext *context)
{
CHECK (sierra_set_int_register (camera, 4, n, context));
CHECK (sierra_sub_action (camera, SIERRA_ACTION_PROT_STATE,
(int) locked, context));
return GP_OK;
}
int sierra_get_size (Camera *camera, int reg, unsigned int n, int *value,
GPContext *context)
{
CHECK (sierra_set_int_register (camera, 4, n, context));
CHECK (sierra_get_int_register (camera, reg, value, context));
return GP_OK;
}