diff options
Diffstat (limited to 'camlibs/mars/mars.c')
-rw-r--r-- | camlibs/mars/mars.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/camlibs/mars/mars.c b/camlibs/mars/mars.c new file mode 100644 index 000000000..04b7a53a0 --- /dev/null +++ b/camlibs/mars/mars.c @@ -0,0 +1,342 @@ +/* mars.c + * + * Copyright (C) 2004 Theodore Kilgore <kilgota@auburn.edu> + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <math.h> + +#include <gphoto2/gphoto2.h> +#include <gphoto2/gphoto2-port.h> +#include "gphoto2-endian.h" + +#include "mars.h" + +#define GP_MODULE "mars" + +#define INIT 0xb5 +#define GET_DATA 0x0f + +static int +M_READ (GPPort *port, char *data, int size) +{ + gp_port_write(port, "\x21", 1); + gp_port_read(port, data, 16); + return GP_OK; +} + +static int +M_COMMAND (GPPort *port, char *command, int size, char *response) +{ + gp_port_write(port, command, size); + M_READ(port, response, 16); + return GP_OK; +} + +static int mars_routine (Info *info, GPPort *port, char param, int n); + +int +mars_init (Camera *camera, GPPort *port, Info *info) +{ + unsigned char c[16]; + unsigned char status = 0; + memset(info,0, sizeof(info)); + memset(c,0,sizeof(c)); + GP_DEBUG("Running mars_init\n"); + + /* Init routine done twice, usually. First time is a dry run. But if + * camera reports 0x02 it is "jammed" and we must clear it. + */ + + M_READ(port, c, 16); + if ( (c[0] == 0x02 ) ) { + gp_port_write(port, "\x19", 1); + gp_port_read(port, c, 16); + } + else { + status = mars_routine (info, port, INIT, 0); + GP_DEBUG("status = 0x%x\n", status); + } + + /* Not a typo. This _will_ download the config data ;) */ + mars_read_picture_data (camera, info, port, info, 0x2000, 0); + + /* Removing extraneous line(s) of data. See "protocol.txt" */ + + if ((info[0] == 0xff)&& (info[1] == 0)&&(info[2]==0xff)) + memmove(info, info + 16, 0x1ff0); /* Saving config */ + else + memcpy(info, info + 144, 0x1f70); /* Saving config */ + + GP_DEBUG("Leaving mars_init\n"); + return GP_OK; +} + +int +mars_get_num_pics (Info *info) +{ + unsigned int i = 0; + + for (i = 0; i < 0x3fe; i++) + if ( !(0xff - info[8*i]) ) { + GP_DEBUG ( "i is %i\n", i); + memcpy(info+0x1ff0, "i", 1); + return i; + } + memcpy(info+0x1ff0, "0", 1); + return 0; +} + + +int +mars_get_pic_data_size (Info *info, int n) +{ + return (info[8*n+6]*0x100 + info[8*n+5])*0x100 + info[8*n+4]; +} + +int +set_usb_in_endpoint (Camera *camera, int inep) +{ + GPPortSettings settings; + gp_port_get_settings ( camera ->port, &settings); + settings.usb.inep = inep; + GP_DEBUG("inep reset to %02X\n", inep); + return gp_port_set_settings ( camera ->port, settings); +} + + +int +mars_read_data (GPPort *port, char *data, int size) +{ + int MAX_BULK = 0x2000; + int len = 0; + while(size > 0) { + len = (size>MAX_BULK)?MAX_BULK:size; + gp_port_read (port, data, len); + data += len; + size -= len; + } + + return 1; +} + +int +mars_read_picture_data (Camera *camera, Info *info, GPPort *port, + char *data, int size, int n) + +{ + unsigned char c[16]; + + memset(c,0,sizeof(c)); + /*Initialization routine for download. */ + mars_routine (info, port, GET_DATA, n); + /*Data transfer begins*/ + set_usb_in_endpoint (camera, 0x82); + mars_read_data (port, data, size); + set_usb_in_endpoint (camera, 0x83); + return GP_OK; +} + +int +mars_reset (GPPort *port) +{ + gp_port_write(port, "\x19\x54", 2); + return GP_OK; +} + +static void precalc_table(code_table_t *table) +{ + int i; + int is_abs, val, len; + + for (i = 0; i < 256; i++) { + is_abs = 0; + val = 0; + len = 0; + if ((i & 0x80) == 0) { + /* code 0 */ + val = 0; + len = 1; + }else if ((i & 0xE0) == 0xC0) { + /* code 110 */ + val = -3; + len = 3; + }else if ((i & 0xE0) == 0xA0) { + /* code 101 */ + val = +3; + len = 3; + }else if ((i & 0xF0) == 0x80) { + /* code 1000 */ + val = +7; + len = 4; + }else if ((i & 0xF0) == 0x90) { + /* code 1001 */ + val = -7; + len = 4; + }else if ((i & 0xF0) == 0xF0) { + /* code 1111 */ + val = -15; + len = 4; + }else if ((i & 0xF8) == 0xE0) { + /* code 11100 */ + val = +15; + len = 5; + }else if ((i & 0xF8) == 0xE8) { + /* code 11101xxxxx */ + is_abs = 1; + val = 0; /* value is calculated later */ + len = 5; + } + table[i].is_abs = is_abs; + table[i].val = val; + table[i].len = len; + } +} + +#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) +#define GET_CODE addr = inp + (bitpos >> 3); \ + code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))) + + +int mars_decompress (unsigned char *inp, unsigned char *outp, int width, + int height) +{ + int row, col; + unsigned char code; + int val; + code_table_t table[256]; + unsigned char *addr; + int bitpos; + unsigned char lp,tp,tlp,trp; + /* First calculate the Huffman table */ + precalc_table(table); + + bitpos = 0; + + /* main decoding loop */ + for (row = 0; row < height; row++) { + col = 0; + + /* first two pixels in first two rows are stored as raw 8-bit */ + if (row < 2) { + GET_CODE; + bitpos += 8; + *outp++ = code; + + GET_CODE; + bitpos += 8; + *outp++ = code; + + col += 2; + } + + while (col < width) { + /* get bitcode */ + GET_CODE; + /* update bit position */ + bitpos += table[code].len; + + /* calculate pixel value */ + if (table[code].is_abs) { + /* get 5 more bits and use them as absolute value */ + GET_CODE; + val = (code & 0xF8); + bitpos += 5; + + }else { + /* value is relative to top or left pixel */ + val = table[code].val; + lp = outp[-2]; + if (row > 1) { + tlp = outp[-2*width-2]; + tp = outp[-2*width]; + trp = outp[-2*width+2]; + } + if (row < 2) { + /* top row: relative to left pixel */ + val += lp; + }else if (col < 2) { + /* left column: relative to top pixel */ + /* initial estimate */ + val += (2*tp + 2*trp +1)/4; + }else if (col > width - 3) { + /* left column: relative to top pixel */ + val += (2*tp + 2*tlp +1)/4; + /* main area: average of left and top pixel */ + }else { + /* initial estimate for predictor */ + val += (2*lp + tp + trp + 1)/4; + } + } + /* store pixel */ + *outp++ = CLAMP(val); + col++; + } + } + return GP_OK; +} + +static int +mars_routine (Info *info, GPPort *port, char param, int n) +{ + unsigned char c[16]; + unsigned char start[2] = {0x19, 0x51}; + unsigned char do_something[2]; + /* See protocol.txt for my theories about what these mean. */ + unsigned char address1[2] = {0x19, info[8*n+1]}; + unsigned char address2[2] = {0x19, info[8*n+2]}; + unsigned char address3[2] = {0x19, info[8*n+3]}; + unsigned char address4[2] = {0x19, info[8*n+4]}; + unsigned char address5[2] = {0x19, info[8*n+5]}; + unsigned char address6[2] = {0x19, info[8*n+6]}; + + do_something[0]= 0x19; + do_something[1]=param; + + + memset(c,0,sizeof(c)); + + /*Routine used in initialization, photo download, and reset. */ + M_READ(port, c, 16); + M_COMMAND(port, start, 2, c); + M_COMMAND(port, do_something, 2, c); + M_COMMAND(port, address1, 2, c); + + c[0] = 0; + gp_port_write(port, address2, 2); + /* Moving the memory cursor to the given address? */ + while (( c[0] != 0xa) ) { + M_READ(port, c, 16); + } + + M_COMMAND(port, address3, 2, c); + M_COMMAND(port, address4, 2, c); + M_COMMAND(port, address5, 2, c); + M_COMMAND(port, address6, 2, c); + gp_port_write(port, "\x19", 1); + gp_port_read(port, c , 16); + /* Next thing is to switch the inep. Some cameras need a pause here */ + usleep (MARS_SLEEP); + + return(c[0]); +} |