Add full support for the mitsubishi P93D

This commit is contained in:
Solomon Peachy 2017-02-04 22:28:55 -05:00
parent 55d24dba50
commit cb15c704a1
2 changed files with 184 additions and 51 deletions

7
README
View file

@ -48,6 +48,7 @@
Mitsubishi CP-D80DW
Mitsubishi CP-K60DW-S
Mitsubishi P95DW
Mitsubishi P93DW
Work-in-progress Printers:
@ -63,7 +64,6 @@
Mitsubishi CP-9000DW, CP-9500DW, and CP-9600DW-S
Mitsubishi CP-9800DW, CP-9800DW-S, CP-9810DW, and CP-9820DW-S
Mitsubishi CP-D707DW
Mitsubishi P93D
Olmec OP900 and OP900II
Shinko CHC-S1245 (aka Sinfonia E1)
Shinko CHC-S6245 (aka Sinfonia CE1)
@ -674,10 +674,7 @@
Verified supported printers:
Mitsubishi P95DW
Work-in-progress printers:
Mitsubishi P93D
Mitsubishi P93DW
This backend does not support additional commands.

View file

@ -1,7 +1,7 @@
/*
* Mitsubishi P95D Monochrome Thermal Photo Printer CUPS backend
*
* (c) 2016 Solomon Peachy <pizza@shaftnet.org>
* (c) 2016-2017 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@ -53,6 +53,8 @@ struct mitsup95d_ctx {
uint8_t endp_up;
uint8_t endp_down;
int type;
uint8_t mem_clr[4]; // 1b 5a 43 00
int mem_clr_present;
@ -62,7 +64,8 @@ struct mitsup95d_ctx {
uint8_t hdr2[50]; // 1b 57 21 2e ...
uint8_t hdr3[50]; // 1b 57 22 2e ...
uint8_t hdr4[36]; // 1b 58 ...
uint8_t hdr4[42]; // 1b 58 ...
int hdr4_len; // 36 (P95) or 42 (P93)
uint8_t plane[12]; // 1b 5a 74 00 ...
uint8_t *databuf;
@ -100,6 +103,8 @@ static void mitsup95d_attach(void *vctx, struct libusb_device_handle *dev,
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
ctx->type = lookup_printer_type(&mitsup95d_backend,
desc.idVendor, desc.idProduct);
}
static void mitsup95d_teardown(void *vctx) {
@ -133,22 +138,18 @@ static int mitsup95d_read_parse(void *vctx, int data_fd) {
top:
i = read(data_fd, buf, sizeof(buf));
if (i == 0)
return CUPS_BACKEND_CANCEL;
if (i < 0)
return CUPS_BACKEND_CANCEL;
printf(">--> %02x %02x\n", buf[0], buf[1]);
if (buf[0] != 0x1b) {
ERROR("malformed data stream\n");
return CUPS_BACKEND_CANCEL;
}
switch (buf[1]) {
case 0x43: /* Memory Clear */
remain = 4;
ptr = ctx->mem_clr;
ctx->mem_clr_present = 1;
break;
case 0x50: /* Footer */
remain = 2;
ptr = ctx->ftr;
@ -162,10 +163,22 @@ top:
ptr = tmphdr;
break;
case 0x58: /* User Comment */
remain = 36;
if (ctx->type == P_MITSU_P93D)
ctx->hdr4_len = 42;
else
ctx->hdr4_len = 36;
remain = ctx->hdr4_len;
ptr = ctx->hdr4;
break;
case 0x5a: /* Plane header */
case 0x5a: /* Plane header OR printer reset */
// XXX read in next character.
// buf[2] is 0x43 for reset, 0x74 for plane.
// remain = 4;
// ptr = ctx->mem_clr;
// ctx->mem_clr_present = 1;
// break;
remain = 12;
ptr = ctx->plane;
break;
@ -251,13 +264,21 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
if (!ctx)
return CUPS_BACKEND_FAILED;
/* P93D is ... special. Windows switches to this halfway through
but it seems be okay to use it everywhere */
if (ctx->type == P_MITSU_P93D) {
querycmd[2] = 0x03;
}
/* Update printjob header to reflect number of requested copies */
if (ctx->hdr2[13] != 0xff)
ctx->hdr2[13] = copies;
/* XXX Update unknown header field to match sniffs */
if (ctx->hdr1[18] == 0x00)
ctx->hdr1[18] = 0x01;
if (ctx->type == P_MITSU_P95D) {
/* XXX Update unknown header field to match sniffs */
if (ctx->hdr1[18] == 0x00)
ctx->hdr1[18] = 0x01;
}
INFO("Waiting for printer idle\n");
@ -268,16 +289,29 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_FAILED;
ret = read_data(ctx->dev, ctx->endp_up,
queryresp, sizeof(queryresp), &num);
if (num != sizeof(queryresp) || ret < 0) {
if (ret < 0)
return CUPS_BACKEND_FAILED;
if (ctx->type == P_MITSU_P95D && num != 9) {
return CUPS_BACKEND_FAILED;
} else if (ctx->type == P_MITSU_P93D && num != 8) {
return CUPS_BACKEND_FAILED;
}
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
if (ctx->type == P_MITSU_P95D) {
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
}
if (queryresp[5] == 0x00)
break;
} else {
if (queryresp[6] == 0x45) {
ERROR("Printer error %02x\n", queryresp[7]);
return CUPS_BACKEND_STOP;
}
if (queryresp[6] == 0x30)
break;
}
if (queryresp[5] == 0x00)
break;
sleep(1);
} while (1);
@ -307,7 +341,7 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
ctx->hdr3, sizeof(ctx->hdr3))))
return CUPS_BACKEND_FAILED;
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->hdr4, sizeof(ctx->hdr4))))
ctx->hdr4, ctx->hdr4_len)))
return CUPS_BACKEND_FAILED;
/* Send plane header and image data */
@ -324,16 +358,38 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_FAILED;
ret = read_data(ctx->dev, ctx->endp_up,
queryresp, sizeof(queryresp), &num);
if (num != sizeof(queryresp) || ret < 0) {
if (ret < 0)
return CUPS_BACKEND_FAILED;
if (ctx->type == P_MITSU_P95D && num != 9) {
return CUPS_BACKEND_FAILED;
} else if (ctx->type == P_MITSU_P93D && num != 8) {
return CUPS_BACKEND_FAILED;
}
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
}
if (queryresp[5] != 0x00) {
ERROR("Printer not ready (%02x)!\n", queryresp[5]);
return CUPS_BACKEND_CANCEL;
if (ctx->type == P_MITSU_P95D) {
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
}
if (queryresp[5] != 0x00) {
ERROR("Printer not ready (%02x)!\n", queryresp[5]);
return CUPS_BACKEND_CANCEL;
}
} else {
if (queryresp[6] == 0x45) {
ERROR("Printer error %02x\n", queryresp[7]);
return CUPS_BACKEND_STOP;
}
if (queryresp[6] != 0x30) {
ERROR("Printer not ready (%02x)!\n", queryresp[6]);
return CUPS_BACKEND_CANCEL;
}
}
/* Send over Footer */
@ -353,21 +409,41 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_FAILED;
ret = read_data(ctx->dev, ctx->endp_up,
queryresp, sizeof(queryresp), &num);
if (num != sizeof(queryresp) || ret < 0) {
if (ret < 0)
return CUPS_BACKEND_FAILED;
if (ctx->type == P_MITSU_P95D && num != 9) {
return CUPS_BACKEND_FAILED;
} else if (ctx->type == P_MITSU_P93D && num != 8) {
return CUPS_BACKEND_FAILED;
}
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
}
if (queryresp[5] == 0 && queryresp[7] == 0)
break;
if (queryresp[7] > 0) {
if (fast_return) {
INFO("Fast return mode enabled.\n");
if (ctx->type == P_MITSU_P95D) {
if (queryresp[5] & 0x40) {
ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
return CUPS_BACKEND_STOP;
}
if (queryresp[5] == 0x00)
break;
if (queryresp[7] > 0) {
if (fast_return) {
INFO("Fast return mode enabled.\n");
break;
}
}
} else {
if (queryresp[6] == 0x45) {
ERROR("Printer error %02x\n", queryresp[7]);
return CUPS_BACKEND_STOP;
}
if (queryresp[6] == 0x30)
break;
if (queryresp[6] == 0x43 && queryresp[7] > 0) {
if (fast_return) {
INFO("Fast return mode enabled.\n");
break;
}
}
}
} while(1);
@ -398,7 +474,7 @@ static int mitsup95d_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend mitsup95d_backend = {
.name = "Mitsubishi P95D",
.version = "0.03",
.version = "0.04",
.uri_prefix = "mitsup95d",
.cmdline_arg = mitsup95d_cmdline_arg,
.init = mitsup95d_init,
@ -415,7 +491,7 @@ struct dyesub_backend mitsup95d_backend = {
/*****************************************************
Mitsubishi P95D Spool Format
Mitsubishi P93D/P95D Spool Format
...All fields are BIG ENDIAN.
@ -429,21 +505,30 @@ struct dyesub_backend mitsup95d_backend = {
PRINT_SETUP
1b 57 20 2e 00 0a 00 02 00 00 00 00 00 00 CC CC
1b 57 20 2e 00 0a 00 ZZ 00 00 00 00 00 00 CC CC
RR RR XX 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
XX == 01 seen in sniffs, 00 seen in dumps. Unknown!
XX == 01 seen in sniffs, 00 seen in dumps. Unknown purpose.
ZZ == 00 on P93D, 02 on P95D
CC CC = columns, RR RR = rows (print dimensions)
PRINT_OPTIONS
P95:
1b 57 21 2e 00 4a aa 00 20 TT 00 00 64 NN 00 MM
[[ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 ]] 00 00 00 02 00 00 00 00 00 00 00 00 00 00
00 XY
P93:
1b 57 21 2e 00 4a aa 00 00 TT 00 00 00 NN 00 MM
[[ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 ]] 00 00 00 02 00 00 00 00 00 00 00 00 00 00
00 XY
NN = copies
@ -455,19 +540,29 @@ struct dyesub_backend mitsup95d_backend = {
02 = Date
03 = DateTime
[[ .. ]] = actual comment (18 bytes), see below.
TT = media type
P95D:
00 = Standard
01 = High Density
02 = High Glossy
03 = High Glossy (K95HG)
X = media cut length
P93D:
00 = High Density
01 = High Glossy
02 = Standard
X = media cut length (P95D ONLY. P93 is 0)
4..8 (mm)
Y = flags
0x04 = Paper save
0x03 = Buzzer (3 = high, 2 = low, 0 = off)
GAMMA ????
GAMMA (P95)
1b 57 22 2e 00 15 TT 00 00 00 00 00 LL BB CC 00
[[ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@ -485,7 +580,20 @@ struct dyesub_backend mitsup95d_backend = {
01 = Yes
[[ .. ]] = Gamma table, loaded from LUT on disk. (skip first 16 bytes)
USER_COMMENT
GAMMA (P93)
1b 57 22 2e 00 d5 00 00 00 00 00 00 SS 00 LL 00
BB 00 CC 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
SS = Sharpening (0 = low, 1 = normal, 2 = high)
LL = Gamma table
00..04 Gamma table 1..5
BB = Brightness (signed 8-bit)
CC = Contrast (signed 8-bit)
USER_COMMENT (P95)
1b 58 [[ 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
@ -494,6 +602,15 @@ struct dyesub_backend mitsup95d_backend = {
[[ .. ]] = Actual comment. 34 bytes payload, 0x20 -> 0x7e
(Null terminated?)
USER_COMMENT (P93)
1b 58 [[ 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 ]]
[[ .. ]] = Actual comment. 40 bytes payload, 0x20 -> 0x7e
(Null terminated?)
IMAGE_DATA
1b 5a 74 00 00 00 YY YY CC CC RR RR
@ -511,7 +628,7 @@ struct dyesub_backend mitsup95d_backend = {
*********************************
Printer Comms:
P95D Printer Comms:
STATUS query
@ -530,13 +647,32 @@ struct dyesub_backend mitsup95d_backend = {
^
\--- 0x40 appears to be a flag that indicates error.
P93D Printer Comms:
STATUS query
-> 1b 72 0? 00
<- e4 72 0? 00 03 XX YY ZZ
? could be 0x00 or 0x03. Seen both.
Seen: 30 30 30
30 43 01 <- 1 copies remaining
30 43 00 <- 0 copies remaining
^^
\-- 30 == idle, 43 == printing
30 45 6f <- door open
30 45 50 <- no paper
45 == error?
****************************
UNKNOWNS:
* How multiple images are stacked for printing on a single page
(col offset too? write four, then tell PRINT?) Is this the mystery 0x01?
* How to adjust printer sharpness?
(col offset too? write four, then tell PRINT?)
* How to adjust P95D printer sharpness?
* Serial number query (iSerial appears bogus)
* What "custom gamma" table does to spool file?