Files
libgphoto2/camlibs/konica/lowlevel.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

641 lines
15 KiB
C

/* lowlevel.c
*
* Copyright 2001 Lutz Mueller <lutz@users.sourceforge.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
*/
#include "config.h"
#include "lowlevel.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gphoto2/gphoto2-result.h>
#include <gphoto2/gphoto2-port-log.h>
#include "libgphoto2/i18n.h"
#include "konica.h"
#define GP_MODULE "konica"
#define DEFAULT_TIMEOUT 1000
#define LESSER_ESCAPES
/* ESC quotes */
#define STX 0x02
#define ETX 0x03
#define ENQ 0x05
#define ACK 0x06
#define XOFF 0x11
#define XON 0x13
#define NACK 0x15
#define ETB 0x17
#define ESC 0x1b
/* Not an ESC quote */
#define EOT 0x04
#define CHECK(r) {int ret = (r); if (ret < 0) return (ret);}
#define CHECK_NULL(r) {if (!(r)) return (GP_ERROR_BAD_PARAMETERS);}
#define CHECK_FREE(r,f) {int ret = (r); if (ret < 0) {free (f); return (ret);}}
static int
l_ping_rec (GPPort *p, unsigned int level)
{
unsigned char c;
/* Write ENQ and read the response. */
c = ENQ;
CHECK (gp_port_write (p, (char *)&c, 1));
CHECK (gp_port_read (p, (char *)&c, 1));
switch (c) {
case ACK:
return (GP_OK);
case NACK:
/*
* Uh, lets try again a couple of times, but
* make sure we don't recurse forever.
*/
if (level < 30)
return (l_ping_rec (p, level + 1));
else
return (GP_ERROR_CORRUPTED_DATA);
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;
CHECK (gp_port_write (p, (char *)&c, 1));
for (;;) {
CHECK (gp_port_read (p, (char *)&c, 1));
switch (c) {
case ENQ:
/* The camera has not yet given up. */
continue;
case ACK:
/* ACK received. We can proceed. */
return (GP_OK);
default:
/* This should not happen. */
return (GP_ERROR_CORRUPTED_DATA);
}
break;
}
break;
default:
/*
* The camera seems to send us data. We'll
* simply ignore it and try again (but make
* sure that we don't loop forever).
*/
CHECK (gp_port_flush (p, 0));
CHECK (gp_port_flush (p, 1));
if (level > 50)
return (GP_ERROR_CORRUPTED_DATA);
else
return (l_ping_rec (p, level + 1));
}
return (GP_OK);
}
int
l_ping (GPPort *p, GPContext *c)
{
return (l_ping_rec (p, 0));
}
int
l_init (GPPort *p, GPContext *c)
{
unsigned int i;
int result = GP_OK;
CHECK_NULL (p);
CHECK (gp_port_set_timeout (p, DEFAULT_TIMEOUT));
for (i = 0; i < 3; i++) {
result = l_ping (p, c);
if (result != GP_ERROR_TIMEOUT)
break;
}
return (result);
}
static int
l_esc_read (GPPort *p, unsigned char *c)
{
CHECK_NULL (p && c);
CHECK (gp_port_read (p, (char *)c, 1));
/*
* 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.
*/
/* The HP PhotoSmart does not escape every special code, only
* some and it gets confused if we do this checks. By relaxing
* these, it now downloads images etc.
*/
#ifndef LESSER_ESCAPES
if ((*c == STX ) || (*c == ETX) || (*c == ENQ ) || (*c == ACK) ||
(*c == XOFF) || (*c == XON) || (*c == NACK) || (*c == ETB)) {
#else /* LESSER_ESCAPES */
if ((*c == STX ) || (*c == XOFF) || (*c == XON)) {
#endif /* LESSER_ESCAPES */
GP_DEBUG ("Wrong ESC masking!");
if ((*c == ETX) || (*c == ETB))
return (GP_ERROR_CORRUPTED_DATA);
} else if (*c == ESC) {
CHECK (gp_port_read (p, (char *)c, 1));
*c = (~*c & 0xff);
if ((*c != STX ) && (*c != ETX ) && (*c != ENQ) &&
(*c != ACK ) && (*c != XOFF) && (*c != XON) &&
(*c != NACK) && (*c != ETB ) && (*c != ESC))
GP_DEBUG ("Wrong ESC masking!");
}
return (GP_OK);
}
static int
l_send (GPPort *p, GPContext *context, unsigned char *send_buffer,
unsigned int send_buffer_size)
{
unsigned char c;
unsigned char checksum;
/**********************************************************************/
/* sb: A pointer to the buffer that we will send. */
/* sbs: Its size. */
/**********************************************************************/
unsigned char *sb;
unsigned int sbs;
unsigned int i = 0;
CHECK_NULL (p && send_buffer);
/* We need to ping the camera first */
CHECK (l_ping (p, context));
/********************************************************/
/* 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 = malloc (sizeof (char) * 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 = realloc (sb, ++sbs * sizeof (char));
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 = realloc (sb, ++sbs * sizeof (char));
sb[sbs - 2] = ESC;
sb[sbs - 1] = ~checksum;
} else sb[sbs - 1] = checksum;
for (i = 0; ; i++) {
/* Write data as above. */
CHECK_FREE (gp_port_write (p, (char *)sb, sbs), sb);
CHECK_FREE (gp_port_read (p, (char *)&c, 1), sb);
switch (c) {
case ACK:
/* ACK received. We can proceed. */
free (sb);
/* Write EOT. */
c = EOT;
CHECK (gp_port_write (p, (char *)&c, 1));
return (GP_OK);
case NACK:
/* NACK received. We'll try up to three times. */
if (i == 2) {
free (sb);
return (GP_ERROR_CORRUPTED_DATA);
} else break;
default:
/* Should not happen. */
return (GP_ERROR_CORRUPTED_DATA);
}
}
}
static int
l_receive (GPPort *p, GPContext *context,
unsigned char **rb, unsigned int *rbs,
unsigned int timeout)
{
unsigned char c, d, progress = 0;
int error_flag;
unsigned int i, j, rbs_internal, id = 0;
unsigned char checksum;
int result;
KCommand command;
CHECK_NULL (p && rb && rbs);
for (i = 0; ; ) {
CHECK (gp_port_set_timeout (p, timeout));
CHECK (gp_port_read (p, (char *)&c, 1));
CHECK (gp_port_set_timeout (p, 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 (;;) {
CHECK (gp_port_read (p, (char *)&c, 1));
if (c == ENQ)
break;
}
break;
}
if (c == ENQ)
break;
}
/* Start progress */
if (*rbs > 1000) {
id = gp_context_progress_start (context, *rbs,
_("Downloading..."));
progress = 1;
}
/* Write ACK. */
CHECK (gp_port_write (p, "\6", 1));
for (*rbs = 0; ; ) {
for (j = 0; ; j++) {
CHECK (gp_port_read (p, (char *)&c, 1));
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.
*/
CHECK (l_esc_read (p, &c));
checksum = c;
CHECK (l_esc_read (p, &d));
checksum += d;
rbs_internal = (d << 8) | c;
if (*rbs == 0)
*rb = malloc (rbs_internal * sizeof (char));
else
*rb = realloc (*rb,
sizeof (char) * (*rbs + rbs_internal));
/* Read 'rbs_internal' bytes data plus ESC quotes. */
error_flag = 0;
{
unsigned int read = 0, r = 0;
while (read < rbs_internal) {
/*
* Read the specified amount of bytes. We will probably read more
* because some bytes will be quoted.
*/
GP_DEBUG ("Reading %i bytes (%i of %i already read)...",
rbs_internal - read, read, rbs_internal);
result = gp_port_read (p, (char *)&((*rb)[*rbs + read]),
rbs_internal - read);
if (result < 0) {
error_flag = 1;
break;
}
r = rbs_internal - read;
/* Unescape the data we just read */
for (i = read; i < read + r; i++) {
unsigned char *buf = &(*rb)[*rbs + i];
/* The HP PhotoSmart does not escape every special code, only
* some and it gets confused if we do this checks. By relaxing
* these, it now downloads images etc.
*/
#ifndef LESSER_ESCAPES
if ((*buf == STX) || (*buf == ETX) || (*buf == ENQ) ||
(*buf == ACK) || (*buf == XOFF) || (*buf == XON) ||
(*buf == NACK) || (*buf == ETB)) {
#else /* LESSER_ESCAPES */
if ((*buf == STX) || (*buf == XOFF) || (*buf == XON)) {
#endif /* LESSER_ESCAPES */
GP_DEBUG ("Wrong ESC masking!");
error_flag = 1;
break;
} else if (*buf == ESC) {
if (i == read + r - 1) {
/* ESC is last char of packet */
CHECK (gp_port_read (p, (char *)buf, 1));
} else {
memmove (buf, buf + 1, read + r - i - 1);
r--;
}
*buf = ~*buf & 0xff;
if ((*buf != STX ) && (*buf != ETX ) && (*buf != ENQ) &&
(*buf != ACK ) && (*buf != XOFF) && (*buf != XON) &&
(*buf != NACK) && (*buf != ETB ) && (*buf != ESC)) {
GP_DEBUG ("Wrong ESC masking!");
error_flag = 1;
break;
}
}
checksum += (*rb)[*rbs + i];
}
if (error_flag)
break;
read += r;
}}
if (!error_flag) {
CHECK (gp_port_read (p, (char *)&d, 1));
switch (d) {
case ETX:
/*
* ETX received. This is the last
* packet.
*/
GP_DEBUG ("Last packet.");
break;
case ETB:
/*
* ETB received. There are more
* packets to come.
*/
GP_DEBUG ("More packets coming.");
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)) {
CHECK (gp_port_read (p,
(char *)&d, 1));
}
error_flag = 1;
break;
}
}
checksum += d;
/* Read 1 byte for checksum plus ESC quotes. */
CHECK (l_esc_read (p, &c));
if ((c == checksum) && (!error_flag)) {
*rbs += rbs_internal;
/* Write ACK. */
CHECK (gp_port_write (p, "\6", 1));
break;
} else {
/*
* Checksum wrong or transmission error. The
* camera will send us the data at the most
* three times.
*/
GP_DEBUG ("Checksum wrong: expected %i, "
"got %i.", c, checksum);
if (j == 2)
return (GP_ERROR_CORRUPTED_DATA);
/* Write NACK. */
c = NACK;
CHECK (gp_port_write (p, (char *)&c, 1));
continue;
}
}
CHECK (gp_port_read (p, (char *)&c, 1));
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. */
if (progress)
gp_context_progress_stop (context, id);
return (GP_OK);
case ETB:
/* We expect more data. Read ENQ. */
CHECK (gp_port_read (p, (char *)&c, 1));
switch (c) {
case ENQ:
/* ENQ received. We can proceed. */
break;
default:
/* Should not happen. */
return (GP_ERROR_CORRUPTED_DATA);
}
if (gp_context_cancel (context) ==
GP_CONTEXT_FEEDBACK_CANCEL) {
GP_DEBUG ("Trying to cancel operation...");
CHECK (k_cancel (p, context, &command));
GP_DEBUG ("Operation 0x%x cancelled.",
command);
return (GP_ERROR_CANCEL);
}
/* Write ACK. */
CHECK (gp_port_write (p, "\6", 1));
break;
default:
/* Should not happen. */
return (GP_ERROR_CORRUPTED_DATA);
}
if (progress)
gp_context_progress_update (context, id, *rbs);
}
}
int
l_send_receive (
GPPort *p, GPContext *c,
unsigned char *send_buffer, unsigned int send_buffer_size,
unsigned char **receive_buffer, unsigned int *receive_buffer_size,
unsigned int timeout,
unsigned char **image_buffer, unsigned int *image_buffer_size)
{
if (!timeout)
timeout = DEFAULT_TIMEOUT;
/* Send data. */
CHECK (l_send (p, c, send_buffer, send_buffer_size));
/* Receive data. */
if (image_buffer_size)
*receive_buffer_size = *image_buffer_size;
CHECK (l_receive (p, c, receive_buffer, receive_buffer_size,
timeout));
/* Check if we've received the control data. */
if ((*receive_buffer_size > 1) &&
(((*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. */
CHECK (l_receive (p, c, receive_buffer, receive_buffer_size,
DEFAULT_TIMEOUT));
/* Sanity check: Did we receive the right control data? */
if (((*receive_buffer)[0] != send_buffer[0]) ||
((*receive_buffer)[1] != send_buffer[1]))
return (GP_ERROR_CORRUPTED_DATA);
return (GP_OK);
}