From 711d544561a1448734f836f79458516a4f98ba44 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 4 Aug 2021 20:20:31 -0400 Subject: [PATCH] kodak8800: Major improvements! Can now print successfully! * Job query, canceling * Printer status for idle/completion detection * Many fixes * Head temperature Todo: * Report printer status in human readable * Better job queries * Decode sensor data & report (know how to report temperature) * 8x12 media handling/reporting --- README | 1 + backend_kodak8800.c | 348 +++++++++++++++++++---------------- testjobs/kodak_8800_8x10.raw | 2 +- 3 files changed, 195 insertions(+), 156 deletions(-) diff --git a/README b/README index e7aa8bb..19cbde4 100644 --- a/README +++ b/README @@ -609,6 +609,7 @@ -i Query printer info -m Query media info -n Query counters + -X id Cancel job (0 for all/current) *************************************************************************** BACKEND=shinkos2145 diff --git a/backend_kodak8800.c b/backend_kodak8800.c index a2a35d7..464c3d2 100644 --- a/backend_kodak8800.c +++ b/backend_kodak8800.c @@ -37,16 +37,49 @@ struct rtp1_req { uint8_t payload[]; }; +struct rtp1_sts { + uint8_t base[2]; // x10 x10 or x10 x12 ? (10 == ok, 12 == error?) + uint16_t err; /* RTP_ERROR_* */ + uint8_t sts[4]; // [0] STATE_* [2] PRINT_* +}; + struct rtp1_resp { uint8_t hdr[4]; /* "RTP1" */ uint8_t cmd[4]; - uint8_t sts1[2]; - uint8_t sts2[3]; - uint8_t zero[3]; + struct rtp1_sts sts; uint32_t payload_len; /* BE */ uint8_t payload[]; }; +#define STS_OK 0x10 +#define STS_ERR 0x12 +#define STS_ERR2 0x13 // Not sure what's different + +#define STATE_IDLE 0x00 +#define STATE_UNK 0x01 // XXX +#define STATE_PRINT 0x02 + +#define PRINT_IDLE 0x00 +#define PRINT_FEED 0x01 +#define PRINT_Y 0x02 +#define PRINT_M 0x03 +#define PRINT_C 0x04 +#define PRINT_O 0x05 +#define PRINT_EJECT 0x06 + +#define RTP_ERROR_UKNOWN_0105 0x0105 // seen after issuing START command +#define RTP_ERROR_JOB_NOT_OPEN 0x0203 +#define RTP_ERROR_COMMAND_DISABLED 0x0307 +#define RTP_ERROR_RIBBON_TOO_SHORT 0x0420 +#define RTP_ERROR_OPERATING_SYS 0x0503 +#define RTP_ERROR_DOOR_OPEN 0x0504 +#define RTP_ERROR_RIBBON_CHECK 0x2001 +#define RTP_ERROR_PAPER_CHECK 0x2004 +#define RTP_ERROR_ENGINE_PROTOCOL 0x4302 +#define RTP_ERROR_BARCODE_SENSE 0x430A +#define RTP_ERROR_HOST_READ 0xFF02 +#define RTP_ERROR_UNKNOWN_FF04 0xFF04 // seen when issuing CANCELJOB + struct rtp1_counters { uint32_t cutter_count; uint32_t prints_finished; @@ -64,17 +97,6 @@ struct rtp1_errorrecord { uint32_t papernum; }; -#define RTP_ERROR_JOB_NOT_OPEN 0x0203 -#define RTP_ERROR_COMMAND_DISABLED 0x0307 -#define RTP_ERROR_RIBBON_TOO_SHORT 0x0420 -#define RTP_ERROR_OPERATING_SYS 0x0503 -#define RTP_ERROR_DOOR_OPEN 0x0504 -#define RTP_ERROR_RIBBON_CHECK 0x2001 -#define RTP_ERROR_PAPER_CHECK 0x2004 -#define RTP_ERROR_ENGINE_PROTOCOL 0x4302 -#define RTP_ERROR_BARCODE_SENSE 0x430A -#define RTP_ERROR_HOST_READ 0xFF02 - struct rtp1_errorlog { struct rtp1_errorrecord row[32]; }; @@ -119,32 +141,36 @@ struct rtp1_fwvers { uint8_t reset[12]; }; +struct rtp1_sensors { + uint8_t unk[6]; + // -> 02 00 06 2a ff 00 + // -> 02 00 06 2a ff 00 + // -> 10 00 02 2a ff 00 + uint8_t head_temp; + uint8_t head_temp_target; +}; + const uint8_t rtp_sendimagedata[4] = { 0x00, 0x00, 0x00, 0x00 }; /* Resp len 0 */ const uint8_t rtp_getmaxxfer[4] = { 0x01, 0x00, 0x00, 0x00 }; /* Resp len 4 (u32) */ -const uint8_t rtp_printfooter[4] = { 0x11, 0x00, 0x00, 0x00 }; /* Resp len 0 */ -const uint8_t rtp_getserial[4] = { 0x81, 0x01, 0x00, 0x00 }; /* Resp len 64 (rtp1_serial) */ -const uint8_t rtp_getserialhead[4] = { 0x81, 0x01, 0x01, 0x00 }; /* Resp len 64 (rtp1_serial) */ -const uint8_t rtp_getmfgmodel[4] = { 0x13, 0x00, 0x00, 0x00 }; /* Resp len 256 (rtp1_mfgmodel) */ -const uint8_t rtp_getcounters[4] = { 0x81, 0x04, 0x00, 0x00 }; /* Resp len 20 (rtp1_counters) */ +const uint8_t rtp_getstatus[4] = { 0x06, 0x00, 0x00, 0x00 }; /* Resp len 0 */ +const uint8_t rtp_getjobstatus[4] = { 0x06, 0x03, 0x00, 0x00 }; /* Req len 4, resp 14 XXX */ +const uint8_t rtp_getjobqstatus[4] = { 0x06, 0x05, 0x00, 0x00 }; /* Req len 4, resp 14 XXX */ const uint8_t rtp_getmedia[4] = { 0x06, 0x40, 0x00, 0x00 }; /* Resp len 16 (rtp1_mediastatus) */ +const uint8_t rtp_getsensors[4] = { 0x06, 0x80, 0x00, 0x00 }; /* Resp len 8 (rtp1_sensors */ const uint8_t rtp_getusererrors[4] = { 0x0c, 0x01, 0x00, 0x00 }; /* Resp len 512 (rtp1_errorlog) */ const uint8_t rtp_getserverrors[4] = { 0x0c, 0x02, 0x00, 0x00 }; /* Resp len 512 (rtp1_errorlog) */ const uint8_t rtp_getifaceerrors[4] = { 0x0c, 0x03, 0x00, 0x00 }; /* Resp len 512 (rtp1_errorlog) */ +const uint8_t rtp_openjob[4] = { 0x10, 0x00, 0x00, 0x00 }; /* Resp len 4 (u32) */ +const uint8_t rtp_closejob[4] = { 0x11, 0x00, 0x00, 0x00 }; /* Resp len 0 */ +const uint8_t rtp_canceljob[4] = { 0x12, 0x00, 0x00, 0x00 }; /* Resp len 0 */ +const uint8_t rtp_canceljobid[4] = { 0x12, 0x01, 0x00, 0x00 }; /* Req len 4, Resp len 0 */ +const uint8_t rtp_getmfgmodel[4] = { 0x13, 0x00, 0x00, 0x00 }; /* Resp len 256 (rtp1_mfgmodel) */ const uint8_t rtp_getfwversions[4] = { 0x13, 0x80, 0x00, 0x00 }; /* Resp len 60 (rtp1_fwvers) */ +const uint8_t rtp_getserial[4] = { 0x81, 0x01, 0x00, 0x00 }; /* Resp len 64 (rtp1_serial) */ +const uint8_t rtp_getserialhead[4] = { 0x81, 0x01, 0x01, 0x00 }; /* Resp len 64 (rtp1_serial) */ +const uint8_t rtp_getcounters[4] = { 0x81, 0x04, 0x00, 0x00 }; /* Resp len 20 (rtp1_counters) */ -/* Unknowns */ -const uint8_t rtp_unknown1[4] = { 0x06, 0x00, 0x00, 0x00 }; /* Resp len 0 */ - // Read Status? -const uint8_t rtp_unknown2[4] = { 0x06, 0x80, 0x00, 0x00 }; /* Resp len 8 */ - // -> 02 00 06 2a ff 00 1d 27 - // -> 02 00 06 2a ff 00 1e 27 - // -> 10 00 02 2a ff 00 26 27 -const uint8_t rtp_unknown3[4] = { 0x10, 0x00, 0x00, 0x00 }; /* Resp len 4 */ - // -> 00 00 00 01 Seen prior to sending data to printer. status/ready? - // ReadCapabilities? -const uint8_t rtp_unknown4[4] = { 0x06, 0x03, 0x00, 0x00 }; /* Req len 4, resp 14?? */ - -// *** XXX head temp (&target), ribbon type, paper type, cut & page alignment, media total +// *** XXX cut & page alignment, media total? // plus state of cutter, cover, ribbon panel position, etc.. struct rosetta_header { @@ -184,7 +210,7 @@ struct kodak8800_ctx { /* Helper Functions */ static int rtp1_docmd(struct kodak8800_ctx *ctx, const uint8_t *cmd, const uint8_t *payload, uint32_t payload_len, - uint32_t maxresp_len, uint8_t *respbuf) + uint32_t maxresp_len, uint8_t *respbuf, struct rtp1_sts *sts) { int ret; int num; @@ -220,11 +246,22 @@ static int rtp1_docmd(struct kodak8800_ctx *ctx, const uint8_t *cmd, goto done; } - // XXX check response header! pass up to higher level? + /* Copy over the error code */ + if (sts) { + memcpy(sts, &resp.sts, sizeof(resp.sts)); + sts->err = be16_to_cpu(sts->err); + } - /* Read response payload, if anything */ + + /* Read response payload, if any */ resp.payload_len = be32_to_cpu(resp.payload_len); - if (resp.payload_len > maxresp_len || (maxresp_len && !respbuf)) { + if (!maxresp_len || !respbuf) { + if (resp.payload_len) + ERROR("No buffer supplied but printer sending %d bytes\n", (int)resp.payload_len); + goto done; + } + + if (resp.payload_len > maxresp_len) { ERROR("Oversize response (%d/%d)\n", resp.payload_len, maxresp_len); return CUPS_BACKEND_FAILED; } @@ -244,7 +281,7 @@ static int rtp1_getmaxxfer(struct kodak8800_ctx *ctx, uint32_t *maxlen) { int ret; - ret = rtp1_docmd(ctx, rtp_getmaxxfer, NULL, 0, 4, (uint8_t*)maxlen); + ret = rtp1_docmd(ctx, rtp_getmaxxfer, NULL, 0, 4, (uint8_t*)maxlen, NULL); *maxlen = be32_to_cpu(*maxlen); @@ -259,15 +296,15 @@ static int kodak8800_getinfo(struct kodak8800_ctx *ctx) struct rtp1_fwvers fwvers; ret = rtp1_docmd(ctx, rtp_getmfgmodel, NULL, 0, - sizeof(mfgmdl), (uint8_t*) &mfgmdl); + sizeof(mfgmdl), (uint8_t*) &mfgmdl, NULL); if (ret) return ret; ret = rtp1_docmd(ctx, rtp_getserialhead, NULL, 0, - sizeof(headsn), (uint8_t*) &headsn); + sizeof(headsn), (uint8_t*) &headsn, NULL); if (ret) return ret; ret = rtp1_docmd(ctx, rtp_getfwversions, NULL, 0, - sizeof(fwvers), (uint8_t*) &fwvers); + sizeof(fwvers), (uint8_t*) &fwvers, NULL); if (ret) return ret; @@ -293,7 +330,7 @@ static int kodak8800_getmedia(struct kodak8800_ctx *ctx) struct rtp1_mediastatus media; ret = rtp1_docmd(ctx, rtp_getmedia, NULL, 0, - sizeof(media), (uint8_t*) &media); + sizeof(media), (uint8_t*) &media, NULL); if (ret) return ret; @@ -306,6 +343,7 @@ static int kodak8800_getmedia(struct kodak8800_ctx *ctx) INFO("Paper Type: %s (%d)\n", media.paper_type == PAPER_TYPE_7 ? "8\"" : "Unknown", media.paper_type); //XXX INFO("Remaining Paper: %d feet\n", media.paper_remain / 12); INFO("Remaining Ribbon: %d feet\n", media.ribbon_remain / 12); + INFO("Remaining Prints: %d\n", media.ribbon_remain / 12 / 4); return CUPS_BACKEND_OK; } @@ -316,7 +354,7 @@ static int kodak8800_getcounters(struct kodak8800_ctx *ctx) struct rtp1_counters counters; ret = rtp1_docmd(ctx, rtp_getcounters, NULL, 0, - sizeof(counters), (uint8_t*) &counters); + sizeof(counters), (uint8_t*) &counters, NULL); if (ret) return ret; @@ -334,11 +372,32 @@ static int kodak8800_getcounters(struct kodak8800_ctx *ctx) return CUPS_BACKEND_OK; } +static int kodak8800_canceljob(struct kodak8800_ctx *ctx, int id) +{ + int ret; + uint8_t jobcmd[4]; + uint32_t jobid; + + memcpy(jobcmd, rtp_canceljob, sizeof(jobcmd)); + + if (id > 0) { + jobid = id; + jobid = cpu_to_be32(jobid); + jobcmd[1] = 1; // XXX this might need to be the jobid + ret = rtp1_docmd(ctx, jobcmd, (uint8_t*)&jobid, sizeof(jobid), 0, NULL, NULL); + } else { + ret = rtp1_docmd(ctx, jobcmd, NULL, 0, 0, NULL, NULL); + } + + return ret; +} + static void kodak8800_cmdline(void) { DEBUG("\t\t[ -i ] # Query printer info\n"); DEBUG("\t\t[ -m ] # Query media info\n"); DEBUG("\t\t[ -n ] # Query counters\n"); + DEBUG("\t\t[ -X id ] # Cancel job (0 for all)\n"); } static int kodak8800_cmdline_arg(void *vctx, int argc, char **argv) @@ -349,7 +408,7 @@ static int kodak8800_cmdline_arg(void *vctx, int argc, char **argv) if (!ctx) return -1; - while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "imn")) >= 0) { + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "imnX:")) >= 0) { switch(i) { GETOPT_PROCESS_GLOBAL case 'i': @@ -361,6 +420,10 @@ static int kodak8800_cmdline_arg(void *vctx, int argc, char **argv) case 'n': j = kodak8800_getcounters(ctx); break; + case 'X': + j = kodak8800_canceljob(ctx, atoi(optarg)); + break; + default: break; /* Ignore completely */ } @@ -402,7 +465,7 @@ static int kodak8800_attach(void *vctx, struct dyesub_connection *conn, uint8_t ret = kodak8800_query_mfgmodel(ctx); if (ret) return CUPS_BACKEND_FAILED; - ret = rtp1_docmd(ctx, rtp_getmedia, NULL, 0, sizeof(media), (uint8_t*)&media); + ret = rtp1_docmd(ctx, rtp_getmedia, NULL, 0, sizeof(media), (uint8_t*)&media, NULL); if (ret) return CUPS_BACKEND_FAILED; @@ -559,6 +622,7 @@ static int kodak8800_main_loop(void *vctx, const void *vjob) { struct kodak8800_ctx *ctx = vctx; int ret; + struct rtp1_sts sts; const struct kodak8800_printjob *job = vjob; @@ -567,15 +631,37 @@ static int kodak8800_main_loop(void *vctx, const void *vjob) { if (!job) return CUPS_BACKEND_FAILED; - // query printer for shit - INFO("Waiting for printer idle\n"); - // update marker levels? - - // RTP1 status etc? + /* Query status */ + do { + ret = rtp1_docmd(ctx, rtp_getstatus, NULL, 0, 0, NULL, &sts); + if (ret) + return ret; + if (sts.err) { + ERROR("Printer reports error: %04x\n", sts.err); + return CUPS_BACKEND_FAILED; // XXX make it more subtle! + } + if (sts.sts[0] == STATE_IDLE) { + break; + } + sleep(1); + } while (1); INFO("Sending image data\n"); + + uint32_t jobid; + ret = rtp1_docmd(ctx, rtp_openjob, NULL, 0, 4, (uint8_t*)&jobid, &sts); + if (ret) + return ret; + + jobid = be32_to_cpu(jobid); + if (sts.err) { + ERROR("Printer reports error: %04x\n", sts.err); + return CUPS_BACKEND_FAILED; + } + INFO("Printer assigned Job ID: %d\n", (int) jobid); + /* Sent over data blocks */ uint32_t offset = 0; while (offset < job->jobsize) { @@ -584,23 +670,48 @@ static int kodak8800_main_loop(void *vctx, const void *vjob) { if (ret) return ret; + if (job->jobsize - offset < max_blocksize) + max_blocksize = job->jobsize - offset; + ret = rtp1_docmd(ctx, rtp_sendimagedata, job->databuf + offset, max_blocksize, - 0, NULL); + 0, NULL, &sts); if (ret) return ret; + if (sts.err) { + ERROR("Printer reports error: %04x\n", sts.err); + return CUPS_BACKEND_FAILED; + } + + offset += max_blocksize; } /* Send payload footer */ - ret = rtp1_docmd(ctx, rtp_printfooter, - NULL, 0, 0, NULL); + ret = rtp1_docmd(ctx, rtp_closejob, + NULL, 0, 0, NULL, &sts); if (ret) return ret; INFO("Waiting for printer to acknowledge completion\n"); - // RTP1 status etc? + do { + sleep(1); - // update marker levels? + ret = rtp1_docmd(ctx, rtp_getstatus, NULL, 0, 0, NULL, &sts); + if (ret) + return ret; + if (sts.err) { + ERROR("Printer reports error: %04x\n", sts.err); + return CUPS_BACKEND_FAILED; + } + if (sts.sts[0] == STATE_IDLE) { + break; + } + if (fast_return) { + INFO("Fast return mode enabled.\n"); + break; + } + sleep(1); + } while (1); INFO("Print complete\n"); @@ -616,7 +727,7 @@ static int kodak8800_query_serno(struct dyesub_connection *conn, char *respbuf, .conn = conn, }; - ret = rtp1_docmd(&ctx, rtp_getserial, NULL, 0, sizeof(buf), buf); + ret = rtp1_docmd(&ctx, rtp_getserial, NULL, 0, sizeof(buf), buf, NULL); if (!ret) memcpy(respbuf, buf, buf_len); @@ -629,7 +740,7 @@ static int kodak8800_query_mfgmodel(struct kodak8800_ctx *ctx) uint8_t buf[256]; int ret; - ret = rtp1_docmd(ctx, rtp_getmfgmodel, NULL, 0, sizeof(buf), buf); + ret = rtp1_docmd(ctx, rtp_getmfgmodel, NULL, 0, sizeof(buf), buf, NULL); if (!ret) { memcpy(ctx->serial, buf + 64*2, sizeof(ctx->serial)); @@ -644,7 +755,7 @@ static int kodak8800_query_markers(void *vctx, struct marker **markers, int *cou struct rtp1_mediastatus media; int ret; - ret = rtp1_docmd(ctx, rtp_getmedia, NULL, 0, sizeof(media), (uint8_t*)&media); + ret = rtp1_docmd(ctx, rtp_getmedia, NULL, 0, sizeof(media), (uint8_t*)&media, NULL); if (ret) return CUPS_BACKEND_FAILED; @@ -668,6 +779,8 @@ static int kodak8800_query_stats(void *vctx, struct printerstats *stats) { struct kodak8800_ctx *ctx= vctx; struct rtp1_counters counters; + struct rtp1_sts sts; + int ret; stats->mfg = "Kodak"; @@ -685,14 +798,25 @@ static int kodak8800_query_stats(void *vctx, struct printerstats *stats) stats->levelmax[0] = ctx->marker.levelmax; stats->levelnow[0] = ctx->marker.levelnow; stats->name[0] = "Roll"; - stats->status[0] = strdup("Unknown"); // XXX - ret = rtp1_docmd(ctx, rtp_getcounters, NULL, 0, sizeof(counters), (uint8_t*) &counters); + ret = rtp1_docmd(ctx, rtp_getcounters, NULL, 0, sizeof(counters), (uint8_t*) &counters, &sts); if (ret) return ret; stats->cnt_life[0] = be32_to_cpu(counters.prints_finished); + const char *status; + if (sts.err) + status = "Error"; + else if (sts.sts[0] == STATE_IDLE) + status = "Idle"; + else if (sts.sts[0] == STATE_PRINT) + status = "Printing"; + else + status = "Unknown"; + + stats->status[0] = strdup(status); // XXX + return CUPS_BACKEND_OK; } @@ -705,7 +829,7 @@ static const char *kodak8800_prefixes[] = { /* Exported */ const struct dyesub_backend kodak8800_backend = { .name = "Kodak 8800/9810", - .version = "0.02WIP", + .version = "0.05", .uri_prefixes = kodak8800_prefixes, .cmdline_usage = kodak8800_cmdline, .cmdline_arg = kodak8800_cmdline_arg, @@ -883,107 +1007,21 @@ const struct dyesub_backend kodak8800_backend = { > 52 54 50 31 xx xx xx xx yy yy yy yy l1 l1 l1 l1 >> [ l1l1l1l1 bytes of payload ] -< 52 54 40 31 xx xx xx xx ss ss s2 s2 s2 00 00 00 l2 l2 l2 l2 +< 52 54 40 31 xx xx xx xx ss ss EE EE s2 00 00 00 l2 l2 l2 l2 << [ l2l2l2l2 bytes of payload ] xx xx xx xx == command yy yy yy yy == response buffer length (ie l2l2l2l2 must be <= yyyyyyyy) - ss ss == status message (10 10 is ok, 10 12 ok, dunno about errors) - s2 s2 s2 == secondary status (seen 00 00 00, 00 00 02, 05 04 02) + ss ss == status message (10 10 is ok, 10 12 error) + EE EE == error code + s2 == secondary status (seen 00, 01, 02) - Specific commands seen when printing: - 52 54 50 31 [....] "RTP1" + **************** TODO - media status: - -> 06 40 00 00 00 10 00 00 00 00 00 00 -< 06 40 00 00 10 10 00 00 00 00 00 00 00 00 00 10 -<< 00 01 00 02 00 01 00 01 00 00 04 a4 00 00 01 20 - - max xfer len: -> 01 00 00 00 00 00 00 04 00 00 00 00 -< 01 00 00 00 10 10 00 00 02 00 00 00 00 00 00 04 -<< 00 18 00 00 - - media status: -> 06 40 00 00 00 10 00 00 00 00 00 00 -< 06 40 00 00 10 10 00 00 00 00 00 00 00 00 00 10 -<< 00 01 00 02 00 01 00 01 00 00 04 a4 00 00 01 20 - - some sort of status? -> 10 00 00 00 00 00 00 04 00 00 00 00 -< 10 00 00 00 10 10 00 00 00 00 00 00 00 00 00 04 -<< 00 00 00 01 - - [ Each data block gets this sequence ] - -> 01 00 00 00 00 00 00 04 00 00 00 00 -< 01 00 00 00 10 10 00 00 02 00 00 00 00 00 00 04 -<< 00 18 00 00 <-- Max available xfer buffer size! -> 00 00 00 00 00 00 00 00 ll ll ll ll ->> [ llllllll bytes of data, in 4K transfers, up to max size] -< 00 00 00 00 10 10 00 00 02 00 00 00 00 00 00 00 - - [ after final block ] - -> 01 00 00 00 00 00 00 04 00 00 00 00 -< 01 00 00 00 10 10 00 00 02 00 00 00 00 00 00 04 -<< 00 00 00 00 <-- finished? - - [ footer ] - -> 11 00 00 00 00 00 00 00 00 00 00 00 -< 11 00 00 00 10 10 00 00 02 00 00 00 00 00 00 00 - - **** COMMANDS: - - Query Printer Serial Number (Matches what's in IEEE1284) =~ 98C070902445 - -> 81 01 00 00 00 00 ff ff 00 00 00 00 -< 81 01 00 00 10 12 05 04 01 00 00 00 00 00 00 40 -<< 39 38 43 30 37 30 39 30 32 34 34 35 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 00 00 00 00 00 -<< 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - Serial number is ASCII, null-terminated, 64 byte payload - - Query Head Serial Number (??) =~ 6J3867 - -> 81 01 01 00 00 00 ff ff 00 00 00 00 -< 81 01 01 00 10 12 05 04 01 00 00 00 00 00 00 40 -<< 39 38 43 30 37 30 39 30 32 34 34 35 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 00 00 00 00 00 -<< 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - Serial number is ASCII, null-terminated, 64 byte payload - - Query Mfg, Model, Serial & Firmware info (??) - -> 13 00 00 00 00 00 01 00 00 00 00 00 -< 13 00 00 00 10 12 05 04 01 00 00 00 00 00 01 00 -<< 45 61 73 74 6d 61 6e 20 4b 6f 64 61 6b 20 43 6f -<< 6d 70 61 63 79 00 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 20 20 20 - - [ followed by three more 64 byte sections ] - - Each section is ASCII, null-terminated/padded, 64 byte payload - 4 sections: Manufacturer, Model, Serial, FW Version - - Query FW sub-versions - -> 13 80 00 00 00 00 00 3c 00 00 00 00 -< 13 80 00 00 10 12 05 04 01 00 00 00 00 00 00 3c -<< 39 38 43 30 37 30 39 30 32 34 34 35 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 00 00 00 00 00 -<< 00 00 00 00 00 00 00 00 00 00 00 00 00 - - Five blocks of 12 bytes, not always null-terminated! - DSP, ??, System, Head, Reset + * Sensor reporting (and queries) + * Job status / Job queue status + * Print status & errors + * 8x12 media crap */ diff --git a/testjobs/kodak_8800_8x10.raw b/testjobs/kodak_8800_8x10.raw index f602e22..e90c0a8 100644 --- a/testjobs/kodak_8800_8x10.raw +++ b/testjobs/kodak_8800_8x10.raw @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:baa99c650a11004d2d38ccd127a72ba0791e0ccd9d3f81b1e9bb9ef02bccf4c5 +oid sha256:95c6e99c2dfe8ce9ec394ec37ba68c4c2d2f646679c712dbff8ce2ed358e2de4 size 22354234