git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@2152 67ed7778-7388-44ab-90cf-0a291f65f57c
584 lines
19 KiB
C
584 lines
19 KiB
C
/******************************************************************************/
|
|
/* See lowlevel.h for licence and details. */
|
|
/******************************************************************************/
|
|
|
|
|
|
/*************************/
|
|
/* Included header files */
|
|
/*************************/
|
|
#include <gphoto2.h>
|
|
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "library.h"
|
|
#include "lowlevel.h"
|
|
|
|
|
|
/***************/
|
|
/* Definitions */
|
|
/***************/
|
|
#define DEFAULT_TIMEOUT 500
|
|
#define STX 0x02 /****************/
|
|
#define ETX 0x03 /* */
|
|
#define ENQ 0x05 /* */
|
|
#define ACK 0x06 /* */
|
|
#define XOFF 0x11 /* ESC quotes. */
|
|
#define XON 0x13 /* */
|
|
#define NACK 0x15 /* */
|
|
#define ETB 0x17 /* */
|
|
#define ESC 0x1b /****************/
|
|
#define EOT 0x04
|
|
|
|
|
|
/**************/
|
|
/* Prototypes */
|
|
/**************/
|
|
gint l_esc_read (gp_port* device, guchar* c);
|
|
|
|
|
|
gint l_send (gp_port* device, guchar* send_buffer, guint send_buffer_size);
|
|
|
|
|
|
gint l_receive (gp_port* device, guchar** rb, guint* rbs, guint timeout);
|
|
|
|
|
|
/*************/
|
|
/* Functions */
|
|
/*************/
|
|
gint
|
|
l_init (gp_port* device)
|
|
{
|
|
guchar c;
|
|
gint i;
|
|
gint result;
|
|
|
|
g_return_val_if_fail (device, GP_ERROR_BAD_PARAMETERS);
|
|
|
|
gp_port_timeout_set (device, DEFAULT_TIMEOUT);
|
|
for (i = 0; ; i++) {
|
|
/****************/
|
|
/* Write ENQ. */
|
|
/****************/
|
|
if ((result = gp_port_write (device, "\5", 1)) != GP_OK) return (result);
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) {
|
|
/******************************************************/
|
|
/* We didn't receive anything. We'll try up to five */
|
|
/* time. */
|
|
/******************************************************/
|
|
if (i == 4)
|
|
return (result);
|
|
continue;
|
|
}
|
|
switch (c) {
|
|
case ACK:
|
|
/******************************************************/
|
|
/* ACK received. We can proceed. */
|
|
/******************************************************/
|
|
return (GP_OK);
|
|
default:
|
|
/******************************************************/
|
|
/* The camera seems to be sending something. We'll */
|
|
/* dump all bytes we get and try again. */
|
|
/******************************************************/
|
|
while (gp_port_read (device, &c, 1) > 0);
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
gint
|
|
l_esc_read (gp_port* device, guchar* c)
|
|
{
|
|
gint result;
|
|
|
|
g_return_val_if_fail (device, GP_ERROR_BAD_PARAMETERS);
|
|
|
|
if ((result = gp_port_read (device, c, 1)) < 1) return (result);
|
|
/**********************************************************************/
|
|
/* STX, ETX, ENQ, ACK, XOFF, XON, NACK, and ETB have to be masked by */
|
|
/* ESC. If we receive one of those (except ETX and ETB) without mask, */
|
|
/* we will not report an error, as it will be recovered automatically */
|
|
/* later. If we receive ETX or ETB, we reached the end of the packet */
|
|
/* and report a transmission error, so that the error can be */
|
|
/* recovered. */
|
|
/* If the camera sends us ESC (the mask), we will not count this byte */
|
|
/* and read a second one. This will be reverted and processed. It */
|
|
/* then must be one of STX, ETX, ENQ, ACK, XOFF, XON, NACK, ETB, or */
|
|
/* ESC. As before, if it is not one of those, we'll not report an */
|
|
/* error, as it will be recovered automatically later. */
|
|
/**********************************************************************/
|
|
if ((*c == STX ) || (*c == ETX) || (*c == ENQ ) || (*c == ACK) || (*c == XOFF) || (*c == XON) || (*c == NACK) || (*c == ETB)) {
|
|
gp_debug_printf (GP_DEBUG_HIGH, "konica", "Wrong ESC masking!");
|
|
if ((*c == ETX) || (*c == ETB)) return (GP_ERROR_CORRUPTED_DATA);
|
|
|
|
} else if (*c == ESC) {
|
|
if ((result = gp_port_read (device, c, 1)) < 1) return (result);
|
|
*c = (~*c & 0xff);
|
|
if ((*c != STX ) && (*c != ETX ) && (*c != ENQ) && (*c != ACK ) && (*c != XOFF) && (*c != XON) && (*c != NACK) && (*c != ETB ) && (*c != ESC))
|
|
gp_debug_printf (GP_DEBUG_HIGH, "konica", "Wrong ESC masking!");
|
|
}
|
|
return (GP_OK);
|
|
}
|
|
|
|
|
|
gint
|
|
l_send (gp_port* device, guchar* send_buffer, guint send_buffer_size)
|
|
{
|
|
guchar c;
|
|
guchar checksum;
|
|
/**********************************************************************/
|
|
/* sb: A pointer to the buffer that we will send. */
|
|
/* sbs: Its size. */
|
|
/**********************************************************************/
|
|
guchar* sb;
|
|
guint sbs;
|
|
gint i;
|
|
gint result;
|
|
|
|
g_return_val_if_fail (device, GP_ERROR_BAD_PARAMETERS);
|
|
|
|
i = 0;
|
|
for (;;) {
|
|
/****************/
|
|
/* Write ENQ. */
|
|
/****************/
|
|
if ((result = gp_port_write (device, "\5", 1)) != GP_OK) return (result);
|
|
/****************/
|
|
/* Read. */
|
|
/****************/
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) {
|
|
/************************************/
|
|
/* Let's try for a couple of times. */
|
|
/************************************/
|
|
i++;
|
|
if (i == 5) return (result);
|
|
continue;
|
|
}
|
|
switch (c) {
|
|
case ACK:
|
|
/****************************************/
|
|
/* ACK received. We can proceed. */
|
|
/****************************************/
|
|
break;
|
|
case NACK:
|
|
/****************************************/
|
|
/* NACK received. We'll start from the */
|
|
/* beginning. */
|
|
/****************************************/
|
|
continue;
|
|
case ENQ:
|
|
/******************************************************/
|
|
/* ENQ received. It seems that the camera would like */
|
|
/* to send us data, but we do not want it and */
|
|
/* therefore simply reject it. The camera will try */
|
|
/* two more times with ENQ to get us to receive data */
|
|
/* before finally giving up and sending us ACK. */
|
|
/******************************************************/
|
|
/****************/
|
|
/* Write NACK. */
|
|
/****************/
|
|
c = NACK;
|
|
if ((result = gp_port_write (device, &c, 1)) != GP_OK) return (result);
|
|
for (;;) {
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) return (result);
|
|
switch (c) {
|
|
case ENQ:
|
|
/**************************************/
|
|
/* The camera has not yet given up. */
|
|
/**************************************/
|
|
continue;
|
|
case ACK:
|
|
/**************************************/
|
|
/* ACK received. We can proceed. */
|
|
/**************************************/
|
|
break;
|
|
default:
|
|
/**************************************/
|
|
/* This should not happen. */
|
|
/**************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
/******************************************************/
|
|
/* The camera seems to send us data. We'll */
|
|
/* simply dump it and try again. */
|
|
/******************************************************/
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
/********************************************************/
|
|
/* We will write: */
|
|
/* - STX */
|
|
/* - low order byte of (send_buffer_size + 5) */
|
|
/* - high order byte of (send_buffer_size + 5) */
|
|
/* - 'send_buffer_size' bytes data plus ESC quotes */
|
|
/* - ETX */
|
|
/* - 1 byte for checksum plus ESC quotes */
|
|
/* */
|
|
/* The checksum covers all bytes after STX and before */
|
|
/* the checksum byte(s). */
|
|
/********************************************************/
|
|
sbs = send_buffer_size + 5;
|
|
sb = g_new (guchar, sbs);
|
|
sb[0] = STX;
|
|
sb[1] = send_buffer_size;
|
|
sb[2] = send_buffer_size >> 8;
|
|
checksum = sb[1];
|
|
checksum += sb[2];
|
|
for (i = 3; i < (sbs - 2); i++) {
|
|
checksum += *send_buffer;
|
|
if ( (*send_buffer == STX ) ||
|
|
(*send_buffer == ETX ) ||
|
|
(*send_buffer == ENQ ) ||
|
|
(*send_buffer == ACK ) ||
|
|
(*send_buffer == XOFF) ||
|
|
(*send_buffer == XON ) ||
|
|
(*send_buffer == NACK) ||
|
|
(*send_buffer == ETB ) ||
|
|
(*send_buffer == ESC )) {
|
|
sb = g_renew (guchar, sb, ++sbs);
|
|
sb[ i] = ESC;
|
|
sb[++i] = ~*send_buffer;
|
|
} else sb[ i] = *send_buffer;
|
|
send_buffer++;
|
|
}
|
|
sb[sbs - 2] = ETX;
|
|
checksum += ETX;
|
|
if ( (checksum == STX ) ||
|
|
(checksum == ETX ) ||
|
|
(checksum == ENQ ) ||
|
|
(checksum == ACK ) ||
|
|
(checksum == XOFF) ||
|
|
(checksum == XON ) ||
|
|
(checksum == NACK) ||
|
|
(checksum == ETB ) ||
|
|
(checksum == ESC )) {
|
|
sb = g_renew (guchar, sb, ++sbs);
|
|
sb[sbs - 2] = ESC;
|
|
sb[sbs - 1] = ~checksum;
|
|
} else sb[sbs - 1] = checksum;
|
|
for (i = 0; ; i++) {
|
|
/************************/
|
|
/* Write data as above. */
|
|
/************************/
|
|
if ((result = gp_port_write (device, sb, sbs)) != GP_OK) {
|
|
g_free (sb);
|
|
return (result);
|
|
}
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) {
|
|
g_free (sb);
|
|
return (result);
|
|
}
|
|
switch (c) {
|
|
case ACK:
|
|
/******************************************************/
|
|
/* ACK received. We can proceed. */
|
|
/******************************************************/
|
|
g_free (sb);
|
|
/****************/
|
|
/* Write EOT. */
|
|
/****************/
|
|
c = EOT;
|
|
if ((result = gp_port_write (device, &c, 1)) != GP_OK) return (result);
|
|
return (GP_OK);
|
|
case NACK:
|
|
/******************************************************/
|
|
/* NACK received. We'll try up to three times. */
|
|
/******************************************************/
|
|
if (i == 2) {
|
|
g_free (sb);
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
} else break;
|
|
default:
|
|
/******************************************************/
|
|
/* Should not happen. */
|
|
/******************************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
gint
|
|
l_receive (gp_port* device, guchar** rb, guint* rbs, guint timeout)
|
|
{
|
|
guchar c, d;
|
|
gboolean error_flag;
|
|
guint i, j, rbs_internal;
|
|
guchar checksum;
|
|
gint result;
|
|
|
|
g_return_val_if_fail (device, GP_ERROR_BAD_PARAMETERS);
|
|
|
|
for (i = 0; ; ) {
|
|
gp_port_timeout_set (device, timeout);
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) return (result);
|
|
gp_port_timeout_set (device, DEFAULT_TIMEOUT);
|
|
switch (c) {
|
|
case ENQ:
|
|
/******************************************************/
|
|
/* ENQ received. We can proceed. */
|
|
/******************************************************/
|
|
break;
|
|
case ACK:
|
|
/******************************************************/
|
|
/* ACK received. We'll try again at most ten times. */
|
|
/******************************************************/
|
|
if (i == 9) {
|
|
/**********************************************/
|
|
/* The camera hangs! Although it could be */
|
|
/* that the camera accepts one of the */
|
|
/* commands */
|
|
/* - KONICA_CANCEL, */
|
|
/* - KONICA_GET_IO_CAPABILITY, and */
|
|
/* - KONICA_SET_IO_CAPABILITY, */
|
|
/* we can not get the camera back to working */
|
|
/* correctly. */
|
|
/**********************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
i++;
|
|
break;
|
|
default:
|
|
/******************************************************/
|
|
/* We'll dump this data until we get ENQ (then, we'll */
|
|
/* proceed) or nothing any more (then, we'll report */
|
|
/* error). */
|
|
/******************************************************/
|
|
for (;;) {
|
|
if ((result = gp_port_read (device, &c, 1)) < 0) return (result);
|
|
if (c == ENQ) break;
|
|
}
|
|
break;
|
|
}
|
|
if (c == ENQ) break;
|
|
}
|
|
/**************/
|
|
/* Write ACK. */
|
|
/**************/
|
|
if ((result = gp_port_write (device, "\6", 1)) != GP_OK) return (result);
|
|
for (*rbs = 0; ; ) {
|
|
for (j = 0; ; j++) {
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) return (result);
|
|
switch (c) {
|
|
case STX:
|
|
/**********************************************/
|
|
/* STX received. We can proceed. */
|
|
/**********************************************/
|
|
break;
|
|
default:
|
|
/**********************************************/
|
|
/* We'll dump this data and try again. */
|
|
/**********************************************/
|
|
continue;
|
|
}
|
|
/******************************************************/
|
|
/* Read 2 bytes for size (low order byte, high order */
|
|
/* byte) plus ESC quotes. */
|
|
/******************************************************/
|
|
result = l_esc_read (device, &c);
|
|
if (result != GP_OK) return (result);
|
|
checksum = c;
|
|
result = l_esc_read (device, &d);
|
|
if (result != GP_OK) return (result);
|
|
checksum += d;
|
|
rbs_internal = (d << 8) | c;
|
|
if (*rbs == 0) *rb = g_new (guchar, rbs_internal);
|
|
else *rb = g_renew (guchar, *rb, *rbs + rbs_internal);
|
|
/******************************************************/
|
|
/* Read 'rbs_internal' bytes data plus ESC quotes. */
|
|
/******************************************************/
|
|
error_flag = FALSE;
|
|
for (i = 0; i < rbs_internal; i++) {
|
|
result = l_esc_read (device, &((*rb)[*rbs + i]));
|
|
switch (result) {
|
|
case GP_ERROR_CORRUPTED_DATA:
|
|
/**************************************/
|
|
/* We already received ETX or ETB. */
|
|
/* Later, we'll read the checksum */
|
|
/* plus ESC quotes and reject the */
|
|
/* packet. */
|
|
/**************************************/
|
|
error_flag = TRUE;
|
|
break;
|
|
case GP_OK:
|
|
/**************************************/
|
|
/* We can proceed. */
|
|
/**************************************/
|
|
checksum += (*rb)[*rbs + i];
|
|
break;
|
|
default:
|
|
return (result);
|
|
}
|
|
if (error_flag) break;
|
|
}
|
|
if (!error_flag) {
|
|
if ((result = gp_port_read (device, &d, 1)) < 1) return (result);
|
|
switch (d) {
|
|
case ETX:
|
|
/**************************************/
|
|
/* ETX received. This is the last */
|
|
/* packet. */
|
|
/**************************************/
|
|
break;
|
|
case ETB:
|
|
/**************************************/
|
|
/* ETB received. There are more */
|
|
/* packets to come. */
|
|
/**************************************/
|
|
break;
|
|
default:
|
|
/**************************************/
|
|
/* We get more bytes than expected. */
|
|
/* Nothing serious, as we will simply */
|
|
/* dump all bytes until we receive */
|
|
/* ETX or ETB. Later, we'll read the */
|
|
/* checksum with ESC quotes and */
|
|
/* reject the packet. */
|
|
/**************************************/
|
|
while ((d != ETX) && (d != ETB)) {
|
|
if ((result = gp_port_read (device, &d, 1)) < 1) return (result);
|
|
}
|
|
error_flag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
checksum += d;
|
|
/******************************************************/
|
|
/* Read 1 byte for checksum plus ESC quotes. */
|
|
/******************************************************/
|
|
if ((result = l_esc_read (device, &c)) != GP_OK) return (result);
|
|
if ((c == checksum) && (!error_flag)) {
|
|
*rbs += rbs_internal;
|
|
/****************/
|
|
/* Write ACK. */
|
|
/****************/
|
|
if ((result = gp_port_write (device, "\6", 1)) != GP_OK) return (result);
|
|
break;
|
|
} else {
|
|
/**********************************************/
|
|
/* Checksum wrong or transmission error. The */
|
|
/* camera will send us the data at the most */
|
|
/* three times. */
|
|
/**********************************************/
|
|
if (j == 2) return (GP_ERROR_CORRUPTED_DATA);
|
|
/****************/
|
|
/* Write NACK. */
|
|
/****************/
|
|
c = NACK;
|
|
if ((result = gp_port_write (device, &c, 1)) != GP_OK) return (result);
|
|
continue;
|
|
}
|
|
}
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) return (result);
|
|
switch (c) {
|
|
case EOT:
|
|
/**********************************************/
|
|
/* EOT received. We can proceed. */
|
|
/**********************************************/
|
|
break;
|
|
default:
|
|
/**********************************************/
|
|
/* Should not happen. */
|
|
/**********************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
/**************************************************************/
|
|
/* Depending on d, we will either continue to receive data or */
|
|
/* stop. */
|
|
/* - ETX: We are all done. */
|
|
/* - ETB: We expect more data. */
|
|
/* - else: Should not happen. */
|
|
/**************************************************************/
|
|
switch (d) {
|
|
case ETX:
|
|
/******************************************************/
|
|
/* We are all done. */
|
|
/******************************************************/
|
|
return (GP_OK);
|
|
case ETB:
|
|
/******************************************************/
|
|
/* We expect more data. */
|
|
/******************************************************/
|
|
/****************/
|
|
/* Read ENQ. */
|
|
/****************/
|
|
if ((result = gp_port_read (device, &c, 1)) < 1) return (result);
|
|
switch (c) {
|
|
case ENQ:
|
|
/**********************************************/
|
|
/* ENQ received. We can proceed. */
|
|
/**********************************************/
|
|
break;
|
|
default:
|
|
/**********************************************/
|
|
/* Should not happen. */
|
|
/**********************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
/****************/
|
|
/* Write ACK. */
|
|
/****************/
|
|
if ((result = gp_port_write (device, "\6", 1)) != GP_OK) return (result);
|
|
break;
|
|
default:
|
|
/******************************************************/
|
|
/* Should not happen. */
|
|
/******************************************************/
|
|
return (GP_ERROR_CORRUPTED_DATA);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
gint
|
|
l_send_receive (
|
|
gp_port* device,
|
|
guchar* send_buffer,
|
|
guint send_buffer_size,
|
|
guchar** receive_buffer,
|
|
guint* receive_buffer_size,
|
|
guint timeout,
|
|
guchar** image_buffer,
|
|
guint* image_buffer_size)
|
|
{
|
|
gint result;
|
|
|
|
if (timeout == 0) timeout = DEFAULT_TIMEOUT;
|
|
|
|
/* Send data. */
|
|
result = l_send (device, send_buffer, send_buffer_size);
|
|
if (result != GP_OK) return (result);
|
|
|
|
/* Receive data. */
|
|
result = l_receive (device, receive_buffer, receive_buffer_size, timeout);
|
|
if (result != GP_OK) return (result);
|
|
|
|
/* Check if we've received the control data. */
|
|
if (*receive_buffer_size > 1) {
|
|
if (((*receive_buffer)[0] == send_buffer[0]) && ((*receive_buffer)[1] == send_buffer[1])) return (GP_OK);
|
|
}
|
|
|
|
/* We didn't receive control data yet. */
|
|
*image_buffer = *receive_buffer;
|
|
*image_buffer_size = *receive_buffer_size;
|
|
*receive_buffer = NULL;
|
|
|
|
/* Receive control data. */
|
|
result = l_receive (device, receive_buffer, receive_buffer_size, DEFAULT_TIMEOUT);
|
|
if (result != GP_OK) return (result);
|
|
|
|
/* Sanity check: Did we receive the right control data? */
|
|
g_return_val_if_fail (((*receive_buffer)[0] == send_buffer[0]) && ((*receive_buffer)[1] == send_buffer[1]), GP_ERROR_CORRUPTED_DATA);
|
|
|
|
return (GP_OK);
|
|
}
|