canonselphyneo: Add a new backend for the CP820/910/1000/1200 printers.
parent
2fb2f56623
commit
2ae41d59ff
|
@ -11,6 +11,7 @@ shinkos2145
|
|||
shinkos6145
|
||||
shinkos6245
|
||||
canonselphy
|
||||
canonselphyneo
|
||||
mitsu70x
|
||||
dnpds40
|
||||
citizencw01
|
||||
|
|
2
Makefile
2
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
|
||||
|
|
20
README
20
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.
|
||||
|
||||
CP820, CP910, CP1000, CP1200
|
||||
***************************************************************************
|
||||
BACKEND=canonselphyneo
|
||||
|
||||
Verified supported printers:
|
||||
|
||||
CP1200
|
||||
|
||||
Untested, but expected to work:
|
||||
|
||||
CP910
|
||||
|
||||
Unknown VID/PIDs, but should work:
|
||||
|
||||
CP820, CP1000
|
||||
|
||||
This backend does not support additional commands.
|
||||
|
||||
|
|
|
@ -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" ...??
|
||||
|
||||
*/
|
|
@ -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,
|
||||
|
|
|
@ -95,6 +95,7 @@ enum {
|
|||
P_CP790,
|
||||
P_CP_XXX,
|
||||
P_CP10,
|
||||
P_CP910,
|
||||
P_KODAK_6800,
|
||||
P_KODAK_6850,
|
||||
P_KODAK_1400_805,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue