From ee9ca87e8ed77476c74eaded971fecbb45467f24 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 20 Nov 2013 21:33:46 -0500 Subject: [PATCH] kodak605: Add an initial implementation of a Kodak 605 backend --- .gitignore | 1 + Makefile | 2 +- backend_common.h | 1 + backend_kodak605.c | 396 +++++++++++++++++++++++ icm/Kodak605/KODAK 605 Photo Printer.icm | 3 + 5 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 backend_kodak605.c create mode 100644 icm/Kodak605/KODAK 605 Photo Printer.icm diff --git a/.gitignore b/.gitignore index 6ebd174..4c6a4c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *~ sonyupdr150 kodak6800 +kodak605 kodak1400 gutenprint shinkos2145 diff --git a/Makefile b/Makefile index d50add5..de4a08a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LDFLAGS = -lusb-1.0 CUPS_BACKEND_DIR = /usr/lib/cups/backend CUPS_DATA_DIR = /usr/share/cups -BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy mitsu70x +BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy mitsu70x kodak605 DEPS = backend_common.h diff --git a/backend_common.h b/backend_common.h index 80bc9e7..d89f982 100644 --- a/backend_common.h +++ b/backend_common.h @@ -90,6 +90,7 @@ enum { P_KODAK_6800, P_KODAK_6850, P_KODAK_1400_805, + P_KODAK_605, P_SHINKO_S2145, P_SONY_UPDR150, P_MITSU_D70X, diff --git a/backend_kodak605.c b/backend_kodak605.c new file mode 100644 index 0000000..a73e9a4 --- /dev/null +++ b/backend_kodak605.c @@ -0,0 +1,396 @@ +/* + * Kodak 605 Photo Printer CUPS backend -- libusb-1.0 version + * + * (c) 2013 Solomon Peachy + * + * The latest version of this program can be found at: + * + * http://git.shaftnet.org/cgit/selphy_print.git + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * [http://www.gnu.org/licenses/gpl-3.0.html] + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "backend_common.h" + +#define USB_VID_KODAK 0x040A +#define USB_PID_KODAK_605 0x402E + +/* File header */ +struct kodak605_hdr { + uint8_t hdr[4]; /* 01 40 0a 00 */ + uint8_t unk1; /* 01 or 02 */ + uint8_t copies; /* 01 or more */ + uint8_t unk2; /* always 00 */ + uint16_t columns; /* BE always 0x0734 */ + uint16_t rows; /* BE */ + uint8_t media; /* 0x03 for 6x8, 0x01 for 6x4 */ + uint8_t laminate; /* 0x02 to laminate, 0x01 for not */ + uint8_t unk3; /* 0x00, 0x01 [may be print mode] */ +} __attribute__((packed)); + +#define CMDBUF_LEN 4 + +/* Private data stucture */ +struct kodak605_ctx { + struct libusb_device_handle *dev; + uint8_t endp_up; + uint8_t endp_down; + + int type; + struct kodak605_hdr hdr; + uint8_t *databuf; + int datalen; +}; + +/* Program states */ +enum { + S_IDLE = 0, + S_READY, + S_STARTED, + S_SENT_HDR, + S_SENT_DATA, + S_FINISHED, +}; + +#define READBACK_LEN 120 + +static void *kodak605_init(void) +{ + struct kodak605_ctx *ctx = malloc(sizeof(struct kodak605_ctx)); + if (!ctx) + return NULL; + memset(ctx, 0, sizeof(struct kodak605_ctx)); + + ctx->type = P_ANY; + + return ctx; +} + +static void kodak605_attach(void *vctx, struct libusb_device_handle *dev, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +{ + struct kodak605_ctx *ctx = vctx; + struct libusb_device *device; + struct libusb_device_descriptor desc; + + ctx->dev = dev; + ctx->endp_up = endp_up; + ctx->endp_down = endp_down; + + device = libusb_get_device(dev); + libusb_get_device_descriptor(device, &desc); + + ctx->type = P_KODAK_605; +} + +static void kodak605_teardown(void *vctx) { + struct kodak605_ctx *ctx = vctx; + + if (!ctx) + return; + + if (ctx->databuf) + free(ctx->databuf); + free(ctx); +} + +static int kodak605_read_parse(void *vctx, int data_fd) { + struct kodak605_ctx *ctx = vctx; + + if (!ctx) + return 1; + + /* Read in then validate header */ + read(data_fd, &ctx->hdr, sizeof(ctx->hdr)); + if (ctx->hdr.hdr[0] != 0x01 || + ctx->hdr.hdr[1] != 0x40 || + ctx->hdr.hdr[2] != 0x0a || + ctx->hdr.hdr[3] != 0x00) { + ERROR("Unrecognized data format!\n"); + return(1); + } + + ctx->datalen = be16_to_cpu(ctx->hdr.rows) * be16_to_cpu(ctx->hdr.columns) * 3; + ctx->databuf = malloc(ctx->datalen); + if (!ctx->databuf) { + ERROR("Memory allocation failure!\n"); + return 2; + } + + { + int remain = ctx->datalen; + uint8_t *ptr = ctx->databuf; + int ret; + do { + ret = read(data_fd, ptr, remain); + if (ret < 0) { + ERROR("Read failed (%d/%d/%d)\n", + ret, remain, ctx->datalen); + perror("ERROR: Read failed"); + return ret; + } + ptr += ret; + remain -= ret; + } while (remain); + } + + return 0; +} + +static int kodak605_main_loop(void *vctx, int copies) { + struct kodak605_ctx *ctx = vctx; + + uint8_t rdbuf[READBACK_LEN]; + uint8_t rdbuf2[READBACK_LEN]; + uint8_t cmdbuf[CMDBUF_LEN]; + + int last_state = -1, state = S_IDLE; + int i, num, ret; + int pending = 0; + + if (!ctx) + return 1; + +top: + if (state != last_state) { + DEBUG("last_state %d new %d\n", last_state, state); + } + + if (pending) + goto skip_query; + + /* Send Status Query */ + cmdbuf[0] = 0x01; + cmdbuf[1] = 0x00; + cmdbuf[2] = 0x00; + cmdbuf[3] = 0x00; + + if ((ret = send_data(ctx->dev, ctx->endp_down, + cmdbuf, CMDBUF_LEN))) + return ret; + +skip_query: + /* Read in the printer status */ + memset(rdbuf, 0, READBACK_LEN); + ret = libusb_bulk_transfer(ctx->dev, ctx->endp_up, + rdbuf, + READBACK_LEN, + &num, + 5000); + + if (ret < 0 || num < 76) { + ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, num, READBACK_LEN, ctx->endp_up); + if (ret < 0) + return ret; + return 4; + } + + if (num != 76 || num != 113) { + ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n", + num, READBACK_LEN, ctx->endp_up); + return ret; + } + + // XXX detect media type based on readback. + + if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) { + DEBUG("readback: "); + for (i = 0 ; i < num ; i++) { + DEBUG2("%02x ", rdbuf[i]); + } + DEBUG2("\n"); + memcpy(rdbuf2, rdbuf, READBACK_LEN); + } else if (state == last_state) { + sleep(1); + } + last_state = state; + + fflush(stderr); + + pending = 0; + + switch (state) { + case S_IDLE: + INFO("Waiting for printer idle\n"); +#if 0 + if (rdbuf[0] != 0x01 || + rdbuf[1] != 0x02 || + rdbuf[2] != 0x01) { + break; + } +#endif + INFO("Printing started; Sending init sequence\n"); + state = S_STARTED; + + break; + case S_STARTED: +#if 0 + if (rdbuf[0] != 0x01 || + rdbuf[2] != 0x00) + break; + + /* Aappears to depend on media */ + if (rdbuf[1] != 0x0b && + rdbuf[1] != 0x03) + break; +#endif + + INFO("Sending image header\n"); + if ((ret = send_data(ctx->dev, ctx->endp_down, + (uint8_t*)&ctx->hdr, sizeof(ctx->hdr)))) + return ret; + pending = 1; + state = S_SENT_HDR; + break; + case S_SENT_HDR: + INFO("Waiting for printer to accept data\n"); +#if 0 + if (rdbuf[0] != 0x01 || + rdbuf[1] != 0x02 || + rdbuf[2] != 0x01) { + break; + } +#endif + INFO("Sending image data\n"); + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf, ctx->datalen))) + return ret; + + INFO("Image data sent\n"); + state = S_SENT_DATA; + break; + case S_SENT_DATA: + INFO("Waiting for printer to acknowledge completion\n"); +#if 0 + if (rdbuf[0] != 0x01 || + rdbuf[1] != 0x02 || + rdbuf[2] != 0x01) { + break; + } +#endif + state = S_FINISHED; + break; + default: + break; + }; + + if (state != S_FINISHED) + goto top; + + /* Clean up */ + if (terminate) + copies = 1; + + INFO("Print complete (%d remaining)\n", copies - 1); + + if (copies && --copies) { + state = S_IDLE; + goto top; + } + + return 0; +} + +/* Exported */ +struct dyesub_backend kodak605_backend = { + .name = "Kodak 605", + .version = "0.01", + .uri_prefix = "kodak605", + .init = kodak605_init, + .attach = kodak605_attach, + .teardown = kodak605_teardown, + .read_parse = kodak605_read_parse, + .main_loop = kodak605_main_loop, + .devices = { + { USB_VID_KODAK, USB_PID_KODAK_605, P_KODAK_605, "Kodak"}, + { 0, 0, 0, ""} + } +}; + +/* Kodak 605 data format + + Spool file consists of 14-byte header followed by plane-interleaved BGR data. + Native printer resolution is 1844 pixels per row, and 1240 or 2434 rows. + + Header: + + 01 40 0a 00 Fixed header + XX Unknown, usually 01 or 02 + CC Number of copies + 00 Always 0x00 + WW WW Number of columns, big endian. (Fixed at 1844) + HH HH Number of rows, big endian. (1240 or 2434) + DD 0x01 (4x6) 0x02 (8x6) + LL Laminate, 0x01 (off) or 0x02 (on) + 00 + + ************************************************************************ + + Kodak 605 Printer Comms: + + [[file header]] 01 40 0a 00 01 CC 00 WW WW HH HH MT LL 00 + +-> 01 00 00 00 +<- [76 bytes -- status ] +-> 01 00 00 00 +<- [76 bytes -- status ] + 01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00 + 00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 01 00 00 00 00 00 + + 01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00 + 00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 00 + 00 00 00 00 00 00 01 01 00 00 00 01 00 20 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 01 00 00 00 00 00 + +-> 02 00 00 00 +<- [113 bytes -- supported media?? ] +-> 01 40 0a 00 01 01 00 34 07 d8 04 01 02 00 [[ unmodified header ]] +<- 01 00 00 00 00 00 02 00 00 00 +-> image data! +-> image data! + +-> 01 00 00 00 +<- [76 bytes -- status ?? ] + + 01 00 00 00 00 00 01 00 42 00 31 00 00 00 31 00 + 00 00 14 00 00 00 77 00 00 00 31 00 00 00 5d 00 + 00 00 00 00 00 00 01 00 00 01 00 01 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 01 00 00 00 00 00 + + 01 00 00 00 00 00 01 00 42 00 31 00 00 00 31 00 + 00 00 14 00 00 00 77 00 00 00 31 00 00 00 5d 00 + 00 00 00 00 00 00 01 00 00 01 00 01 00 00 02 01 + 00 00 00 01 00 02 02 01 00 00 00 01 00 02 00 00 + 00 00 00 00 00 00 01 00 00 00 00 00 + +*/ diff --git a/icm/Kodak605/KODAK 605 Photo Printer.icm b/icm/Kodak605/KODAK 605 Photo Printer.icm new file mode 100644 index 0000000..7a4a124 --- /dev/null +++ b/icm/Kodak605/KODAK 605 Photo Printer.icm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d85cc8105a1f91fc72f603a5bef1b3f17df17437ca577eef2edfce6db9bb2a6 +size 770308