summaryrefslogtreecommitdiff
path: root/camlibs/largan/lmini/lmini.c
diff options
context:
space:
mode:
Diffstat (limited to 'camlibs/largan/lmini/lmini.c')
-rw-r--r--camlibs/largan/lmini/lmini.c582
1 files changed, 582 insertions, 0 deletions
diff --git a/camlibs/largan/lmini/lmini.c b/camlibs/largan/lmini/lmini.c
new file mode 100644
index 000000000..f70457ba4
--- /dev/null
+++ b/camlibs/largan/lmini/lmini.c
@@ -0,0 +1,582 @@
+/* library.c (for Largan)
+ *
+ * Copyright © 2002 Hubert Figuiere <hfiguiere@teaser.fr>
+ * Code largely borrowed to lmini-0.1 by Steve O Connor
+ * With the help of specifications for lmini camera by Largan
+ *
+ * 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 <string.h>
+
+#include <gphoto2/gphoto2.h>
+#include <gphoto2/gphoto2-port.h>
+#include "gphoto2-endian.h"
+
+#include "lmini.h"
+#include "lmini_ccd.h"
+
+
+#define GP_MODULE "largan"
+
+static const char BMPheader[54]={
+ 0x42, 0x4d, 0x36, 0x10, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x28,
+ 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0, 0x1, 0x0,0x18, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0,0x10, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ };
+
+#if 0
+/*
+ * baud rate enumerations
+ */
+static struct largan_baud_rate {
+ int baud;
+ char value; /* value to be sent in the protocol */
+} bauds [] = {
+ {19200, 0x02 }, /* default */
+ {38400, 0x03 },
+ { 9600, 0x01 },
+ { 4800, 0x00 },
+ { 0, 0x00 }
+};
+#endif
+
+enum {
+ LARGAN_NUM_PICT_CMD = 0xfa,
+ LARGAN_GET_PICT_CMD = 0xfb,
+ LARGAN_BAUD_ERASE_CMD = 0xfc, /* set baud rate and erase use the same command */
+ LARGAN_CAPTURE_CMD = 0xfd
+};
+
+
+static int purge_camera (Camera * camera);
+static int wakeup_camera (Camera * camera);
+static int largan_send_command (Camera * camera, uint8_t cmd,
+ uint8_t param1, uint8_t param2);
+static int largan_recv_reply (Camera * camera, uint8_t *reply,
+ uint8_t *code, uint8_t * code2);
+static int set_serial_speed (Camera * camera, int speed);
+
+
+largan_pict_info * largan_pict_new (void)
+{
+ largan_pict_info * ptr = (largan_pict_info *)malloc (sizeof (largan_pict_info));
+ memset (ptr, 0, sizeof (largan_pict_info));
+ ptr->quality = 0xff; /* something invalid */
+ return ptr;
+}
+
+
+void largan_pict_free (largan_pict_info * ptr)
+{
+ if (ptr->data) {
+ free (ptr->data);
+ }
+ free (ptr);
+}
+
+
+void largan_pict_alloc_data (largan_pict_info * ptr, uint32_t size)
+{
+ ptr->data = realloc (ptr->data, size);
+ ptr->data_size = size;
+}
+
+
+/*
+ * Open the camera
+ */
+int largan_open (Camera * camera)
+{
+ int ret;
+
+ ret = largan_get_num_pict (camera);
+ if (ret < 0){
+ ret = purge_camera (camera);
+ if (ret == GP_ERROR) {
+ return ret;
+ }
+ ret = wakeup_camera (camera);
+ }
+ return ret; /* here: number of pictures */
+}
+
+/*
+ * Return the number of pictures in the camera, -1 if error.
+ */
+int largan_get_num_pict (Camera * camera)
+{
+ int ret;
+ unsigned char reply, code;
+
+ ret = largan_send_command (camera, LARGAN_NUM_PICT_CMD, 0, 0);
+ if (ret < 0) {
+ GP_DEBUG ("largan_send_command() failed: %d\n", ret);
+ return -1;
+ }
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ GP_DEBUG ("largan_recv_reply() failed: %d\n", ret);
+ return -1;
+ }
+ if (reply != LARGAN_NUM_PICT_CMD) {
+ GP_DEBUG ("Reply incorrect\n");
+ return -1;
+ }
+ return code;
+}
+
+/*
+ * get image index and return it in largan_pict_info
+ *
+ * return GP_OK if OK. Otherwise < 0
+ */
+int largan_get_pict (Camera * camera, largan_pict_type type,
+ uint8_t index, largan_pict_info * pict)
+{
+ int ret;
+ uint8_t reply,code;
+ uint8_t param;
+ uint8_t buf[5];
+ uint32_t pict_size; /* size of the picture as returned by the camera */
+
+ switch (type) {
+ case LARGAN_PICT:
+ param = 0x01;
+ break;
+ case LARGAN_THUMBNAIL:
+ param = 0x00;
+ break;
+ default:
+ GP_DEBUG ("largan_get_pict(): wrong picture type requested !\n");
+ return GP_ERROR;
+ }
+ ret = largan_send_command (camera, LARGAN_GET_PICT_CMD, param, index);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+/* here we have to receive 7 bytes back
+ the 2nd contains 00 for thumbnail or 01 for original picture
+ the 3rd contains the picturenumber for an original picture
+ or 00 for an thumbnail for an lowres picture
+ or 01 for an thumbnail for an hires picture
+ bytes 4 5 6 7 contain the number of byte coming in the datastream */
+/* the 1st and the 2nd byte are read here */
+ if (ret < 0) {
+ /* clean up and give it a 2nd chance */
+ wakeup_camera (camera);
+ largan_send_command (camera, LARGAN_GET_PICT_CMD, param, index);
+ GP_DEBUG ("largan_get_pict(): command sent 2nd time\n");
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ /* clean up and give it even a 3rd chance */
+ wakeup_camera (camera);
+ sleep (5);
+ largan_send_command (camera, LARGAN_GET_PICT_CMD, param, index);
+ GP_DEBUG ("largan_get_pict(): command sent 3rd time\n");
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ GP_DEBUG ("largan_get_pict(): timeout after command sent 3rd time\n");
+ return ret; /* timeout after 3rd trial */
+ }
+ }
+ }
+ if ((reply != LARGAN_GET_PICT_CMD) || ((code != 0x01) && (code != 0x00))) {
+ GP_DEBUG ("largan_get_pict(): code != 0x01 && 0x00\n");
+ return GP_ERROR;
+ }
+
+ /* the remaining 5 bytes are read here */
+
+ ret = gp_port_read (camera->port, buf, sizeof(buf));
+ if (ret < GP_OK) {
+ return ret;
+ }
+ if (ret < 5) {
+ GP_DEBUG ("largan_get_pict(): unexpected short read\n");
+ return GP_ERROR;
+ }
+ if (type == LARGAN_PICT) {
+ if (buf[0] != index) {
+ GP_DEBUG ("largan_get_pict(): picture index inconsistent\n");
+ return GP_ERROR;
+ }
+ }
+ else {
+ if (buf[0] > 1) {
+ GP_DEBUG ("largan_get_pict(): thumb size inconsistent\n");
+ return GP_ERROR;
+ }
+ }
+ pict->type = type;
+ pict_size = be32atoh (&buf[1]);
+ switch (type) {
+ case LARGAN_PICT:
+ largan_pict_alloc_data (pict, pict_size);
+ ret = gp_port_read (camera->port, pict->data, pict->data_size);
+ if (ret < GP_OK) {
+ return ret;
+ }
+ if (ret < pict->data_size) {
+ GP_DEBUG ("largan_get_pict(): picture data short read\n");
+ return GP_ERROR;
+ }
+ pict->quality = 0xff; /* this is not a thumbnail */
+ break;
+ case LARGAN_THUMBNAIL:
+ {
+ char * buffer = (char*)malloc(pict_size);
+ ret = gp_port_read (camera->port, buffer, pict_size);
+ if (ret < GP_OK) {
+ return ret;
+ }
+ largan_pict_alloc_data (pict, 19200 + sizeof(BMPheader));
+ memcpy (pict->data, BMPheader, sizeof(BMPheader));
+ /*this is the segfaulty function */
+ largan_ccd2dib (buffer, pict->data + sizeof(BMPheader), 240, 1);
+
+ free (buffer);
+ pict->quality = buf[0];
+ break;
+ }
+ default:
+ GP_DEBUG ("largan_get_pict(): type not LARGAN_PICT nor LARGAN_THUMBNAIL\n");
+ return GP_ERROR;
+ }
+ return GP_OK;
+}
+
+
+
+/*
+ * erase a pictures
+ * if all > 0 then all pictures are erased, otherwise the last one is
+ *
+ * return GP_OK if OK.
+ */
+int largan_erase (Camera *camera, int pict_num)
+{
+ int ret;
+ int num_pix;
+ uint8_t erase_code;
+ uint8_t reply,code;
+
+ if (pict_num == 0xff) {
+ erase_code = 0x11;
+ GP_DEBUG ("largan_erase() all sheets \n");
+ }
+ else {
+ num_pix = largan_get_num_pict (camera);
+ if (pict_num == num_pix) {
+ erase_code = 0x10;
+ GP_DEBUG ("largan_erase() last sheet \n");
+ }
+ else {
+ GP_DEBUG ("Only the last sheet can be erased!\n");
+ return GP_ERROR;
+ }
+ }
+ ret = largan_send_command (camera, LARGAN_BAUD_ERASE_CMD, erase_code, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ if ((reply != LARGAN_BAUD_ERASE_CMD) || (code != erase_code)) {
+ GP_DEBUG ("largan_erase() wrong error code\n");
+ return GP_ERROR;
+ }
+ return GP_OK;
+}
+
+/*
+ * Take a picture with the camera
+ *
+ * return GP_OK if OK
+ */
+int largan_capture (Camera *camera)
+{
+ int ret;
+ uint8_t reply, code, code2;
+
+ ret = largan_send_command (camera, LARGAN_CAPTURE_CMD, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = largan_recv_reply (camera, &reply, &code, &code2);
+ if (ret < 0) {
+ GP_DEBUG ("return ret\n");
+ return ret;
+ }
+ if (reply != LARGAN_CAPTURE_CMD) {
+ GP_DEBUG ("largan_capture(): inconsisten reply code\n");
+ return GP_ERROR;
+ }
+ if (code != code2) {
+ GP_DEBUG ("code != code2\n");
+ return GP_ERROR;
+ }
+ if (code == 0xee) {
+ GP_DEBUG ("Memory full\n");
+ return GP_ERROR;
+ }
+ if (code != 0xff) {
+ GP_DEBUG ("largan_capture(): inconsistent reply\n");
+ return GP_ERROR;
+ }
+ return GP_OK;
+}
+
+
+#if 0
+/*
+ * Tell the camera to change the speed
+ * Then set the serial port speed
+ */
+static int largan_set_serial_speed (Camera * camera, int speed)
+{
+ int ret;
+ int i;
+ uint8_t reply, code;
+
+ if (camera->port->type != GP_PORT_SERIAL) {
+ GP_DEBUG ("largan_set_serial_speed() called on non serial port\n");
+ return GP_ERROR;
+ }
+ for (i = 0; bauds[i].baud; i++) {
+ if (bauds[i].baud == speed) {
+ ret = largan_send_command (camera, LARGAN_BAUD_ERASE_CMD, bauds[i].value, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = largan_recv_reply (camera, &reply, &code, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ if (reply != LARGAN_BAUD_ERASE_CMD) {
+ return ret;
+ }
+ if (code != bauds[i].baud) {
+ return ret;
+ }
+ return set_serial_speed (camera, bauds[i].baud);
+ }
+ }
+ GP_DEBUG ("largan_set_serial_speed(): baud rate not found\n");
+ return GP_ERROR;
+}
+#endif
+
+
+/*
+ * received a reply from the camera.
+ * can accept NULL on input.
+ * TODO: check how much we need to read.
+ */
+static int largan_recv_reply (Camera * camera, uint8_t *reply,
+ uint8_t *code, uint8_t *code2)
+{
+ int ret;
+ uint8_t packet [4];
+ uint8_t packet_size = 0;
+ memset (packet, 0, sizeof (packet));
+ ret = gp_port_read (camera->port, packet, 1);
+ if (ret < GP_OK) {
+ return ret;
+ }
+ switch (packet[0])
+ {
+ case LARGAN_NUM_PICT_CMD:
+ packet_size = 2;
+ break;
+ case LARGAN_GET_PICT_CMD:
+ packet_size = 2;
+ break;
+ case LARGAN_BAUD_ERASE_CMD:
+ packet_size = 2;
+ break;
+ case LARGAN_CAPTURE_CMD:
+ packet_size = 3;
+ break;
+ default:
+ packet_size = 0;
+ GP_DEBUG("largan_receive_reply: Unkown reply.\n");
+ break;
+ }
+ if (reply) {
+ *reply = packet[0];
+ }
+ if (packet_size >= 2) {
+ ret = gp_port_read (camera->port, &packet[1], 1);
+ if (ret < GP_OK) {
+ return ret;
+ }
+ if (code) {
+ *code = packet[1];
+ }
+ }
+ if (packet_size >= 3) {
+ ret = gp_port_read (camera->port, &packet[2], 1);
+ if (ret < GP_OK) {
+ return ret;
+ }
+ if (code2) {
+ *code2 = packet[2];
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Send a command packet
+ */
+static int largan_send_command (Camera * camera, uint8_t cmd, uint8_t param1,
+ uint8_t param2)
+{
+ uint8_t packet_size = 0;
+ uint8_t packet [3];
+ memset (&packet, 0, sizeof (packet));
+
+ packet [0] = cmd;
+
+ switch (cmd) {
+ case LARGAN_NUM_PICT_CMD:
+ packet_size = 1;
+ break;
+ case LARGAN_GET_PICT_CMD:
+ if ((param1 != 0) && (param1 != 1)) {
+ GP_DEBUG ("wrong parameter for get picture\n");
+ return GP_ERROR; /* wrong parameter */
+ }
+ packet[1] = param1;
+ packet[2] = param2;
+ packet_size = 3;
+ break;
+ case LARGAN_BAUD_ERASE_CMD:
+ if ((param1 > 0x11) || ((param1 > 0x03) && (param1 < 0x10))) {
+ GP_DEBUG ("wrong parameter for baud/erase\n");
+ return GP_ERROR; /* wrong parameter */
+ }
+ packet[1] = param1;
+ packet_size = 2;
+ break;
+ case LARGAN_CAPTURE_CMD:
+ packet_size = 1;
+ break;
+ default:
+ GP_DEBUG ("unknown command\n");
+ return GP_ERROR; /* unknown command */
+ }
+
+ return gp_port_write (camera->port, packet, packet_size);
+}
+
+
+/*
+ * set the baud speed for serial port
+ */
+static int set_serial_speed (Camera * camera, int speed)
+{
+ int ret;
+ GPPortSettings settings;
+ GP_DEBUG ("set_serial_speed() called ***************\n");
+
+ if (camera->port->type != GP_PORT_SERIAL) {
+ GP_DEBUG ("set_serial_speed() called on non serial port\n");
+ return GP_ERROR;
+ }
+
+ ret = gp_port_get_settings (camera->port, &settings);
+ if (ret < 0) {
+ return ret;
+ }
+ settings.serial.speed = speed;
+
+ ret = gp_port_set_settings (camera->port, settings);
+ return ret;
+}
+
+/*
+ * purge the camera internal buffers
+ */
+static int purge_camera (Camera * camera)
+{
+ int count;
+ long t1, t2;
+ uint8_t buffer[1];
+
+ t1 = time (NULL);
+
+ while (1)
+ {
+ count = gp_port_read (camera->port, buffer, 1);
+ if (count < GP_OK)
+ return count;
+
+ if (count)
+ {
+ t1 = time(NULL);
+ }
+ else
+ {
+ t2 = time(NULL);
+ if ((t2 - t1) > 1)
+ {
+ GP_DEBUG ("Camera purged\n");
+ return GP_OK;
+ }
+ }
+ }
+ GP_DEBUG ("Could not purge camera\n");
+ return GP_ERROR;
+}
+
+/*
+ * Try to initiate something with the camera just to make sure it
+ * answer. Will check all the speed in case the camera has not been reset
+ * Perhaps is there a smarter way. This is the way it is done in lmini.
+ */
+static int wakeup_camera (Camera * camera)
+{
+ int num_pix;
+ /* int i;*/
+ int ret;
+
+ if (camera->port->type == GP_PORT_SERIAL) {
+ ret = set_serial_speed (camera, 4800); /*wakes camera best*/
+ num_pix = largan_get_num_pict (camera); /*this wakes*/
+ ret = set_serial_speed (camera, 19200); /*back to normal*/
+ sleep (1);
+ num_pix = largan_get_num_pict (camera); /*this wakes*/
+ if (num_pix >= 0){
+ return GP_OK;
+ }
+ }
+ purge_camera (camera);
+ return GP_ERROR;
+}