/****************************************************************/ /* library.c - Gphoto2 library for the KBGear JamCam v2 and v3 */ /* */ /* Copyright 2001 Chris Pinkham */ /* */ /* Author: Chris Pinkham */ /* */ /* This library is free software; you can redistribute it */ /* and/or modify it under the terms of the GNU Library 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 Library General Public License for */ /* more details. */ /* */ /* You should have received a copy of the GNU Library 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 #include #include #include #include #include #include "library.h" #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (GETTEXT_PACKAGE, String) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define N_(String) (String) #endif #define GP_MODULE static struct jamcam_file jamcam_files[1024]; static int jamcam_count = 0; static int jamcam_mmc_card_size = 0; static int jamcam_read_packet (Camera *camera, unsigned char *packet, int length); static int jamcam_write_packet (Camera *camera, unsigned char *packet, int length); static int jamcam_fetch_memory( Camera *camera, CameraFile *file, unsigned char *data, int start, int length, GPContext *context); static int jamcam_query_mmc_card (Camera *camera); static int jamcam_set_int_at_pos( unsigned char *buf, int pos, int value ) { buf[pos + 0] = ( value ) & 0xff; buf[pos + 1] = ( value >> 8 ) & 0xff; buf[pos + 2] = ( value >> 16 ) & 0xff; buf[pos + 3] = ( value >> 24 ) & 0xff; return( value ); } static int jamcam_get_int_at_pos( unsigned char *buf, int pos ) { int ret = 0; ret += buf[pos + 0]; ret += buf[pos + 1] * 256; ret += buf[pos + 2] * 256 * 256; ret += buf[pos + 3] * 256 * 256 * 256; return( ret ); } static int jamcam_set_usb_mem_pointer( Camera *camera, int position ) { char reply[8]; GP_DEBUG ("* jamcam_set_usb_mem_pointer"); GP_DEBUG ("*** position: %d (0x%x)", position, position); gp_port_usb_msg_write( camera->port, 0xa1, ( position ) & 0xffff, ( position >> 16 ) & 0xffff, NULL, 0 ); gp_port_usb_msg_read( camera->port, 0xa0, 0, 0, reply, 8 ); return( GP_OK ); } /* get the number of images on the mmc card */ static int jamcam_mmc_card_file_count (Camera *camera) { unsigned char buf[16]; unsigned char reply[512]; unsigned int position = 0x40000000; int data_incr; int width; int height; GP_DEBUG ("* jamcam_mmc_card_file_count"); memset( buf, 0, sizeof( buf )); switch( camera->port->type ) { default: case GP_PORT_SERIAL: memcpy( buf, "KB00", 4 ); jamcam_set_int_at_pos( buf, 4, position ); jamcam_write_packet( camera, buf, 8 ); jamcam_read_packet( camera, reply, 16 ); while( memcmp( reply, "KB", 2 ) == 0 ) { width = (reply[5] * 256) + reply[4]; height = (reply[7] * 256) + reply[6]; data_incr = jamcam_get_int_at_pos( reply, 8 ); jamcam_files[jamcam_count].position = position; jamcam_files[jamcam_count].width = width; jamcam_files[jamcam_count].height = height; jamcam_files[jamcam_count].data_incr = data_incr; jamcam_count++; position += data_incr; jamcam_set_int_at_pos( buf, 4, position ); jamcam_write_packet( camera, buf, 8 ); jamcam_read_packet( camera, reply, 16 ); } break; case GP_PORT_USB: gp_port_usb_msg_write( camera->port, 0xa5, 0x0005, 0x0000, NULL, 0 ); jamcam_set_usb_mem_pointer( camera, position ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); width = (reply[13] * 256) + reply[12]; height = (reply[15] * 256) + reply[14]; jamcam_set_usb_mem_pointer( camera, position + 8 ); CHECK( gp_port_read (camera->port, (char*)reply, 512 )); gp_port_usb_msg_write( camera->port, 0xa5, 0x0006, 0x0000, NULL, 0 ); while((reply[0] != 0xff ) && (reply[0] != 0xaa ) && ((reply[0] != 0x00 ) || (reply[1] != 0x00 ))) { data_incr = jamcam_get_int_at_pos( reply, 0 ); jamcam_files[jamcam_count].position = position; jamcam_files[jamcam_count].width = width; jamcam_files[jamcam_count].height = height; jamcam_files[jamcam_count].data_incr = data_incr; jamcam_count++; position += data_incr; gp_port_usb_msg_write( camera->port, 0xa5, 0x0005, 0x0000, NULL, 0 ); jamcam_set_usb_mem_pointer( camera, position ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); width = (reply[13] * 256) + reply[12]; height = (reply[15] * 256) + reply[14]; jamcam_set_usb_mem_pointer( camera, position + 8 ); CHECK( gp_port_read (camera->port, (char*)reply, 512 )); gp_port_usb_msg_write( camera->port, 0xa5, 0x0006, 0x0000, NULL, 0 ); } break; } GP_DEBUG ( "*** returning with jamcam_count = %d", jamcam_count); return( 0 ); } int jamcam_file_count (Camera *camera) { unsigned char buf[16]; unsigned char reply[16]; int position = 0; int data_incr; int width; int height; int last_offset_size = 0; GP_DEBUG ("* jamcam_file_count"); jamcam_count = 0; memset( buf, 0, sizeof( buf )); switch( camera->port->type ) { default: case GP_PORT_SERIAL: memcpy( buf, "KB00", 4 ); jamcam_set_int_at_pos( buf, 4, position ); jamcam_write_packet( camera, buf, 8 ); jamcam_read_packet( camera, reply, 16 ); while( reply[0] == 'K' ) { width = (reply[5] * 256) + reply[4]; height = (reply[7] * 256) + reply[6]; data_incr = jamcam_get_int_at_pos( reply, 8 ); last_offset_size = data_incr; jamcam_files[jamcam_count].position = position; jamcam_files[jamcam_count].width = width; jamcam_files[jamcam_count].height = height; jamcam_files[jamcam_count].data_incr = data_incr; jamcam_count++; position += data_incr; jamcam_set_int_at_pos( buf, 4, position ); jamcam_write_packet( camera, buf, 8 ); jamcam_read_packet( camera, reply, 16 ); } /* the v3 camera uses 0x3fdf0 data increments so check for MMC */ if ( last_offset_size == 0x03fdf0 ) { jamcam_query_mmc_card( camera ); } break; case GP_PORT_USB: jamcam_set_usb_mem_pointer( camera, position ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); width = (reply[13] * 256) + reply[12]; height = (reply[15] * 256) + reply[14]; jamcam_set_usb_mem_pointer( camera, position + 8 ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); while(reply[0] != 0xff ) { data_incr = jamcam_get_int_at_pos( reply, 0 ); jamcam_files[jamcam_count].position = position; jamcam_files[jamcam_count].width = width; jamcam_files[jamcam_count].height = height; jamcam_files[jamcam_count].data_incr = data_incr; jamcam_count++; position += data_incr; jamcam_set_usb_mem_pointer( camera, position ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); width = (reply[13] * 256) + reply[12]; height = (reply[15] * 256) + reply[14]; jamcam_set_usb_mem_pointer( camera, position + 8 ); CHECK( gp_port_read (camera->port, (char*)reply, 0x10 )); } break; } if ( jamcam_mmc_card_size ) { jamcam_count += jamcam_mmc_card_file_count( camera ); } GP_DEBUG ( "*** returning jamcam_count = %d", jamcam_count); return( jamcam_count ); } static int jamcam_fetch_memory( Camera *camera, CameraFile *file, unsigned char *data, int start, int length, GPContext *context) { unsigned char tmp_buf[16]; unsigned char packet[16]; int new_start; int new_end; int bytes_read = 0; int bytes_to_read; int bytes_left = length; int res = GP_OK; unsigned int id = 0; GP_DEBUG ("* jamcam_fetch_memory"); GP_DEBUG (" * start: %d (0x%x)", start, start); GP_DEBUG (" * length: %d (0x%x)", length, length); if ( length > 1000 ) id = gp_context_progress_start (context, length, _("Downloading data...")); while( bytes_left ) { switch( camera->port->type ) { default: case GP_PORT_SERIAL: bytes_to_read = bytes_left > SER_PKT_SIZE ? SER_PKT_SIZE : bytes_left; memset( packet, 0, sizeof( packet )); memcpy( packet, "KB01", 4 ); new_start = start + bytes_read; new_end = start + bytes_read + bytes_to_read - 1; /* start and end (inclusive) */ jamcam_set_int_at_pos( packet, 4, new_start ); jamcam_set_int_at_pos( packet, 8, new_end ); jamcam_write_packet( camera, packet, 12 ); CHECK (jamcam_read_packet( camera, data + bytes_read, bytes_to_read )); break; case GP_PORT_USB: bytes_to_read = bytes_left > USB_PKT_SIZE ? USB_PKT_SIZE : bytes_left; /* for some reason this priming read fixes an offset problem */ /* in the images, we are only reading the first 16 bytes of */ /* data twice by doing this, so I don't know why it works */ jamcam_set_usb_mem_pointer( camera, start + bytes_read ); CHECK( gp_port_read (camera->port, (char*)tmp_buf, 16 )); jamcam_set_usb_mem_pointer( camera, start + bytes_read ); CHECK( gp_port_read (camera->port, (char*)data + bytes_read, bytes_to_read )); break; } bytes_left -= bytes_to_read; bytes_read += bytes_to_read; /* hate this hardcoded, but don't want to update here */ /* when downloading parts of a thumbnail */ if ( length > 1000 ) { gp_context_progress_update (context, id, bytes_read); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { GP_DEBUG (" * CANCELED"); break; } } } if ( length > 1000 ) gp_context_progress_stop (context, id); if ( res == GP_OK ) { GP_DEBUG (" * returning OK"); } return( res ); } int jamcam_request_image( Camera *camera, CameraFile *file, char *buf, int *len, int number, GPContext *context ) { int position; int result; unsigned char *tmp_buf; GP_DEBUG ("* jamcam_request_image"); tmp_buf = malloc(640*480*3); position = jamcam_files[number].position; /* don't know why this is necessary, but do it anyway */ if ( camera->port->type == GP_PORT_USB ) { position += 8; } if ( camera->port->type == GP_PORT_USB ) { gp_port_usb_msg_write( camera->port, 0xa5, 0x0005, 0x0000, NULL, 0 ); } result = jamcam_fetch_memory( camera, file, tmp_buf, position, jamcam_files[number].data_incr, context ); /* this seems to reset the camera to a sane status */ if ( camera->port->type == GP_PORT_USB ) { gp_port_usb_msg_write( camera->port, 0xa5, 0x0006, 0x0000, NULL, 0 ); } if ( result == GP_OK ) { *len = jamcam_files[number].width * jamcam_files[number].height; memcpy( buf, tmp_buf + 0x10, *len ); } free (tmp_buf); return( result ); } struct jamcam_file *jamcam_file_info(Camera *camera, int number) { GP_DEBUG(" * jamcam_file_info, nr is %d", number); return( &jamcam_files[number] ); } int jamcam_request_thumbnail( Camera *camera, CameraFile *file, char *buf, int *len, int number, GPContext *context ) { unsigned char line[2048]; char packet[16]; int position; int x, y; int res = GP_OK; char *ptr; int bytes_to_read; unsigned int id; GP_DEBUG ("* jamcam_request_thumbnail"); memset( packet, 0, sizeof( packet )); position = jamcam_files[number].position + 0x10; *len = 4800; ptr = buf; if ( camera->port->type == GP_PORT_USB ) { /* windows driver does this sometimes */ gp_port_usb_msg_write( camera->port, 0xa5, 0x0005, 0x0000, NULL, 0 ); /* just read one row of data at a time */ bytes_to_read = jamcam_files[number].width; } else { /* MMC card is quirky, need to fetch larger amounts of data */ if ( position >= 0x40000000 ) { /* serial with mmc card needs bigger packets */ bytes_to_read = 2048; } else { /* just read one row of data at a time */ bytes_to_read = jamcam_files[number].width; } } /* fetch thumbnail lines and build the thumbnail */ position += 10 * jamcam_files[number].width; id = gp_context_progress_start (context, 60., _("Downloading thumbnail...")); for( y = 0 ; y < 60 ; y++ ) { jamcam_fetch_memory( camera, file, line, position, bytes_to_read, context ); gp_context_progress_update (context, id, y); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { res = GP_ERROR_CANCEL; break; } if ( jamcam_files[number].width == 600 ) { for( x = 22; x < 578 ; x += 7 ) { *(ptr++) = line[x]; } position += 7 * 600; } else { for( x = 0; x < 320 ; ) { *(ptr++) = line[x]; x += 3; *(ptr++) = line[x]; x += 5; } if ( y % 2 ) { position += 5 * 320; } else { position += 3 * 320; } } } gp_context_progress_stop (context, id); /* this seems to reset the camera to a sane status */ if ( camera->port->type == GP_PORT_USB ) { gp_port_usb_msg_write( camera->port, 0xa5, 0x0006, 0x0000, NULL, 0 ); } return( res ); } static int jamcam_write_packet (Camera *camera, unsigned char *packet, int length) { int ret, r; GP_DEBUG ("* jamcam_write_packet"); for (r = 0; r < RETRIES; r++) { ret = gp_port_write (camera->port, (char*)packet, length); if (ret == GP_ERROR_TIMEOUT) continue; return (ret); } return (GP_ERROR_TIMEOUT); } static int jamcam_read_packet (Camera *camera, unsigned char *packet, int length) { int r = 0; int bytes_read; GP_DEBUG ("* jamcam_read_packet"); GP_DEBUG ("*** length: %d (0x%x)", length, length); for (r = 0; r < RETRIES; r++) { bytes_read = gp_port_read (camera->port, (char*)packet, length); if (bytes_read == GP_ERROR_TIMEOUT) continue; if (bytes_read < 0) return (bytes_read); if ( bytes_read == length ) { return( GP_OK ); } } return (GP_ERROR_TIMEOUT); } int jamcam_enq (Camera *camera) { int ret, r = 0; unsigned char buf[16]; GP_DEBUG ("* jamcam_enq"); memset( buf, 0, 16 ); switch( camera->port->type ) { default: case GP_PORT_SERIAL: for (r = 0; r < RETRIES; r++) { memcpy (buf, "KB99", 4 ); ret = jamcam_write_packet (camera, buf, 4); if (ret == GP_ERROR_TIMEOUT) continue; if (ret != GP_OK) return (ret); ret = jamcam_read_packet (camera, buf, 4); if (ret == GP_ERROR_TIMEOUT) continue; if (ret != GP_OK) return (ret); if ( !memcmp( buf, "KIDB", 4 )) { return (GP_OK); } } return (GP_ERROR_CORRUPTED_DATA); break; case GP_PORT_USB: for (r = 0; r < RETRIES; r++) { gp_port_usb_msg_write( camera->port, 0xa5, 0x0004, 0x0000, NULL, 0 ); jamcam_set_usb_mem_pointer( camera, 0x0000 ); CHECK( gp_port_read( camera->port, (char *)buf, 0x0c )); if (( !memcmp( buf, "KB00", 4 )) || (( buf[0] == 0xff ) && ( buf[1] == 0xff ) && ( buf[2] == 0xff ) && ( buf[3] == 0xff ) && ( buf[4] == 0xff ) && ( buf[5] == 0xff ) && ( buf[6] == 0xff ) && ( buf[7] == 0xff ))) { /* found a JamCam v3 camera */ /* reply contains 4-bytes with MMC card size if present */ /* set to 0 if none */ jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 8 ); if ( jamcam_mmc_card_size ) { GP_DEBUG ( "* jamcam_enq, MMC card size = %d", jamcam_mmc_card_size ); } return (GP_OK); } else if ( !memcmp( buf + 8, "KB00", 4 )) { /* found a JamCam v2 camera */ /* JamCam v2 doesn't support MMC card so no need to check */ return (GP_OK); } else if (( buf[0] == 0xf0 ) && ( buf[1] == 0xfd ) && ( buf[2] == 0x03 )) { return( GP_OK ); } } return (GP_ERROR_CORRUPTED_DATA); break; } return (GP_ERROR_TIMEOUT); } static int jamcam_query_mmc_card (Camera *camera) { int ret, r = 0; unsigned char buf[16]; GP_DEBUG ("* jamcam_query_mmc_card"); /* usb port doesn't need this packet, this info found in enquiry reply */ if ( camera->port->type == GP_PORT_USB ) { return( GP_OK ); } memcpy( buf, "KB04", 4 ); for (r = 0; r < RETRIES; r++) { ret = jamcam_write_packet (camera, buf, 4); if (ret == GP_ERROR_TIMEOUT) continue; if (ret != GP_OK) return (ret); ret = jamcam_read_packet (camera, buf, 4); if (ret == GP_ERROR_TIMEOUT) continue; if (ret != GP_OK) return (ret); /* reply is 4-byte int showing length of MMC card if any, 0 if none */ jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 0 ); if ( jamcam_mmc_card_size ) { GP_DEBUG ("* jamcam_query_mmc_card, MMC card size = %d", jamcam_mmc_card_size ); } return (GP_OK); } return (GP_ERROR_TIMEOUT); }