canonselphy: Rewrite the error detection code.

Now instead of a dumb offset/flag, we parse the whole response from the
printer and holistically figure out what's wrong.  On a per-printer type
basis.

This was needed because the ES40 and CP790 share a single "backend" but
have radically different error reporting.
This commit is contained in:
Solomon Peachy 2014-01-29 10:22:20 -05:00
parent 0eef76d2b3
commit 3764319eb2
1 changed files with 149 additions and 26 deletions

View File

@ -53,9 +53,131 @@ struct printer_data {
int16_t paper_codes[256];
int16_t pgcode_offset; /* Offset into printjob for paper type */
int16_t paper_code_offset; /* Offset in readback for paper type */
int16_t error_offset;
int (*error_detect)(uint8_t *rdbuf);
};
static int es1_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[1])
return 0;
if (rdbuf[9] == 0x80)
ERROR("No media loaded!\n");
else if (rdbuf[9] == 0x00)
ERROR("Cover open!\n");
else
ERROR("Unknown error - %02x\n",
rdbuf[9]);
return 1;
}
static int es2_error_detect(uint8_t *rdbuf)
{
if (rdbuf[0] == 0x16 &&
rdbuf[1] == 0x01) {
ERROR("Cover open!\n");
return 1;
}
if (rdbuf[0] == 0x02 &&
rdbuf[4] == 0x05 &&
rdbuf[5] == 0x05 &&
rdbuf[6] == 0x02) {
ERROR("No media loaded!\n");
return 1;
}
return 0;
}
static int es3_error_detect(uint8_t *rdbuf)
{
if (rdbuf[8] == 0x01) {
if (rdbuf[10] == 0x0f) {
ERROR("Communications Error\n");
} else if (rdbuf[10] == 0x01) {
ERROR("No media/ribbon loaded!\n");
} else {
ERROR("Unknown error - %02x + %02x\n",
rdbuf[8], rdbuf[10]);
}
return 1;
} else if (rdbuf[8] == 0x03 &&
rdbuf[10] == 0x02) {
ERROR("No media!\n");
return 1;
} else if (rdbuf[8] == 0x08 &&
rdbuf[10] == 0x04) {
ERROR("Cover open!\n");
return 1;
}
if (rdbuf[8] || rdbuf[10]) {
ERROR("Unknown error - %02x + %02x\n",
rdbuf[8], rdbuf[10]);
}
return 0;
}
static int es40_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[4] && !rdbuf[5]) {
/* ES40 */
if (!rdbuf[3])
return 0;
if (rdbuf[3] == 0x01)
ERROR("Generic communication error\n");
else if (rdbuf[3] == 0x32)
ERROR("Cover open or media empty!\n");
else
ERROR("Unknown error - %02x\n", rdbuf[3]);
return 1;
}
/* CP790 */
if (rdbuf[4] == 0x10 && rdbuf[5] == 0xff) {
ERROR("No ribbon!\n");
return 1;
} else if (rdbuf[4] == 0xff && rdbuf[5] == 0x01) {
ERROR("No media loaded!\n");
return 1;
}
return 0;
}
static int cp10_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[2])
return 0;
if (rdbuf[2] == 0x80)
ERROR("No ribbon\n");
else if (rdbuf[2] == 0x01)
ERROR("No media!\n");
else
ERROR("Unknown error - %02x\n", rdbuf[2]);
return 1;
}
static int cpxxx_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[2])
return 0;
if (rdbuf[2] == 0x01)
ERROR("Out of paper!\n");
else if (rdbuf[2] == 0x04)
ERROR("Ribbon problem!\n");
else if (rdbuf[2] == 0x08)
ERROR("Ribbon depleted!\n");
else
ERROR("Unknown error - %02x\n", rdbuf[2]);
return 1;
}
static struct printer_data selphy_printers[] = {
{ .type = P_ES1,
.model = "SELPHY ES1",
@ -70,7 +192,7 @@ static struct printer_data selphy_printers[] = {
// .paper_codes
.pgcode_offset = 3,
.paper_code_offset = 6,
.error_offset = 1,
.error_detect = es1_error_detect,
},
{ .type = P_ES2_20,
.model = "SELPHY ES2/ES20",
@ -85,7 +207,7 @@ static struct printer_data selphy_printers[] = {
// .paper_codes
.pgcode_offset = 2,
.paper_code_offset = 4,
.error_offset = 1, // XXX insufficient
.error_detect = es2_error_detect,
},
{ .type = P_ES3_30,
.model = "SELPHY ES3/ES30",
@ -100,7 +222,7 @@ static struct printer_data selphy_printers[] = {
// .paper_codes
.pgcode_offset = 2,
.paper_code_offset = -1,
.error_offset = 8, // or 10
.error_detect = es3_error_detect,
},
{ .type = P_ES40_CP790,
.model = "SELPHY ES40/CP790",
@ -115,7 +237,7 @@ static struct printer_data selphy_printers[] = {
// .paper_codes
.pgcode_offset = 2,
.paper_code_offset = 11,
.error_offset = 3,
.error_detect = es40_error_detect,
},
{ .type = P_CP_XXX,
.model = "SELPHY CP Series (!CP-10/CP790)",
@ -130,7 +252,7 @@ static struct printer_data selphy_printers[] = {
// .paper_codes
.pgcode_offset = 3,
.paper_code_offset = 6,
.error_offset = 2,
.error_detect = cpxxx_error_detect,
},
{ .type = P_CP10,
.model = "SELPHY CP-10",
@ -145,7 +267,7 @@ static struct printer_data selphy_printers[] = {
// .clear_error
.pgcode_offset = -1,
.paper_code_offset = -1,
.error_offset = 2,
.error_detect = cp10_error_detect,
},
{ .type = -1 },
};
@ -215,17 +337,12 @@ enum {
S_FINISHED,
};
static int fancy_memcmp(const uint8_t *buf_a, const int16_t *buf_b, uint len, int16_t papercode_offset, int16_t papercode_val)
static int fancy_memcmp(const uint8_t *buf_a, const int16_t *buf_b, uint len)
{
uint i;
for (i = 0 ; i < len ; i++) {
if (papercode_offset != -1 && i == (uint) papercode_offset) {
if (papercode_val == -1)
continue;
else if ((buf_a[i] & 0xf) != (papercode_val & 0xf))
return INCORRECT_PAPER;
} else if (buf_b[i] == -1)
if (buf_b[i] == -1)
continue;
else if (buf_a[i] > buf_b[i])
return 1;
@ -530,18 +647,25 @@ top:
fflush(stderr);
/* Error detection */
if (ctx->printer->error_offset != -1 &&
rdbuf[ctx->printer->error_offset]) {
ERROR("Printer reported error condition %02x; aborting. (Out of ribbon/paper?)\n", rdbuf[ctx->printer->error_offset]);
if (ctx->printer->error_detect(rdbuf))
return 4;
}
switch(state) {
case S_IDLE:
INFO("Waiting for printer idle\n");
if (!fancy_memcmp(rdbuf, ctx->printer->init_readback, READBACK_LEN, ctx->printer->paper_code_offset, ctx->paper_code)) {
state = S_PRINTER_READY;
if (fancy_memcmp(rdbuf, ctx->printer->init_readback, READBACK_LEN))
break;
/* Make sure paper is correct */
if (ctx->printer->paper_code_offset != -1) {
if ((rdbuf[ctx->printer->paper_code_offset] & 0x0f) !=
(ctx->paper_code & 0x0f)) {
ERROR("Incorrect paper loaded, aborting job!\n");
return 3; /* Hold this job, don't stop queue */
}
}
state = S_PRINTER_READY;
break;
case S_PRINTER_READY:
INFO("Printing started; Sending init sequence\n");
@ -552,7 +676,7 @@ top:
state = S_PRINTER_INIT_SENT;
break;
case S_PRINTER_INIT_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->ready_y_readback, READBACK_LEN, ctx->printer->paper_code_offset, ctx->paper_code)) {
if (!fancy_memcmp(rdbuf, ctx->printer->ready_y_readback, READBACK_LEN)) {
state = S_PRINTER_READY_Y;
}
break;
@ -568,7 +692,7 @@ top:
state = S_PRINTER_Y_SENT;
break;
case S_PRINTER_Y_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->ready_m_readback, READBACK_LEN, ctx->printer->paper_code_offset, ctx->paper_code)) {
if (!fancy_memcmp(rdbuf, ctx->printer->ready_m_readback, READBACK_LEN)) {
if (ctx->bw_mode)
state = S_PRINTER_DONE;
else
@ -584,7 +708,7 @@ top:
state = S_PRINTER_M_SENT;
break;
case S_PRINTER_M_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->ready_c_readback, READBACK_LEN, ctx->printer->paper_code_offset, ctx->paper_code)) {
if (!fancy_memcmp(rdbuf, ctx->printer->ready_c_readback, READBACK_LEN)) {
state = S_PRINTER_READY_C;
}
break;
@ -597,7 +721,7 @@ top:
state = S_PRINTER_C_SENT;
break;
case S_PRINTER_C_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->done_c_readback, READBACK_LEN, ctx->printer->paper_code_offset, ctx->paper_code)) {
if (!fancy_memcmp(rdbuf, ctx->printer->done_c_readback, READBACK_LEN)) {
state = S_PRINTER_DONE;
}
break;
@ -666,7 +790,7 @@ top:
struct dyesub_backend canonselphy_backend = {
.name = "Canon SELPHY CP/ES",
.version = "0.68",
.version = "0.69",
.multipage_capable = 1,
.uri_prefix = "canonselphy",
.init = canonselphy_init,
@ -834,7 +958,6 @@ struct dyesub_backend canonselphy_backend = {
00 ff 10 00 ff ff ff ff 00 00 00 00 [ready for footer]
01 ff 10 00 ff ff ff ff 01 00 0f 00 [communication error]
00 ff 00 00 ff ff ff ff 00 00 00 00 [cover open, no media]
00 ff 01 00 ff ff ff ff 01 00 01 00 [error, no media/ink]
00 ff 01 00 ff ff ff ff 03 00 02 00 [attempt to print with no media]
00 ff 01 00 ff ff ff ff 08 00 04 00 [attempt to print with cover open]