summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2016-12-02 23:49:22 -0500
committerSolomon Peachy <pizza@shaftnet.org>2016-12-02 23:49:22 -0500
commit1a1889b1696e9bc36565a7da1c7614be585176aa (patch)
treeb1668e5f7a4de14bf9e430a6aa07a64cdb1c886f
parent1cee0d5cfedbdefe3f06ddc5a09bc734e5289c39 (diff)
downloadselphy_print-1a1889b1696e9bc36565a7da1c7614be585176aa.tar.gz
selphy_print-1a1889b1696e9bc36565a7da1c7614be585176aa.tar.bz2
selphy_print-1a1889b1696e9bc36565a7da1c7614be585176aa.zip
canonselphyneo: Add a new backend for the CP820/910/1000/1200 printers.
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--README20
-rw-r--r--backend_canonselphyneo.c440
-rw-r--r--backend_common.c2
-rw-r--r--backend_common.h1
-rw-r--r--blacklist6
-rw-r--r--testjobs/canon_cp1200-p.rawbin0 -> 7008800 bytes
8 files changed, 468 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index ac1507a..ae7736b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ shinkos2145
shinkos6145
shinkos6245
canonselphy
+canonselphyneo
mitsu70x
dnpds40
citizencw01
diff --git a/Makefile b/Makefile
index 75f02c3..ff38323 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ CPPFLAGS += -DURI_PREFIX=\"$(BACKEND_NAME)\"
CFLAGS += -funit-at-a-time
# List of backends
-BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 citizencw01 mitsu9550 shinkos6245 shinkos6145
+BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 citizencw01 mitsu9550 shinkos6245 shinkos6145 canonselphyneo
# For the s6145 and mitsu70x backends
CPPFLAGS += -DUSE_DLOPEN
diff --git a/README b/README
index bfb2d5e..942e647 100644
--- a/README
+++ b/README
@@ -23,7 +23,7 @@
Supported Printers:
Canon SELPHY ES series
- Canon SELPHY CP series (except CP820, CP910, CP1000, CP1200)
+ Canon SELPHY CP series
Kodak Professional 1400
Kodak 305 Photo Printer
Kodak 605 Photo Printer
@@ -54,6 +54,7 @@
Mitsubishi CP-D707DW
Mitsubishi CP-9000DW, CP-9500DW, and CP-9600DW-S
Mitsubishi CP-9800DW, CP-9800DW-S, CP-9810DW, and CP-9820DW-S
+ Canon SELPHY CP820 and CP1000
Fujifilm ASK-300
Citizen CW-02 and CX2
Olmec OP900 and OP900II
@@ -212,9 +213,22 @@
ES20, CP-220, CP520, CP530, CP600, CP810
- NOT supported: (Printer does not need any special backend)
+ This backend does not support additional commands.
+
+ ***************************************************************************
+ BACKEND=canonselphyneo
+
+ Verified supported printers:
+
+ CP1200
+
+ Untested, but expected to work:
+
+ CP910
+
+ Unknown VID/PIDs, but should work:
- CP820, CP910, CP1000, CP1200
+ CP820, CP1000
This backend does not support additional commands.
diff --git a/backend_canonselphyneo.c b/backend_canonselphyneo.c
new file mode 100644
index 0000000..47411bc
--- /dev/null
+++ b/backend_canonselphyneo.c
@@ -0,0 +1,440 @@
+/*
+ * Canon SELPHY CPneo series CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2016 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#define BACKEND canonselphyneo_backend
+
+#include "backend_common.h"
+
+/* Exported */
+#define USB_VID_CANON 0x04a9
+#define USB_PID_CANON_CP820 XXX
+#define USB_PID_CANON_CP910 0x327a
+#define USB_PID_CANON_CP1000 XXX
+#define USB_PID_CANON_CP1200 0x32b1
+
+/* Header data structure */
+struct selphyneo_hdr {
+ uint8_t data[32];
+} __attribute((packed));
+
+/* Readback data structure */
+struct selphyneo_readback {
+ uint8_t data[12];
+} __attribute((packed));
+
+/* Private data stucture */
+struct selphyneo_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ uint8_t *databuf;
+ uint32_t datalen;
+};
+
+static char *selphyneo_statuses(uint8_t sts)
+{
+ switch(sts) {
+ case 0x01:
+ return "Idle";
+ case 0x02:
+ return "Feeding Paper";
+ case 0x04:
+ return "Printing YELLOW";
+ case 0x08:
+ return "Printing MAGENTA";
+ case 0x10:
+ return "Printing CYAN";
+ case 0x20:
+ return "Printing LAMINATE";
+ default:
+ return "Unknown state!";
+ }
+}
+
+static char *selphyneo_errors(uint8_t err)
+{
+ switch(err) {
+ case 0x00:
+ return "None";
+ case 0x02:
+ return "Paper Feed";
+ case 0x03:
+ return "No Paper";
+ case 0x07:
+ return "No Ink";
+ case 0x0A:
+ return "Incorrect media for job";
+ default:
+ return "Unknown Error";
+ }
+}
+
+static void *selphyneo_init(void)
+{
+ struct selphyneo_ctx *ctx = malloc(sizeof(struct selphyneo_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct selphyneo_ctx));
+
+ return ctx;
+}
+
+extern struct dyesub_backend selphyneo_backend;
+
+static void selphyneo_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct selphyneo_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+}
+
+static void selphyneo_teardown(void *vctx) {
+ struct selphyneo_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+
+ free(ctx);
+}
+
+static int selphyneo_read_parse(void *vctx, int data_fd)
+{
+ struct selphyneo_ctx *ctx = vctx;
+ struct selphyneo_hdr hdr;
+ int i, remain;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ /* Read the header.. */
+ i = read(data_fd, &hdr, sizeof(hdr));
+ if (i != sizeof(hdr)) {
+ if (i == 0)
+ return CUPS_BACKEND_CANCEL;
+ ERROR("Read failed (%d/%d)\n",
+ i, (int)sizeof(hdr));
+ perror("ERROR: Read failed");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ /* Determine job length */
+ switch(hdr.data[18]) {
+ case 0x50:
+ remain = 1872 * 1248 * 3;
+ break;
+ case 0x4c:
+ remain = 1536 * 1104 * 3;
+ break;
+ case 0x43:
+ remain = 1088 * 668 * 3;
+ break;
+ default:
+ ERROR("Unknown print size! (%02x/%02x/%02x/%02x)\n",
+ hdr.data[10], hdr.data[24], hdr.data[28], hdr.data[29]);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Allocate a buffer */
+ ctx->datalen = 0;
+ ctx->databuf = malloc(remain + sizeof(hdr));
+ if (!ctx->databuf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ /* Store the read-in header */
+ memcpy(ctx->databuf, &hdr, sizeof(hdr));
+ ctx->datalen += sizeof(hdr);
+
+ /* Read in data */
+ while (remain > 0) {
+ i = read(data_fd, ctx->databuf + ctx->datalen, remain);
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ remain -= i;
+ ctx->datalen += i;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int selphyneo_main_loop(void *vctx, int copies) {
+ struct selphyneo_ctx *ctx = vctx;
+ struct selphyneo_readback rdback;
+
+ int ret, num;
+
+ /* Read in the printer status to clear last state */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+
+top:
+ INFO("Waiting for printer idle\n");
+
+ do {
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (rdback.data[0] == 0x01)
+ break;
+
+ INFO("Printer state: %s\n", selphyneo_statuses(rdback.data[0]));
+
+ switch (rdback.data[2]) {
+ case 0x00:
+ break;
+ case 0x0A:
+ ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
+ return CUPS_BACKEND_CANCEL;
+ default:
+ ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
+ return CUPS_BACKEND_STOP;
+ }
+
+ sleep(1);
+ } while(1);
+
+ // XXX dump over markers
+#if 0
+ ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
+ ATTR("marker-high-levels=100\n");
+ ATTR("marker-low-levels=10\n");
+ ATTR("marker-names='%s'\n", ctx->printer->pgcode_names? ctx->printer->pgcode_names(rdbuf[ctx->printer->paper_code_offset]) : "Unknown");
+ ATTR("marker-types=ribbonWax\n");
+ ATTR("marker-levels=%d\n", -3); /* ie Unknown but OK */
+#endif
+
+ INFO("Sending spool data\n");
+ /* Send the data over in 256K chunks */
+ {
+ int chunk = 256*1024;
+ int sent = 0;
+ while (chunk > 0) {
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ctx->databuf + sent, chunk)))
+ return CUPS_BACKEND_FAILED;
+ sent += chunk;
+ chunk = ctx->datalen - sent;
+ if (chunk > 256*1024)
+ chunk = 256*1024;
+ }
+ }
+
+ /* Read in the printer status to clear last state */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ INFO("Waiting for printer acknowledgement\n");
+ do {
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (rdback.data[0] == 0x01)
+ break;
+
+ INFO("Printer state: %s\n", selphyneo_statuses(rdback.data[0]));
+
+ switch (rdback.data[2]) {
+ case 0x00:
+ break;
+ case 0x0A:
+ ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
+ return CUPS_BACKEND_CANCEL;
+ default:
+ ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
+ return CUPS_BACKEND_STOP;
+ }
+
+ if (rdback.data[0] > 0x02 && fast_return) {
+ INFO("Fast return mode enabled.\n");
+ break;
+ }
+
+ sleep(1);
+ } while(1);
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int selphyneo_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct selphyneo_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL)) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+struct dyesub_backend canonselphyneo_backend = {
+ .name = "Canon SELPHY CPneo",
+ .version = "0.01wip",
+ .uri_prefix = "canonselphyneo",
+ .cmdline_arg = selphyneo_cmdline_arg,
+ .init = selphyneo_init,
+ .attach = selphyneo_attach,
+ .teardown = selphyneo_teardown,
+ .read_parse = selphyneo_read_parse,
+ .main_loop = selphyneo_main_loop,
+ .devices = {
+// { USB_VID_CANON, USB_PID_CANON_CP820, P_CP910, ""},
+ { USB_VID_CANON, USB_PID_CANON_CP910, P_CP910, ""},
+// { USB_VID_CANON, USB_PID_CANON_CP1000, P_CP910, ""},
+ { USB_VID_CANON, USB_PID_CANON_CP1200, P_CP910, ""},
+ { 0, 0, 0, ""}
+ }
+};
+/*
+
+ ***************************************************************************
+
+ Stream formats and readback codes for supported printers
+
+ ***************************************************************************
+ Selphy CP820/CP910/CP1000/CP1200:
+
+ Radically different spool file format! 300dpi, same print sizes, but also
+ adding a 50x50mm sticker and 22x17.3mm ministickers, though I think the
+ driver treats all of those as 'C' sizes for printing purposes.
+
+ 32-byte header:
+
+ 0f 00 00 40 00 00 00 00 00 00 00 00 00 00 01 00
+ 01 00 ?? 00 00 00 00 00 XX 04 00 00 WW ZZ 00 00
+
+ ?? == 50 (P)
+ == 4c (L)
+ == 43 (C)
+
+ XX == e0 (P)
+ 80 (L)
+ 40 (C)
+
+ WW == 50 (P)
+ c0 (L)
+ 9c (C)
+
+ ZZ == 07 (P)
+ 05 (L)
+ 02 (C)
+
+ P == 7008800 == 2336256 * 3 + 32 (1872*1248)
+ L == 5087264 == 1695744 * 3 + 32 (1536*1104)
+ C == 2180384 == 726784 * 3 + 32 (1088*668)
+
+ It is worth mentioning that the image payload is Y'CbCr rather than the
+ traditional YMC (or even BGR) of other dyseubs. Our best guess is that
+ we need to use the JPEG coefficients, although we realistically have
+ no way of confirming this.
+
+ It is hoped that the printers do support YMC data, but as of yet we
+ have no way of determining if this is possible.
+
+ Data Readback:
+
+ XX 00 YY 00 00 00 ZZ 00 00 00 00 00
+
+ XX == Status
+
+ 01 Idle
+ 02 Feeding Paper
+ 04 Printing Y
+ 08 Printing M
+ 10 Printing C
+ 20 Printing L
+
+ YY == Error
+
+ 00 None
+ 02 No Paper (?)
+ 03 No Paper
+ 07 No Ink
+ 0A Media/Job mismatch
+
+ ZZ == Media?
+
+ 01
+ 10
+ 11
+
+Also, the first time a readback happens after plugging in the printer:
+
+34 44 35 31 01 00 01 00 01 00 45 00 "4D51" ...??
+
+*/
diff --git a/backend_common.c b/backend_common.c
index 59fc0b6..c1ec2e7 100644
--- a/backend_common.c
+++ b/backend_common.c
@@ -562,6 +562,7 @@ extern struct dyesub_backend shinkos2145_backend;
extern struct dyesub_backend shinkos6145_backend;
extern struct dyesub_backend shinkos6245_backend;
extern struct dyesub_backend canonselphy_backend;
+extern struct dyesub_backend canonselphyneo_backend;
extern struct dyesub_backend mitsu70x_backend;
extern struct dyesub_backend mitsu9550_backend;
extern struct dyesub_backend dnpds40_backend;
@@ -569,6 +570,7 @@ extern struct dyesub_backend cw01_backend;
static struct dyesub_backend *backends[] = {
&canonselphy_backend,
+ &canonselphyneo_backend,
&kodak6800_backend,
&kodak605_backend,
&kodak1400_backend,
diff --git a/backend_common.h b/backend_common.h
index 3ff6581..15c6ff7 100644
--- a/backend_common.h
+++ b/backend_common.h
@@ -95,6 +95,7 @@ enum {
P_CP790,
P_CP_XXX,
P_CP10,
+ P_CP910,
P_KODAK_6800,
P_KODAK_6850,
P_KODAK_1400_805,
diff --git a/blacklist b/blacklist
index 5a8697a..a8c0380 100644
--- a/blacklist
+++ b/blacklist
@@ -78,6 +78,12 @@
# Canon SELPHY CP900
0x04a9 0x3255 blacklist
+# Canon SELPHY CP910
+0x04a9 0x327a blacklist
+
+# Canon SELPHY CP1200
+0x04a9 0x32b1 blacklist
+
# Canon SELPHY ES1
0x04a9 0x3141 blacklist
diff --git a/testjobs/canon_cp1200-p.raw b/testjobs/canon_cp1200-p.raw
new file mode 100644
index 0000000..f6fad37
--- /dev/null
+++ b/testjobs/canon_cp1200-p.raw
Binary files differ