kodak605: Major strides on status decoding (and other stuff)

Major commonalities with Shinko S2145
This commit is contained in:
Solomon Peachy 2015-08-25 18:11:41 -04:00
parent 0a9811197f
commit 70ace070e8
1 changed files with 155 additions and 82 deletions

View File

@ -42,72 +42,109 @@
#define USB_VID_KODAK 0x040A
#define USB_PID_KODAK_605 0x402E
/* Command Header */
struct kodak605_cmd {
uint16_t cmd; /* LE */
uint16_t len; /* LE, not counting this header */
} __attribute__((packed));
struct kodak605_sts_hdr {
uint8_t result; /* RESULT_* */
uint8_t unk_1[5]; /* 00 00 00 00 00 */
uint8_t sts_1; /* 01/02 */
uint8_t sts_2; /* 00/61->6b ?? temperature? */
uint16_t length; /* LE, not counting this header */
} __attribute__((packed));
#define RESULT_SUCCESS 0x01
#define RESULT_FAIL 0x02
/* Media structure */
struct kodak605_medium {
uint8_t index;
uint16_t cols; /* LE */
uint16_t rows; /* LE */
uint8_t unk[5]; /* 01 00 00 00 00 */
uint8_t type; /* MEDIA_TYPE_* */
uint8_t unk[4]; /* 00 00 00 00 */
} __attribute__((packed));
#define MEDIA_TYPE_UNKNOWN 0x00
#define MEDIA_TYPE_PAPER 0x01
struct kodak605_media_list {
uint8_t unk[12]; /* 01 00 00 00 00 00 02 00 67 00 02 0b */
struct kodak605_sts_hdr hdr;
uint8_t unk; /* always seen 02 */
uint8_t type; /* KODAK_MEDIA_* */
uint8_t count;
struct kodak605_medium entries[];
} __attribute__((packed));
#define KODAK_MEDIA_6R 0x0b
#define KODAK_MEDIA_NONE 0x00
#define MAX_MEDIA_LEN 128
/* Status response */
struct kodak605_status {
uint8_t unk_1[6]; /* 01 00 00 00 00 00 */
uint8_t sts_1; /* 01 or 02 */
uint8_t sts_2; /* 00 or 62 */
uint8_t unk_2[2]; /* 42 00 */
uint32_t ctr_1; /* 30 00 00 00 -> incr by 1 ?? lifetime? */
uint32_t ctr_2; /* 30 00 00 00 -> incr by 1 ?? since maint? */
uint32_t ctr_3; /* 13 00 00 00 -> incr by 1 ?? media count? */
uint32_t ctr_4; /* 75 00 00 00 -> incr by 2 ?? cutter? */
uint32_t ctr_5; /* 30 00 00 00 -> incr by 1 ?? lifetime? */
uint8_t unk_3; /* 5d -> 5c -> 5b -- Donor % ?? */
struct kodak605_sts_hdr hdr;
/*@10*/ uint32_t ctr_life; /* Lifetime Prints */
uint32_t ctr_maint; /* Prints since last maintainence */
uint32_t ctr_media; /* Prints on current media */
uint32_t ctr_cut; /* Cutter Actuations */
uint32_t ctr_head; /* Prints on current head */
/*@30*/ uint8_t donor; /* Donor Percentage remaining */
/*@31*/ uint8_t null_1[7]; /* 00 00 00 00 00 00 00 */
/*@38*/ uint8_t sts_3; /* 00 or 01 or 02 */
uint8_t sts_4; /* 00 or 01 */
uint8_t unk_4; /* 00 */
uint8_t sts_5; /* 00 or 01 */
uint8_t unk_5; /* 00 */
uint8_t sts_6; /* 00 or 01 */
uint8_t unk_6; /* 00 */
/*@45*/ uint8_t sts_7; /* 00 or 02 or 12 */ // XXX theory; 00 is idle, 02 is buffer "full", 12 is "printing"
uint8_t sts_8; /* 00 or 01 or 02 */
uint8_t sts_9; /* 00 or 01 */
uint8_t unk_7[3]; /* 00 00 00 */
uint8_t sts_10; /* 00 or 01 */
uint8_t unk_8; /* 00 */
/*@53*/ uint8_t sts_11; /* 00 or 02 or 12, always matches @45 */
/*@54*/ uint8_t sts_12; /* 00 or 01 or 02 */
/*@55*/ uint8_t sts_13; /* 00 or 01 (remaining prints in job?) */
/*@56*/ uint8_t unk_9; /* 00 */
/*@57*/ uint8_t sts_14; /* 00 or 01 (completed prints in job?) */
/*@58*/ uint8_t unk_10; /* 00 */
/*@59*/ uint8_t sts_15; /* 00 or 01 (total prints in job?) */
/*@60*/ uint8_t null_2[10];/* 00 00 00 00 00 00 00 00 00 00*/
uint8_t unk_12[6]; /* 01 00 00 00 00 00 */
/*@38*/ uint8_t b1_id; /* 00/01/02 */
uint16_t b1_remain;
uint16_t b1_complete;
uint16_t b1_total;
/*@45*/ uint8_t b1_sts; /* See BANK_STATUS_* */
uint8_t b2_id; /* 00/01/02 */
uint16_t b2_remain;
uint16_t b2_complete;
uint16_t b2_total;
/*@53*/ uint8_t b2_sts; /* see BANK_STATUS_* */
/*@54*/ uint8_t id; /* current job id ( 00/01/02 seen ) */
/*@55*/ uint16_t remain; /* in current job */
/*@57*/ uint16_t complete; /* in current job */
/*@59*/ uint16_t total; /* in current job */
/*@61*/ uint8_t null_2[9]; /* 00 00 00 00 00 00 00 00 00 */
/*@70*/ uint8_t unk_12[6]; /* 01 00 00 00 00 00 */
} __attribute__((packed));
/* File header */
struct kodak605_hdr {
uint8_t hdr[4]; /* 01 40 0a 00 */
uint8_t unk1; /* 01 (file) or 02 (sometimes sent to printer) */
uint8_t copies; /* 01 or more */
uint8_t unk2; /* always 00 */
uint16_t columns; /* BE always 0x0734 */
uint16_t rows; /* BE */
uint8_t jobid; /* 01/02 seen */
uint16_t copies; /* LE, 0x0001 or more */
uint16_t columns; /* LE, always 0x0734 */
uint16_t rows; /* LE */
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 BANK_STATUS_FREE 0x00
#define BANK_STATUS_XFER 0x01
#define BANK_STATUS_FULL 0x02
#define BANK_STATUS_PRINTING 0x12
static char *bank_statuses(uint8_t v)
{
switch (v) {
case BANK_STATUS_FREE:
return "Free";
case BANK_STATUS_XFER:
return "Xfer";
case BANK_STATUS_FULL:
return "Full";
case BANK_STATUS_PRINTING:
return "Printing";
default:
return "Unknown";
}
}
#define CMDBUF_LEN 4
/* Private data stucture */
@ -116,6 +153,7 @@ struct kodak605_ctx {
uint8_t endp_up;
uint8_t endp_down;
int type;
uint8_t jobid;
struct kodak605_hdr hdr;
@ -148,9 +186,14 @@ static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_li
if (num < (int)sizeof(*media)) {
ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*media));
return 4;
return CUPS_BACKEND_FAILED;
}
if (media->hdr.result != RESULT_SUCCESS) {
ERROR("Unexpected response from media query (%x)!\n", media->hdr.result);
return CUPS_BACKEND_FAILED;
}
return 0;
}
@ -177,17 +220,18 @@ static void kodak605_attach(void *vctx, struct libusb_device_handle *dev,
struct libusb_device *device;
struct libusb_device_descriptor desc;
UNUSED(jobid);
ctx->dev = dev;
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 = lookup_printer_type(&kodak605_backend,
desc.idVendor, desc.idProduct);
desc.idVendor, desc.idProduct);
/* Make sure jobid is sane */
ctx->jobid = (jobid & 0x7f) + 1;
/* Query media info */
if (kodak605_get_media(ctx, ctx->media)) {
@ -289,11 +333,11 @@ static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status
return CUPS_BACKEND_FAILED;
}
if (sts->unk_1[0] != 0x01) {
ERROR("Unexpected response from status query!\n");
if (sts->hdr.result != RESULT_SUCCESS) {
ERROR("Unexpected response from status query (%x)!\n", sts->hdr.result);
return CUPS_BACKEND_FAILED;
}
return 0;
}
@ -308,10 +352,8 @@ static int kodak605_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_FAILED;
/* Printer handles generating copies.. */
if (copies > 255)
copies = 255;
if (ctx->hdr.copies < copies)
ctx->hdr.copies = copies;
if (le16_to_cpu(ctx->hdr.copies) < copies)
ctx->hdr.copies = cpu_to_le16(copies);
/* Validate against supported media list */
for (num = 0 ; num < ctx->media->count; num++) {
@ -323,20 +365,26 @@ static int kodak605_main_loop(void *vctx, int copies) {
ERROR("Print size unsupported by media!\n");
return CUPS_BACKEND_HOLD;
}
/* Use specified jobid */
ctx->hdr.jobid = ctx->jobid;
INFO("Waiting for printer idle\n");
while(1) {
if ((ret = kodak605_get_status(ctx, &sts)))
return CUPS_BACKEND_FAILED;
// XXX check status.. check for idle?
sleep(1);
break;
}
// XXX check for errors
if (ctx->hdr.media == 0x03)
ctx->hdr.unk1 = 0x02; /* XXX Seen in many sniffs... */
/* Wait for a free buffer */
if (sts.b1_sts == BANK_STATUS_FREE ||
sts.b2_sts == BANK_STATUS_FREE) {
break;
}
sleep(1);
}
{
INFO("Sending image header\n");
@ -344,37 +392,46 @@ static int kodak605_main_loop(void *vctx, int copies) {
(uint8_t*)&ctx->hdr, sizeof(ctx->hdr))))
return CUPS_BACKEND_FAILED;
uint8_t rdbuf[10];
struct kodak605_sts_hdr resp;
if ((ret = read_data(ctx->dev, ctx->endp_up,
rdbuf, sizeof(rdbuf), &num)))
(uint8_t*) &resp, sizeof(resp), &num)))
return CUPS_BACKEND_FAILED;
if (rdbuf[0] != 0x01 ||
rdbuf[6] != 0x02) { // XXX is this always the case?
ERROR("Printer not ready..\n");
if (resp.result != RESULT_SUCCESS) {
ERROR("Unexpected response from print command (%x)!\n", resp.result);
return CUPS_BACKEND_FAILED;
}
// XXX what about resp.sts1 or resp.sts2?
}
sleep(1);
INFO("Sending image data\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->databuf, ctx->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Image data sent\n");
sleep(1);
INFO("Waiting for printer to acknowledge completion\n");
while(1) {
do {
sleep(1);
if ((ret = kodak605_get_status(ctx, &sts)))
return CUPS_BACKEND_FAILED;
// XXX check status.. wait for idle?
// don't forget fast_return!
sleep(1);
break;
}
// XXX check for errors ?
/* Wait for completion */
if (sts.b1_id == ctx->jobid && sts.b1_complete == sts.b1_total)
break;
if (sts.b2_id == ctx->jobid && sts.b2_complete == sts.b2_total)
break;
if (fast_return) {
INFO("Fast return mode enabled.\n");
break;
}
} while(1);
INFO("Print complete\n");
return CUPS_BACKEND_OK;
@ -382,22 +439,38 @@ static int kodak605_main_loop(void *vctx, int copies) {
static void kodak605_dump_status(struct kodak605_status *sts)
{
uint8_t *rdbuf = (uint8_t *) sts;
int i;
DEBUG("raw status: ");
for (i = 0 ; i < (int)sizeof(*sts) ; i++) {
DEBUG2("%02x ", rdbuf[i]);
}
INFO("Bank 1: %s Job %03u @ %03u/%03u\n",
bank_statuses(sts->b1_sts), sts->b1_id,
le16_to_cpu(sts->b1_complete), le16_to_cpu(sts->b1_complete));
INFO("Bank 2: %s Job %03u @ %03u/%03u\n",
bank_statuses(sts->b2_sts), sts->b2_id,
le16_to_cpu(sts->b2_complete), le16_to_cpu(sts->b2_complete));
INFO("Lifetime prints : %d\n", be32_to_cpu(sts->ctr_life));
INFO("Cutter actuations : %d\n", be32_to_cpu(sts->ctr_cut));
INFO("Head prints : %d\n", be32_to_cpu(sts->ctr_head));
INFO("Media prints : %d\n", be32_to_cpu(sts->ctr_media));
INFO("Donor : %d%%\n", sts->donor);
}
static void kodak605_dump_mediainfo(struct kodak605_media_list *media)
{
int i;
if (media->type == KODAK_MEDIA_NONE) {
DEBUG("No Media Loaded\n");
return;
}
if (media->type == KODAK_MEDIA_6R) {
DEBUG("Media type: 6R (Kodak 197-4096 or equivalent)\n");
} else {
DEBUG("Media type %02x (unknown, please report!)\n", media->type);
}
DEBUG("Legal print sizes:\n");
for (i = 0 ; i < media->count ; i++) {
DEBUG("\t%d: %dx%d\n", i,
DEBUG("\t%d: %dx%d\n", i,
le16_to_cpu(media->entries[i].cols),
le16_to_cpu(media->entries[i].rows));
}
@ -527,7 +600,7 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend kodak605_backend = {
.name = "Kodak 605",
.version = "0.23",
.version = "0.24",
.uri_prefix = "kodak605",
.cmdline_usage = kodak605_cmdline,
.cmdline_arg = kodak605_cmdline_arg,