/* ricoh.c * * Copyright 2002 Lutz Mueller * * 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 "ricoh.h" #include #include #include #include "libgphoto2/i18n.h" #include "crctab.h" #define GP_MODULE "ricoh" #define STX 0x02 /* start of text */ #define ETX 0x03 /* end of text */ #define ACK 0x06 /* acknowledge */ #define NAK 0x15 /* negative acknowledge */ #define ETB 0x17 /* end of transmission block */ #define DLE 0x10 /* datalink escape */ #define CR(result) {int r_mac=(result); if (r_mac<0) return r_mac;} #define CRF(result,data) {int r_mac=(result); \ if (r_mac<0) {free (data); return r_mac;}} #define C_CMD(context,cmd,target) \ { \ if (cmd != target) { \ gp_context_error (context, _("Expected %i, got %i. Please "\ "report this error to %s."),\ cmd, target, MAIL_GPHOTO_DEVEL); \ return (GP_ERROR_CORRUPTED_DATA); \ } \ } #define C_LEN(context,len,target) \ { \ if (len != target) { \ gp_context_error (context, _("Expected "\ "%i bytes, got %i. " \ "Please report this error to " \ "%s."), \ target, len, MAIL_GPHOTO_DEVEL); \ return (GP_ERROR_CORRUPTED_DATA); \ } \ } #ifndef HAVE_TM_GMTOFF /* required for time conversions in canon_int_set_time() */ extern long int timezone; #endif static int ricoh_send (Camera *camera, GPContext *context, unsigned char cmd, unsigned char number, const unsigned char *data, unsigned char len) { unsigned char buf[6]; unsigned int i, w, crc = 0; int timeout; /* First, make sure there is no data coming from the camera. */ CR (gp_port_get_timeout (camera->port, &timeout)); CR (gp_port_set_timeout (camera->port, 20)); while (gp_port_read (camera->port, (char *)buf, 1) >= 0) { /* do nothing */ } CR (gp_port_set_timeout (camera->port, timeout)); /* Write header */ buf[0] = DLE; buf[1] = STX; buf[2] = cmd; buf[3] = len; CR (gp_port_write (camera->port, (char *)buf, 4)); crc = updcrc (cmd, crc); crc = updcrc (len, crc); /* * Write data (escape DLE). * * w ... bytes written */ w = 0; while (w < len) { for (i = w; i < len; i++) { crc = updcrc (data[i], crc); if (data[i] == 0x10) { i++; break; } } CR (gp_port_write (camera->port, (char *)data + w, i - w)); if (data[i - 1] == 0x10) CR (gp_port_write (camera->port, "\x10", 1)); w = i; } /* Write footer */ buf[0] = DLE; buf[1] = ETX; buf[2] = crc >> 0; buf[3] = crc >> 8; buf[4] = len + 2; buf[5] = number; CR (gp_port_write (camera->port, (char *)buf, 6)); return (GP_OK); } static int ricoh_send_ack (Camera *camera, GPContext *context) { CR (gp_port_write (camera->port, "\x10\x06", 2)); return (GP_OK); } static int ricoh_send_nack (Camera *camera, GPContext *context) { CR (gp_port_write (camera->port, "\x10\x15", 2)); return (GP_OK); } static int ricoh_recv (Camera *camera, GPContext *context, unsigned char *cmd, unsigned char *number, unsigned char *data, unsigned char *len) { unsigned char buf[6]; unsigned char r, i, ii, last_dle; unsigned int crc = 0; for (ii = 0; ; ii++) { crc = 0; /* * Get header (DLE,STX). If we receive (DLE,ACK), just * drop that and read on. */ for (i = 0, buf[1] = ACK; i < 4; i++) { CR (gp_port_read (camera->port, (char *)buf, 2)); if (buf[0] != DLE) { gp_context_error (context, _("We expected " "0x%x but received 0x%x. Please " "contact %s."), DLE, buf[0], MAIL_GPHOTO_DEVEL); return (GP_ERROR_CORRUPTED_DATA); } if (buf[1] != ACK) break; } switch (buf[1]) { case STX: break; case NAK: default: gp_context_error (context, _("We expected " "0x%x but received 0x%x. Please " "contact %s."), STX, buf[1], MAIL_GPHOTO_DEVEL); return GP_ERROR_CORRUPTED_DATA; } CR (gp_port_read (camera->port, (char *)cmd, 1)); CR (gp_port_read (camera->port, (char *)len, 1)); crc = updcrc (*cmd, crc); crc = updcrc (*len, crc); /* * Get data (check for DLEs). * r ... number of bytes received */ r = 0; last_dle = 0; while (r < *len) { CR (gp_port_read (camera->port, (char *)data + r, *len - r)); if (last_dle) { r++; last_dle = 0; } for (i = r; i < *len; i++) { if (data[r] == DLE) { if (i + 1 != *len && data[r + 1] != DLE) { gp_context_error (context, _("Bad characters " "(0x%x, 0x%x). Please " "contact %s."), data[r], data[r + 1], MAIL_GPHOTO_DEVEL); return (GP_ERROR_CORRUPTED_DATA); } memmove (&data[r], &data[r +1], *len - i - 1); i++; } crc = updcrc (data[r], crc); if (i != *len) r++; else last_dle = 1; } } /* Get footer */ CR (gp_port_read (camera->port, (char *)buf, 6)); if ((buf[0] != DLE) || (buf[1] != ETX && buf[1] != ETB)) return (GP_ERROR_CORRUPTED_DATA); /* CRC correct? If not, retry. */ if ((buf[2] != (crc & 0xff)) || (buf[3] != (crc >> 8 & 0xff)) || (buf[4] != *len + 2)) { GP_DEBUG ("CRC error. Retrying..."); CR (ricoh_send_nack (camera, context)); continue; } /* Acknowledge the packet. */ CR (ricoh_send_ack (camera, context)); /* If camera is busy, try again (but at most 4 times). */ if ((*len == 3) && (data[0] == 0x00) && (data[1] == 0x04) && (data[2] == 0xff)) { if (ii >= 4) { gp_context_error (context, _("Camera busy. " "If the problem persists, please " "contact %s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } continue; } /* Everything is ok. Break out of loop. */ break; } /* Sequence number */ if (number) *number = buf[5]; return (GP_OK); } static int ricoh_transmit (Camera *camera, GPContext *context, unsigned char cmd, const unsigned char *data, unsigned char len, unsigned char *ret_data, unsigned char *ret_len) { unsigned char ret_cmd; unsigned int r = 0; int result; while (1) { CR (ricoh_send (camera, context, cmd, 0, data, len)); result = ricoh_recv (camera, context, &ret_cmd, NULL, ret_data, ret_len); switch (result) { case GP_ERROR_TIMEOUT: if (++r > 2) { gp_context_error (context, _("Timeout " "even after 2 retries. Please " "contact %s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR_TIMEOUT); } GP_DEBUG ("Timeout! Retrying..."); continue; default: CR (result); } /* Check if the answer is for our command. */ if (cmd != ret_cmd) { GP_DEBUG ("Commands differ (expected 0x%02x, " "got 0x%02x)!", cmd, ret_cmd); if (++r > 2) { gp_context_error (context, _("Communication " "error even after 2 retries. Please " "contact %s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } continue; } /* Check if the camera reported success. */ if ((*ret_len >= 2) && (ret_data[0] == 0x00) && (ret_data[1] == 0x00)) break; /* Check if the camera reported success, 2nd version. */ if ((*ret_len == 3) && (ret_data[0] == 0x00) && (ret_data[1] == 0x06) && (ret_data[2] == 0xff)) break; /* If camera is busy, try again (but at most 4 times). */ if ((*ret_len == 3) && (ret_data[0] == 0x00) && (ret_data[1] == 0x04) && (ret_data[2] == 0xff)) { if (++r >= 4) { gp_context_error (context, _("Camera busy. " "If the problem persists, please " "contact %s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } continue; } /* * It could be that the camera is in the wrong mode to * execute this command. */ if ((*ret_len == 2) && (ret_data[0] == 0x06) && (ret_data[1] == 0x00)) { gp_context_error (context, _("Camera is in wrong " "mode. Please contact " "%s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } /* Invalid parameters? */ if ((*ret_len == 2) && (ret_data[0] == 0x04) && (ret_data[1] == 0x00)) { gp_context_error (context, _("Camera did not " "accept the parameters. Please contact " "%s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } gp_context_error (context, _("An unknown error occurred. " "Please contact %s."), MAIL_GPHOTO_DEVEL); return (GP_ERROR); } /* Success! We don't need the first two bytes any more. */ *ret_len -= 2; if (*ret_len > 0) memmove (ret_data, ret_data + 2, *ret_len); return (GP_OK); } int ricoh_get_pic_size (Camera *camera, GPContext *context, unsigned int n, uint64_t *size) { unsigned char p[3], buf[0xff], len; GP_DEBUG ("Getting size of picture %i...", n); p[0] = 0x04; p[1] = n >> 0; p[2] = n >> 8; CR (ricoh_transmit (camera, context, 0x95, p, 3, buf, &len)); C_LEN (context, len, 4); if (size) *size = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0] << 0; return (GP_OK); } #define B2H( bcd ) ((bcd>>4)*10+(bcd&0xF)) int ricoh_get_pic_date (Camera *camera, GPContext *context, unsigned int n, time_t *date) { unsigned char p[3], buf[0xff], len; struct tm time; GP_DEBUG ("Getting date of picture %i...", n); p[0] = 0x03; p[1] = n >> 0; p[2] = n >> 8; CR (ricoh_transmit (camera, context, 0x95, p, 3, buf, &len)); C_LEN (context, len, 7); if (date) { time.tm_year = B2H (buf[1]); /* correct for Y2K in case older images are read */ if (time.tm_year < 90) time.tm_year += 100; time.tm_mon = B2H (buf[2]) - 1; time.tm_mday = B2H (buf[3]); time.tm_hour = B2H (buf[4]); time.tm_min = B2H (buf[5]); time.tm_sec = B2H (buf[6]); time.tm_isdst = -1; *date = mktime (&time); } return (GP_OK); } int ricoh_get_pic_name (Camera *camera, GPContext *context, unsigned int n, const char **name) { unsigned char p[3], len; static unsigned char buf[0xff]; GP_DEBUG ("Getting name of picture %i...", n); p[0] = 0x00; p[1] = n >> 0; p[2] = n >> 8; CR (ricoh_transmit (camera, context, 0x95, p, 3, buf, &len)); if (name && *name) { *name = (char *)buf; buf[len] = '\0'; } return (GP_OK); } int ricoh_get_pic_memo (Camera *camera, GPContext *context, unsigned int n, const char **memo) { unsigned char p[3], len; static unsigned char buf[0xff]; GP_DEBUG ("Getting memo of picture %i...", n); p[0] = 0x02; p[1] = n >> 0; p[2] = n >> 8; CR (ricoh_transmit (camera, context, 0x95, p, 3, buf, &len)); if (memo && *memo) { *memo = (char *)buf; buf[len] = '\0'; } return (GP_OK); } int ricoh_del_pic (Camera *camera, GPContext *context, unsigned int n) { unsigned char p[2], buf[0xff], len; GP_DEBUG ("Deleting picture %i...", n); /* Put camera in delete mode */ CR (ricoh_transmit (camera, context, 0x97, NULL, 0, buf, &len)); C_LEN (context, len, 0); /* Find and send picture to delete */ p[0] = n >> 0; p[1] = n >> 8; CR (ricoh_transmit (camera, context, 0x93, p, 2, buf, &len)); C_LEN (context, len, 0); CR (ricoh_transmit (camera, context, 0x92, p, 2, buf, &len)); C_LEN (context, len, 0); return (GP_OK); } int ricoh_get_num (Camera *camera, GPContext *context, unsigned int *n) { unsigned char p[2], buf[0xff], len; GP_DEBUG ("Getting number of pictures..."); p[0] = 0x00; p[1] = 0x01; CR (ricoh_transmit (camera, context, 0x51, p, 2, buf, &len)); C_LEN (context, len, 2); if (n) *n = (buf[1] << 8) | buf[0]; return (GP_OK); } int ricoh_set_speed (Camera *camera, GPContext *context, RicohSpeed speed) { unsigned char p[1], buf[0xff], len; p[0] = speed; CR (ricoh_transmit (camera, context, 0x32, p, 1, buf, &len)); C_LEN (context, len, 0); /* Wait for camera to switch speed. */ sleep (1); return (GP_OK); } int ricoh_connect (Camera *camera, GPContext *context, RicohModel *model) { unsigned char p[3], buf[0xff], len; p[0] = 0x00; p[1] = 0x00; p[2] = 0x00; CR (ricoh_transmit (camera, context, 0x31, p, 3, buf, &len)); C_LEN (context, len, 4); /* Model */ if (model) *model = (buf[0] << 8) | buf[1]; /* No idea what buf[2] and buf[3] contain. */ return (GP_OK); } int ricoh_disconnect (Camera *camera, GPContext *context) { unsigned char buf[0xff], len; CR (ricoh_transmit (camera, context, 0x37, NULL, 0, buf, &len)); C_LEN (context, len, 2); return (GP_OK); } static unsigned char header[236] = { 0x49,0x49,0x2a,0x00,0x08,0x00,0x00,0x00,0x0c,0x00,0x00,0x01,0x03,0x00, 0x01,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x01,0x03,0x00,0x01,0x00, 0x00,0x00,0x3c,0x00,0x00,0x00,0x02,0x01,0x03,0x00,0x03,0x00,0x00,0x00, 0x9e,0x00,0x00,0x00,0x03,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00, 0x00,0x00,0x06,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00, 0x11,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0xec,0x00,0x00,0x00,0x15,0x01, 0x03,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x17,0x01,0x04,0x00, 0x01,0x00,0x00,0x00,0x80,0x25,0x00,0x00,0x1c,0x01,0x03,0x00,0x01,0x00, 0x00,0x00,0x01,0x00,0x00,0x00,0x11,0x02,0x05,0x00,0x03,0x00,0x00,0x00, 0xa4,0x00,0x00,0x00,0x12,0x02,0x03,0x00,0x02,0x00,0x00,0x00,0x02,0x00, 0x01,0x00,0x14,0x02,0x05,0x00,0x06,0x00,0x00,0x00,0xbc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0xe0,0xd0,0x22,0x13, 0x00,0x00,0x00,0x40,0x80,0x68,0x91,0x25,0x00,0x00,0x00,0x40,0xa8,0xc6, 0x4b,0x07,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0xe0,0x1f,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x10,0x00,0x00, 0x20,0x00,0x00,0x00,0xe0,0x1f,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x10, 0x00,0x00,0x20,0x00,0x00,0x00,0xe0,0x1f,0x00,0x00,0x20,0x00 }; int ricoh_get_pic (Camera *camera, GPContext *context, unsigned int n, RicohFileType type, unsigned char **data, unsigned int *size) { unsigned char p[2], cmd, buf[0xff], len; unsigned int r, header_len; RicohMode mode; GP_DEBUG ("Getting image %i as %s...", n, (type==RICOH_FILE_TYPE_PREVIEW ? "thumbnail":"image")); /* Put camera into play mode, if not already */ CR (ricoh_get_mode (camera, context, &mode)); if (mode != RICOH_MODE_PLAY) CR (ricoh_set_mode (camera, context, RICOH_MODE_PLAY)); /* Send picture number */ p[0] = n >> 0; p[1] = n >> 8; CR (ricoh_transmit (camera, context, (unsigned char) type, p, 2, buf, &len)); C_LEN (context, len, 16); /* * Allocate the necessary memory. Note that previews are 80x60 pixels * raw TIFF data, we therefore need to allocate some extra memory * for the TIFF header. */ header_len = (type == RICOH_FILE_TYPE_PREVIEW) ? sizeof (header) : 0; *size = buf[15] << 24 | buf[14] << 16 | buf[13] << 8 | buf[12]; *size += header_len; *data = malloc (*size); if (!*data) return (GP_ERROR_NO_MEMORY); /* * Receive data. * r ... number of bytes received */ for (r = 0; r < (*size) - header_len; r += len) { CRF (ricoh_recv (camera, context, &cmd, NULL, *data + header_len + r, &len), *data); C_CMD (context, cmd, 0xa2); } /* In case of previews, copy over the TIFF header. */ if (type == RICOH_FILE_TYPE_PREVIEW) memcpy (*data, header, header_len); return (GP_OK); } int ricoh_get_date (Camera *camera, GPContext *context, time_t *date) { unsigned char p[1], buf[0xff], len; struct tm time; p[0] = 0x0a; CR (ricoh_transmit (camera, context, 0x51, p, 1, buf, &len)); /* the camera only supplies 2 digits for year, so I will * make the assumption that if less than 90, then it is * year 2000 or greater */ time.tm_year = ((buf[1] & 0xf0) >> 4) * 10 + (buf[1] & 0xf); if(time.tm_year < 90) time.tm_year += 100; time.tm_mon = ((buf[2] & 0xf0) >> 4) * 10 + (buf[2] & 0xf) - 1; time.tm_mday = ((buf[3] & 0xf0) >> 4) * 10 + (buf[3] & 0xf); time.tm_hour = ((buf[4] & 0xf0) >> 4) * 10 + (buf[4] & 0xf); time.tm_min = ((buf[5] & 0xf0) >> 4) * 10 + (buf[5] & 0xf); time.tm_sec = ((buf[6] & 0xf0) >> 4) * 10 + (buf[6] & 0xf); time.tm_isdst = -1; *date = mktime (&time); return (GP_OK); } #ifdef HEX # undef HEX #endif #define HEX(x) (((x)/10)<<4)+((x)%10) int ricoh_set_date (Camera *camera, GPContext *context, time_t time) { unsigned char p[8], buf[0xff], len; struct tm *t; p[0] = 0x0a; /* Call localtime() to get 'extern long timezone' */ t = localtime (&time); #ifdef HAVE_TM_GMTOFF time += t->tm_gmtoff; #else time += timezone; #endif t = localtime (&time); GP_DEBUG ("ricoh_set_date: converted time to localtime %s " "(timezone is %ld)", asctime (t), timezone); p[1] = HEX (t->tm_year / 100 + 19); p[2] = HEX (t->tm_year % 100); p[3] = HEX (t->tm_mon + 1); p[4] = HEX (t->tm_mday); p[5] = HEX (t->tm_hour); p[6] = HEX (t->tm_min); p[7] = HEX (t->tm_sec); CR (ricoh_transmit (camera, context, 0x50, p, 8, buf, &len)); return (GP_OK); } /* get the cameras memory size */ int ricoh_get_cam_mem (Camera *camera, GPContext *context, int *size) { unsigned char p[2], buf[0xff], len; p[0] = 0x00; p[1] = 0x05; CR (ricoh_transmit (camera, context, 0x51, p, 2, buf, &len)); C_LEN (context, len, 4); if (size) *size = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]; return (GP_OK); } /* get the cameras available memory size */ int ricoh_get_cam_amem (Camera *camera, GPContext *context, int *size) { unsigned char p[2], buf[0xff], len; p[0] = 0x00; p[1] = 0x06; CR (ricoh_transmit (camera, context, 0x51, p, 2, buf, &len)); C_LEN (context, len, 4); if (size) *size = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]; return (GP_OK); } #define RICOH_GET_SET_VALUE(name,type,code) \ int \ ricoh_get_##name (Camera *camera, GPContext *context, \ type *value) \ { \ unsigned char p[1], buf[0xff], len; \ \ p[0] = (code); \ CR (ricoh_transmit (camera, context, 0x51, p, 1, buf, &len)); \ C_LEN (context, len, 1); \ if (value) \ *value = buf[0]; \ return (GP_OK); \ } \ \ int \ ricoh_set_##name (Camera *camera, GPContext *context, \ type value) \ { \ unsigned char p[2], buf[0xff], len; \ \ p[0] = (code); \ p[1] = (unsigned char) value; \ CR (ricoh_transmit (camera, context, 0x50, p, 2, buf, &len)); \ C_LEN (context, len, 0); \ \ return (GP_OK); \ } RICOH_GET_SET_VALUE(exposure, RicohExposure, 0x03) RICOH_GET_SET_VALUE(white_level,RicohWhiteLevel, 0x04) RICOH_GET_SET_VALUE(zoom, RicohZoom, 0x05) RICOH_GET_SET_VALUE(flash, RicohFlash, 0x06) RICOH_GET_SET_VALUE(rec_mode, RicohRecMode, 0x07) RICOH_GET_SET_VALUE(compression,RicohCompression,0x08) RICOH_GET_SET_VALUE(resolution, RicohResolution, 0x09) RICOH_GET_SET_VALUE(mode, RicohMode, 0x12) RICOH_GET_SET_VALUE(macro, RicohMacro, 0x16) int ricoh_get_copyright (Camera *camera, GPContext *context, const char **copyright) { unsigned char p[1], len; static char buf[1024]; p[0] = 0x0f; CR (ricoh_transmit (camera, context, 0x51, p, 1, (unsigned char *)buf, &len)); if (copyright && *copyright) { *copyright = (char *)buf; buf[len] = '\0'; } return (GP_OK); } int ricoh_set_copyright (Camera *camera, GPContext *context, const char *copyright) { unsigned char p[21], len, buf[0xff]; p[0] = 0x0f; strncpy ((char *)p + 1, copyright, 20); CR (ricoh_transmit (camera, context, 0x50, p, 21, buf, &len)); return (GP_OK); } int ricoh_take_pic (Camera *camera, GPContext *context) { unsigned char p[1]; RicohMode mode; /* Put camera into record mode, if not already */ CR (ricoh_get_mode (camera, context, &mode)); if (mode != RICOH_MODE_RECORD) CR (ricoh_set_mode (camera, context, RICOH_MODE_RECORD)); p[0] = 0x01; CR (ricoh_send (camera, context, 0x60, 0x00, p, 1)); return (GP_OK); } #undef MIN #define MIN(x,y) (((x) < (y)) ? (x) : (y)) int ricoh_put_file (Camera *camera, GPContext *context, const char *name, const unsigned char *data, unsigned int size) { RicohMode mode; unsigned char p[16], len, buf[0xff], block[0xff]; unsigned int i, pr; CR (ricoh_get_mode (camera, context, &mode)); if (mode != RICOH_MODE_PLAY) CR (ricoh_set_mode (camera, context, RICOH_MODE_PLAY)); /* Filename ok? */ if (strlen (name) > 12) { gp_context_error (context, _("The filename's length must not " "exceed 12 characters ('%s' has %i characters)."), name, (int)strlen (name)); return (GP_ERROR); } strncpy ((char *)p, name, 12); p[12] = size << 24; p[13] = size << 16; p[14] = size << 8; p[15] = size; CR (ricoh_transmit (camera, context, 0xa1, p, 16, buf, &len)); C_LEN (context, len, 2); /* * We just received the picture number of the new file. We don't * need it. */ /* Now send the data */ pr = gp_context_progress_start (context, size, _("Uploading...")); for (i = 0; i < size; i += 128) { memset (block, 0, sizeof (buf)); memcpy (block, data + i, MIN (128, size - i)); CR (ricoh_transmit (camera, context, 0xa2, block, 128, buf, &len)); C_LEN (context, len, 0); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) return (GP_ERROR_CANCEL); gp_context_progress_update (context, pr, MIN (i + 128, size)); } gp_context_progress_stop (context, pr); /* Finish upload */ p[0] = 0x12; p[1] = 0x00; CR (ricoh_transmit (camera, context, 0x50, p, 2, buf, &len)); C_LEN (context, len, 0); return (GP_OK); }