summaryrefslogtreecommitdiff
path: root/camlibs/mars/mars.c
diff options
context:
space:
mode:
Diffstat (limited to 'camlibs/mars/mars.c')
-rw-r--r--camlibs/mars/mars.c342
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]);
+}