diff --git a/README b/README index ea2c660..3e00a81 100644 --- a/README +++ b/README @@ -239,7 +239,8 @@ -c filename Query tone curve [1] -C filename Set tone curve [1] -m Query supported media - -s Query printer status (not fully decoded) + -s Query printer status + -X id Cancel print job 'id' [2] Notes: @@ -249,6 +250,11 @@ Values are unsigned 16-bit big endian, between 0 and 16383 (ie 14-bit) + [2] Job ID is the Internal Job ID (reported via status) + This cancels a multi-copy print job. + To see which jobs are active/pending, see the output of the + '-s' command, specifically the 'Bank' output. + *************************************************************************** BACKEND=kodak605 diff --git a/backend_kodak6800.c b/backend_kodak6800.c index 0f209a7..edb69a2 100644 --- a/backend_kodak6800.c +++ b/backend_kodak6800.c @@ -49,48 +49,150 @@ /* File header */ struct kodak6800_hdr { - uint8_t hdr[9]; /* Always 03 1b 43 48 43 0a 00 04 00 [6850] - 03 1b 43 48 43 0a 00 01 00 [6800] */ - uint8_t copies; + uint8_t hdr[7]; /* Always 03 1b 43 48 43 0a 00 */ + uint8_t jobid; /* Non-zero */ + uint16_t copies; /* BE, in BCD format (1-9999) */ uint16_t columns; /* BE */ uint16_t rows; /* BE */ uint8_t size; /* 0x06 for 6x8, 0x00 for 6x4, 0x07 for 5x7 */ uint8_t laminate; /* 0x01 to laminate, 0x00 for not */ - uint8_t unk1; /* 0x00 or 0x01 (for 4x6 on 6x8 media) */ + uint8_t mode; /* 0x00 or 0x01 (for 4x6 on 6x8 media) */ } __attribute__((packed)); struct kodak68x0_status_readback { uint8_t hdr; /* Always 01 */ - uint8_t sts1; /* Always 0x02 (idle) or 0x01 (busy) */ - uint8_t sts2; /* 0x01 == ready, 0x02 == no media, 0x03 == not ready */ - uint8_t errtype; /* see 68x0_error_codes() */ - uint8_t null0[2]; - uint8_t unkA; /* 0x00 or 0x01 or 0x10 */ + uint8_t status; /* STATUS_* */ + uint8_t status1; /* STATUS1_* */ + uint32_t status2; /* STATUS2_* */ uint8_t errcode; /* Error ## */ - uint32_t ctr0; /* Total Prints (BE) (lifetime?) */ - uint32_t ctr1; /* Total Prints (BE) (since maint?) */ - uint32_t ctr2; /* Increments by 1 for each print (6850), unk (6800). BE */ - uint32_t ctr3; /* Increments by 2 for each print. Cutter? BE */ + uint32_t lifetime; /* Lifetime Prints (BE) */ + uint32_t maint; /* Maint Prints (BE) */ + uint32_t media; /* Media Prints (6850), Unknown (6800) (BE) */ + uint32_t cutter; /* Cutter Actuations (BE) */ uint8_t nullB[2]; - uint8_t errtype2; /* see 68x0_error_codes() */ - uint8_t donor; /* Percentage, 0-100 */ - uint8_t unkC[2]; /* Always 00 03 */ - uint16_t main_fw; /* seen 652, 656, 670, 671 (6850) and 232 (6800) */ - uint8_t unkD[2]; /* Always 00 01 */ - uint16_t dsp_fw; /* Seen 540, 541, 560 (6850) and 131 (6800) */ - uint8_t unk1; /* Seen 0x00, 0x01, 0x03, 0x04 (4x6), 0x05 (8x6) */ - uint8_t null1; - uint16_t remain; /* Remaining prints in job */ - uint16_t complete; /* Completed prints in job */ - uint16_t total; /* Total prints in job */ - uint8_t null5[7]; + uint8_t errtype; /* seen 0x00 or 0xd0 */ + uint8_t donor; /* Percentage, 0-100 */ + uint16_t main_boot; /* Always 003 */ + uint16_t main_fw; /* seen 652, 656, 670, 671 (6850) and 232 (6800) */ + uint16_t dsp_boot; /* Always 001 */ + uint16_t dsp_fw; /* Seen 540, 541, 560 (6850) and 131 (6800) */ + uint8_t b1_jobid; + uint8_t b2_jobid; + uint16_t b1_remain; /* Remaining prints in job */ + uint16_t b1_complete; /* Completed prints in job */ + uint16_t b1_total; /* Total prints in job */ + uint16_t b2_remain; /* Remaining prints in job */ + uint16_t b2_complete; /* Completed prints in job */ + uint16_t b2_total; /* Total prints in job */ + uint8_t curve_status; /* Always seems to be 0x00 */ } __attribute__((packed)); +enum { + STATUS_PRINTING = 1, + STATUS_IDLE = 2, +}; + +enum { + STATUS1_STANDBY = 1, + STATUS1_ERROR = 2, + STATUS1_WAIT = 3, +}; + +#define STATE_STANDBY_STATUS2 0x0 + +enum { + WAIT_STATUS2_INIT = 0, + WAIT_STATUS2_RIBBON = 1, + WAIT_STATUS2_THERMAL = 2, + WAIT_STATUS2_OPERATING = 3, + WAIT_STATUS2_BUSY = 4, +}; + +#define ERROR_STATUS2_CTRL_CIRCUIT (1<<31) +#define ERROR_STATUS2_MECHANISM_CTRL (1<<30) +#define ERROR_STATUS2_SENSOR (1<<13) +#define ERROR_STATUS2_COVER_OPEN (1<<12) +#define ERROR_STATUS2_TEMP_SENSOR (1<<9) +#define ERROR_STATUS2_PAPER_JAM (1<<8) +#define ERROR_STATUS2_PAPER_EMPTY (1<<6) +#define ERROR_STATUS2_RIBBON_ERR (1<<4) + +enum { + CTRL_CIR_ERROR_EEPROM1 = 0x01, + CTRL_CIR_ERROR_EEPROM2 = 0x02, + CTRL_CIR_ERROR_DSP = 0x04, + CTRL_CIR_ERROR_CRC_MAIN = 0x06, + CTRL_CIR_ERROR_DL_MAIN = 0x07, + CTRL_CIR_ERROR_CRC_DSP = 0x08, + CTRL_CIR_ERROR_DL_DSP = 0x09, + CTRL_CIR_ERROR_ASIC = 0x0a, + CTRL_CIR_ERROR_DRAM = 0x0b, + CTRL_CIR_ERROR_DSPCOMM = 0x29, +}; + +enum { + MECH_ERROR_HEAD_UP = 0x01, + MECH_ERROR_HEAD_DOWN = 0x02, + MECH_ERROR_MAIN_PINCH_UP = 0x03, + MECH_ERROR_MAIN_PINCH_DOWN = 0x04, + MECH_ERROR_SUB_PINCH_UP = 0x05, + MECH_ERROR_SUB_PINCH_DOWN = 0x06, + MECH_ERROR_FEEDIN_PINCH_UP = 0x07, + MECH_ERROR_FEEDIN_PINCH_DOWN = 0x08, + MECH_ERROR_FEEDOUT_PINCH_UP = 0x09, + MECH_ERROR_FEEDOUT_PINCH_DOWN = 0x0a, + MECH_ERROR_CUTTER_LR = 0x0b, + MECH_ERROR_CUTTER_RL = 0x0c, +}; + +enum { + SENSOR_ERROR_CUTTER = 0x05, + SENSOR_ERROR_HEAD_DOWN = 0x09, + SENSOR_ERROR_HEAD_UP = 0x0a, + SENSOR_ERROR_MAIN_PINCH_DOWN = 0x0b, + SENSOR_ERROR_MAIN_PINCH_UP = 0x0c, + SENSOR_ERROR_FEED_PINCH_DOWN = 0x0d, + SENSOR_ERROR_FEED_PINCH_UP = 0x0e, + SENSOR_ERROR_EXIT_PINCH_DOWN = 0x0f, + SENSOR_ERROR_EXIT_PINCH_UP = 0x10, + SENSOR_ERROR_LEFT_CUTTER = 0x11, + SENSOR_ERROR_RIGHT_CUTTER = 0x12, + SENSOR_ERROR_CENTER_CUTTER = 0x13, + SENSOR_ERROR_UPPER_CUTTER = 0x14, + SENSOR_ERROR_PAPER_FEED_COVER = 0x15, +}; + +enum { + TEMP_SENSOR_ERROR_HEAD_HIGH = 0x01, + TEMP_SENSOR_ERROR_HEAD_LOW = 0x02, + TEMP_SENSOR_ERROR_ENV_HIGH = 0x03, + TEMP_SENSOR_ERROR_ENV_LOW = 0x04, +}; + +enum { + COVER_OPEN_ERROR_UPPER = 0x01, + COVER_OPEN_ERROR_LOWER = 0x02, +}; + +enum { + PAPER_EMPTY_ERROR = 0x00, +}; + +enum { + RIBBON_ERROR = 0x00, +}; + +enum { + CURVE_TABLE_STATUS_INITIAL = 0x00, + CURVE_TABLE_STATUS_USERSET = 0x01, + CURVE_TABLE_STATUS_CURRENT = 0x02, +}; + struct kodak6800_printsize { uint8_t hdr; /* Always 0x06 */ uint16_t width; /* BE */ uint16_t height; /* BE */ - uint8_t hdr2; /* Always 0x01 */ + uint8_t type; /* MEDIA_TYPE_* [ ie paper ] */ uint8_t code; /* 00, 01, 02, 03, 04, 05 seen. An index? */ uint8_t code2; /* 00, 01 seen. Seems to be 1 only after a 4x6 printed. */ uint8_t null[2]; @@ -120,6 +222,8 @@ struct kodak6800_ctx { int type; + uint8_t jobid; + struct kodak68x0_media_readback *media; struct kodak6800_hdr hdr; @@ -128,16 +232,6 @@ struct kodak6800_ctx { }; #define READBACK_LEN 68 -char *kodak68x0_error_codes(uint8_t code1, uint8_t code2) -{ - if (code1 == 0x80 && code2 == 0xd0) - return "Control Error"; - if (code1 == 0x00 && code2 == 0xd0) - return "Ribbon Checking"; - - return "Unknown Type (please report!)"; -} - static void kodak68x0_dump_mediainfo(struct kodak68x0_media_readback *media) { int i; @@ -190,7 +284,7 @@ static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx, struct kodak68x0_m return ret; if (num < (int)sizeof(*media)) { ERROR("Short read! (%d/%d)\n", num, (int) sizeof(*media)); - return 4; + return CUPS_BACKEND_FAILED; } @@ -204,42 +298,225 @@ static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx, struct kodak68x0_m return 0; } -static char *kodak68x0_statuses(uint8_t sts1, uint8_t sts2) +static int kodak68x0_canceljob(struct kodak6800_ctx *ctx, + int id) { - switch (sts2) { - case 0x01: - switch (sts1) { - case 0x01: - return "Busy"; - case 0x02: - return "Idle"; - default: - return "Unknown sts1"; - } - break; - case 0x02: - return "Out of Media"; - case 0x03: - return "Offline"; - default: - return "Unknown sts2"; + uint8_t req[16]; + int ret, num; + struct kodak68x0_status_readback sts; + + memset(req, 0, sizeof(req)); + + req[0] = 0x03; + req[1] = 0x1b; + req[2] = 0x43; + req[3] = 0x48; + req[4] = 0x43; + req[5] = 0x13; + req[6] = id; + + /* Send request */ + if ((ret = send_data(ctx->dev, ctx->endp_down, + req, sizeof(req)))) + return ret; + + /* Get response */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*)&sts, sizeof(sts), &num); + + if (ret < 0) + return ret; + if (num < (int)sizeof(sts)) { + ERROR("Short read! (%d/%d)\n", num, (int) sizeof(sts)); + return CUPS_BACKEND_FAILED; } + return 0; +} + +/* Structure dumps */ +static char *kodak68x0_status_str(struct kodak68x0_status_readback *resp) +{ + switch(resp->status1) { + case STATUS1_STANDBY: + return "Standby (Ready)"; + case STATUS1_WAIT: + switch (be32_to_cpu(resp->status2)) { + case WAIT_STATUS2_INIT: + return "Wait (Initializing)"; + case WAIT_STATUS2_RIBBON: + return "Wait (Ribbon Winding)"; + case WAIT_STATUS2_THERMAL: + return "Wait (Thermal Protection)"; + case WAIT_STATUS2_OPERATING: + return "Wait (Operating)"; + case WAIT_STATUS2_BUSY: + return "Wait (Busy)"; + default: + return "Wait (Unknown)"; + } + case STATUS1_ERROR: + switch (be32_to_cpu(resp->status2)) { + case ERROR_STATUS2_CTRL_CIRCUIT: + switch (resp->errcode) { + case CTRL_CIR_ERROR_EEPROM1: + return "Error (EEPROM1)"; + case CTRL_CIR_ERROR_EEPROM2: + return "Error (EEPROM2)"; + case CTRL_CIR_ERROR_DSP: + return "Error (DSP)"; + case CTRL_CIR_ERROR_CRC_MAIN: + return "Error (Main CRC)"; + case CTRL_CIR_ERROR_DL_MAIN: + return "Error (Main Download)"; + case CTRL_CIR_ERROR_CRC_DSP: + return "Error (DSP CRC)"; + case CTRL_CIR_ERROR_DL_DSP: + return "Error (DSP Download)"; + case CTRL_CIR_ERROR_ASIC: + return "Error (ASIC)"; + case CTRL_CIR_ERROR_DRAM: + return "Error (DRAM)"; + case CTRL_CIR_ERROR_DSPCOMM: + return "Error (DSP Communincation)"; + default: + return "Error (Unknown Circuit)"; + } + case ERROR_STATUS2_MECHANISM_CTRL: + switch (resp->errcode) { + case MECH_ERROR_HEAD_UP: + return "Error (Head Up Mechanism)"; + case MECH_ERROR_HEAD_DOWN: + return "Error (Head Down Mechanism)"; + case MECH_ERROR_MAIN_PINCH_UP: + return "Error (Main Pinch Up Mechanism)"; + case MECH_ERROR_MAIN_PINCH_DOWN: + return "Error (Main Pinch Down Mechanism)"; + case MECH_ERROR_SUB_PINCH_UP: + return "Error (Sub Pinch Up Mechanism)"; + case MECH_ERROR_SUB_PINCH_DOWN: + return "Error (Sub Pinch Down Mechanism)"; + case MECH_ERROR_FEEDIN_PINCH_UP: + return "Error (Feed-in Pinch Up Mechanism)"; + case MECH_ERROR_FEEDIN_PINCH_DOWN: + return "Error (Feed-in Pinch Down Mechanism)"; + case MECH_ERROR_FEEDOUT_PINCH_UP: + return "Error (Feed-out Pinch Up Mechanism)"; + case MECH_ERROR_FEEDOUT_PINCH_DOWN: + return "Error (Feed-out Pinch Down Mechanism)"; + case MECH_ERROR_CUTTER_LR: + return "Error (Left->Right Cutter)"; + case MECH_ERROR_CUTTER_RL: + return "Error (Right->Left Cutter)"; + default: + return "Error (Unknown Mechanism)"; + } + case ERROR_STATUS2_SENSOR: + switch (resp->errcode) { + case SENSOR_ERROR_CUTTER: + return "Error (Cutter Sensor)"; + case SENSOR_ERROR_HEAD_DOWN: + return "Error (Head Down Sensor)"; + case SENSOR_ERROR_HEAD_UP: + return "Error (Head Up Sensor)"; + case SENSOR_ERROR_MAIN_PINCH_DOWN: + return "Error (Main Pinch Down Sensor)"; + case SENSOR_ERROR_MAIN_PINCH_UP: + return "Error (Main Pinch Up Sensor)"; + case SENSOR_ERROR_FEED_PINCH_DOWN: + return "Error (Feed Pinch Down Sensor)"; + case SENSOR_ERROR_FEED_PINCH_UP: + return "Error (Feed Pinch Up Sensor)"; + case SENSOR_ERROR_EXIT_PINCH_DOWN: + return "Error (Exit Pinch Up Sensor)"; + case SENSOR_ERROR_EXIT_PINCH_UP: + return "Error (Exit Pinch Up Sensor)"; + case SENSOR_ERROR_LEFT_CUTTER: + return "Error (Left Cutter Sensor)"; + case SENSOR_ERROR_RIGHT_CUTTER: + return "Error (Right Cutter Sensor)"; + case SENSOR_ERROR_CENTER_CUTTER: + return "Error (Center Cutter Sensor)"; + case SENSOR_ERROR_UPPER_CUTTER: + return "Error (Upper Cutter Sensor)"; + case SENSOR_ERROR_PAPER_FEED_COVER: + return "Error (Paper Feed Cover)"; + default: + return "Error (Unknown Sensor)"; + } + case ERROR_STATUS2_COVER_OPEN: + switch (resp->errcode) { + case COVER_OPEN_ERROR_UPPER: + return "Error (Upper Cover Open)"; + case COVER_OPEN_ERROR_LOWER: + return "Error (Lower Cover Open)"; + default: + return "Error (Unknown Cover Open)"; + } + case ERROR_STATUS2_TEMP_SENSOR: + switch (resp->errcode) { + case TEMP_SENSOR_ERROR_HEAD_HIGH: + return "Error (Head Temperature High)"; + case TEMP_SENSOR_ERROR_HEAD_LOW: + return "Error (Head Temperature Low)"; + case TEMP_SENSOR_ERROR_ENV_HIGH: + return "Error (Environmental Temperature High)"; + case TEMP_SENSOR_ERROR_ENV_LOW: + return "Error (Environmental Temperature Low)"; + default: + return "Error (Unknown Temperature)"; + } + case ERROR_STATUS2_PAPER_JAM: + return "Error (Paper Jam)"; + case ERROR_STATUS2_PAPER_EMPTY: + return "Error (Paper Empty)"; + case ERROR_STATUS2_RIBBON_ERR: + return "Error (Ribbon)"; + default: + return "Error (Unknown)"; + } + default: + return "Unknown!"; + } } static void kodak68x0_dump_status(struct kodak6800_ctx *ctx, struct kodak68x0_status_readback *status) { - if (status->errtype || status->errtype2 || status->errcode) { - DEBUG("Error code : %s (%d/%d) # %d\n", - kodak68x0_error_codes(status->errtype, status->errtype2), - status->errtype, status->errtype2, status->errcode); - } + char *detail; + + switch (status->status) { + case STATUS_PRINTING: + detail = "Printing"; + break; + case STATUS_IDLE: + detail = "Idle"; + break; + default: + detail = "Unknown"; + break; + } + INFO("Printer Status : %s\n", detail); + + INFO("Printer State : %s # %02x %08x %02x\n", + kodak68x0_status_str(status), + status->status1, be32_to_cpu(status->status2), status->errcode); + + INFO("Bank 1 ID: %d\n", status->b1_jobid); + INFO("\tPrints: %d/%d complete\n", + be16_to_cpu(status->b1_complete), be16_to_cpu(status->b1_total)); + INFO("Bank 2 ID: %d\n", status->b2_jobid); + INFO("\tPrints: %d/%d complete\n", + be16_to_cpu(status->b2_complete), be16_to_cpu(status->b2_total)); + + INFO("Counters:\n"); + INFO("\tLifetime : %d\n", be32_to_cpu(status->lifetime)); + INFO("\tThermal Head : %d\n", be32_to_cpu(status->maint)); + INFO("\tCutter : %d\n", be32_to_cpu(status->cutter)); - DEBUG("Printer Status : %s\n", kodak68x0_statuses(status->sts1, status->sts2)); - DEBUG("Job Status : %d/%d completed\n", be16_to_cpu(status->complete), be16_to_cpu(status->total)); - DEBUG("Total prints : %d\n", be32_to_cpu(status->ctr0)); - DEBUG("Media prints : %d\n", be32_to_cpu(status->ctr2)); if (ctx->type == P_KODAK_6850) { int max; + + INFO("\tMedia : %d\n", be32_to_cpu(status->media)); + if (ctx->media->media == KODAK68x0_MEDIA_6R) { max = 375; } else { @@ -247,15 +524,15 @@ static void kodak68x0_dump_status(struct kodak6800_ctx *ctx, struct kodak68x0_st } if (max) { - DEBUG("Remaining prints : %d\n", max - be32_to_cpu(status->ctr2)); + INFO("\t Remaining : %d\n", max - be32_to_cpu(status->media)); } else { - DEBUG("Remaining prints : Unknown media type\n"); + INFO("\t Remaining : Unknown\n"); } } - DEBUG("Main FW version : %d\n", be16_to_cpu(status->main_fw)); - DEBUG("DSP FW version : %d\n", be16_to_cpu(status->dsp_fw)); - DEBUG("Donor : %d%%\n", status->donor); - DEBUG("\n"); + INFO("Main FW version: %d\n", be16_to_cpu(status->main_fw)); + INFO("DSP FW version : %d\n", be16_to_cpu(status->dsp_fw)); + INFO("Donor : %d%%\n", status->donor); + INFO("\n"); } static int kodak6800_get_status(struct kodak6800_ctx *ctx, @@ -425,7 +702,7 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname) ERROR("Memory Allocation Failure\n"); return -1; } - + INFO("Set Tone Curve from '%s'\n", fname); /* Read in file */ @@ -471,7 +748,7 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname) respbuf, sizeof(respbuf), &num); if (ret < 0) goto done; - + if (num != 51) { ERROR("Short read! (%d/%d)\n", num, 51); ret = 4; @@ -529,7 +806,7 @@ static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_ req[2] = 0x43; req[3] = 0x48; req[4] = 0x43; - req[5] = 0x03; + req[5] = 0x12; /* Send request */ if ((ret = send_data(dev, endp_down, @@ -554,7 +831,7 @@ static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_ static int kodak6850_send_init(struct kodak6800_ctx *ctx) { - uint8_t cmdbuf[64]; + uint8_t cmdbuf[CMDBUF_LEN]; uint8_t rdbuf[64]; int ret = 0, num = 0; @@ -565,34 +842,34 @@ static int kodak6850_send_init(struct kodak6800_ctx *ctx) cmdbuf[3] = 0x48; cmdbuf[4] = 0x43; cmdbuf[5] = 0x4c; - + if ((ret = send_data(ctx->dev, ctx->endp_down, cmdbuf, CMDBUF_LEN -1))) return CUPS_BACKEND_FAILED; - + /* Read response */ ret = read_data(ctx->dev, ctx->endp_up, rdbuf, READBACK_LEN, &num); if (ret < 0) return CUPS_BACKEND_FAILED; - + if (num < 51) { ERROR("Short read! (%d/%d)\n", num, 51); return CUPS_BACKEND_FAILED; } - + if (num != 51) { ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n", num, READBACK_LEN, ctx->endp_up); return CUPS_BACKEND_FAILED; } - + if (rdbuf[0] != 0x01 || rdbuf[2] != 0x43) { ERROR("Unexpected response from printer init!\n"); return CUPS_BACKEND_FAILED; } - + // XXX I believe this the media position // saying when we have a 4x6 left on an 8x6 blank if (rdbuf[1] != 0x01 && rdbuf[1] != 0x00) { @@ -608,6 +885,7 @@ static void kodak6800_cmdline(void) DEBUG("\t\t[ -C filename ] # Set tone curve\n"); DEBUG("\t\t[ -m ] # Query media\n"); DEBUG("\t\t[ -s ] # Query status\n"); + DEBUG("\t\t[ -X jobid ] # Cancel Job\n"); } static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv) @@ -621,7 +899,7 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv) /* Reset arg parsing */ optind = 1; opterr = 0; - while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:c:ms")) >= 0) { + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:c:msX:")) >= 0) { switch(i) { GETOPT_PROCESS_GLOBAL case 'c': @@ -640,6 +918,9 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv) kodak68x0_dump_status(ctx, &status); break; } + case 'X': + j = kodak68x0_canceljob(ctx, atoi(optarg)); + break; default: break; /* Ignore completely */ } @@ -673,9 +954,7 @@ static void kodak6800_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; @@ -685,6 +964,9 @@ static void kodak6800_attach(void *vctx, struct libusb_device_handle *dev, ctx->type = lookup_printer_type(&kodak6800_backend, desc.idVendor, desc.idProduct); + /* Ensure jobid is sane */ + ctx->jobid = (jobid & 0x7f) + 1; + /* Query media info */ if (kodak6800_get_mediainfo(ctx, ctx->media)) { ERROR("Can't query media\n"); @@ -763,18 +1045,17 @@ static int kodak6800_main_loop(void *vctx, int copies) { struct kodak6800_ctx *ctx = vctx; struct kodak68x0_status_readback status; - uint8_t cmdbuf[CMDBUF_LEN]; - int num, ret; if (!ctx) return CUPS_BACKEND_FAILED; + /* Fix max print count. */ + if (copies > 9999) // XXX test against remaining media + copies = 9999; + /* Printer handles generating copies.. */ - if (copies > 255) - copies = 255; - if (ctx->hdr.copies < copies) - ctx->hdr.copies = copies; + ctx->hdr.copies = cpu_to_be16(uint16_to_packed_bcd(copies)); /* Validate media */ if (ctx->media->media != KODAK68x0_MEDIA_6R && @@ -795,38 +1076,26 @@ static int kodak6800_main_loop(void *vctx, int copies) { return CUPS_BACKEND_HOLD; } - // XXX test against remaining media - INFO("Waiting for printer idle\n"); while(1) { if (kodak6800_get_status(ctx, &status)) return CUPS_BACKEND_FAILED; - if (status.errtype || status.errtype2 || status.errcode) { - ERROR("Printer error reported: %s (%d/%d) # %d\n", - kodak68x0_error_codes(status.errtype, status.errtype2), - status.errtype, status.errtype2, status.errcode); + if (status.status1 == STATUS1_ERROR) { + INFO("Printer State: %s # %02x %08x %02x\n", + kodak68x0_status_str(&status), + status.status1, be32_to_cpu(status.status2), status.errcode); return CUPS_BACKEND_FAILED; } - if (status.sts2 == 0x02) { - ERROR("Printer is out of media!\n"); - return CUPS_BACKEND_STOP; - } else if (status.sts2 == 0x03) { - ERROR("Printer is offline!\n"); - return CUPS_BACKEND_STOP; - } else if (status.sts2 != 0x01) { - ERROR("Unknown status 0x%02x\n", status.sts2); - return CUPS_BACKEND_FAILED; - } - - if (status.sts1 == 0x02) { + if (status.status == STATUS_IDLE) break; - } else if (status.sts1 != 0x01) { - ERROR("Unknown status1 0x%02x\n", status.sts1); - return CUPS_BACKEND_FAILED; - } + + /* See if we have an open bank */ + if (!status.b1_remain || + !status.b2_remain) + break; sleep(1); } @@ -837,34 +1106,25 @@ static int kodak6800_main_loop(void *vctx, int copies) { if (ret) return ret; } - - /* Set up print job header */ - memcpy(cmdbuf, &ctx->hdr, CMDBUF_LEN); - - /* 6850 uses same spool format but different header gets sent */ - if (ctx->type == P_KODAK_6850) { - if (ctx->hdr.size == 0x00) - cmdbuf[7] = 0x04; - else if (ctx->hdr.size == 0x06) - cmdbuf[7] = 0x05; /* XXX audit this! */ - } + + ctx->hdr.jobid = ctx->jobid; #if 0 /* If we want to disable 4x6 rewind on 8x6 media.. */ if (ctx->hdr.size == 0x00 && be16_to_cpu(ctx->media->sizes[0].width) == 0x0982) { - cmdbuf[14] = 0x06; - cmdbuf[16] = 0x01; + ctx->hdr.size = 0x06; + ctx->hdr.mode = 0x01; } #endif - + INFO("Sending image header\n"); if ((ret = send_data(ctx->dev, ctx->endp_down, - cmdbuf, CMDBUF_LEN))) + (uint8_t*) &ctx->hdr, sizeof(ctx->hdr)))) return ret; sleep(1); // Appears to be necessary for reliability INFO("Sending image data\n"); - if ((ret = send_data(ctx->dev, ctx->endp_down, + if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->databuf, ctx->datalen))) return CUPS_BACKEND_FAILED; @@ -874,15 +1134,17 @@ static int kodak6800_main_loop(void *vctx, int copies) { if (kodak6800_get_status(ctx, &status)) return CUPS_BACKEND_FAILED; - if (status.errtype || status.errtype2 || status.errcode) { - ERROR("Printer error reported: %s (%d/%d) # %d\n", - kodak68x0_error_codes(status.errtype, status.errtype2), - status.errtype, status.errtype2, status.errcode); + if (status.status1 == STATUS1_ERROR) { + INFO("Printer State: %s # %02x %08x %02x\n", + kodak68x0_status_str(&status), + status.status1, be32_to_cpu(status.status2), status.errcode); return CUPS_BACKEND_FAILED; } /* If all prints are complete, we're done! */ - if (status.complete == status.total) + if (status.b1_jobid == ctx->hdr.jobid && status.b1_complete == status.b1_total) + break; + if (status.b2_jobid == ctx->hdr.jobid && status.b2_complete == status.b2_total) break; if (fast_return) { @@ -891,7 +1153,7 @@ static int kodak6800_main_loop(void *vctx, int copies) { } } while (1); - + INFO("Print complete\n"); return CUPS_BACKEND_OK; @@ -900,7 +1162,7 @@ static int kodak6800_main_loop(void *vctx, int copies) { /* Exported */ struct dyesub_backend kodak6800_backend = { .name = "Kodak 6800/6850", - .version = "0.48", + .version = "0.49", .uri_prefix = "kodak6800", .cmdline_usage = kodak6800_cmdline, .cmdline_arg = kodak6800_cmdline_arg, @@ -910,7 +1172,7 @@ struct dyesub_backend kodak6800_backend = { .read_parse = kodak6800_read_parse, .main_loop = kodak6800_main_loop, .query_serno = kodak6800_query_serno, - .devices = { + .devices = { { USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak"}, { USB_VID_KODAK, USB_PID_KODAK_6850, P_KODAK_6850, "Kodak"}, { 0, 0, 0, ""} @@ -924,153 +1186,26 @@ struct dyesub_backend kodak6800_backend = { 6850 Adds support for 5x7, with 1548 pixels per row and 2140 columns. + All fields are BIG ENDIAN unless otherwise specified. + Header: - 03 1b 43 48 43 0a 00 01 00 Fixed header - NN Number of copies (01-255) - WW WW Number of columns, big endian. (Fixed at 1844 on 6800) - HH HH Number of rows, big endian. - SS 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850) - LL Laminate, 0x00 (off) or 0x01 (on) - UU 0x01 for multi-cut, 0x00 otherwise. - - Note: For 4x6 prints on 6x8 media, print size (SS) is set to 0x06 and the - final octet is set to 0x01. + 03 1b 43 48 43 0a 00 01 Fixed header + NN NN Number of copies in BCD form (0001->9999) + WW WW Number of columns (Fixed at 1844 on 6800) + HH HH Number of rows. + SS Print size -- 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850) + LL Laminate mode -- 0x00 (off) or 0x01 (on) + UU Print mode -- 0x00 (normal) or (0x01) 4x6 on 8x6 ************************************************************************ Note: 6800 is Shinko CHC-S1145-5A, 6850 is Shinko CHC-S1145-5B + Both are very similar to Shinko S1245! + ************************************************************************ - Kodak 6800 Printer Comms: - - [[file header]] 03 1b 43 48 43 0a 00 01 00 NN WW WW HH HH SS LL UU - - (see above for details on fields) - --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query] -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 a2 7b 00 00 a2 7b - 00 00 02 f4 00 00 e6 b1 00 00 00 1a 00 03 00 e8 - 00 01 00 83 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 - --> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [media query] -<- [58 octets] - - 01 XX 00 00 00 00 00 04 06 WW WW MM MM 01 00 00 [MM MM == max printable size of media, 09 82 == 2434 for 6x8!] - 00 00 06 WW WW 09 ba 01 02 00 00 00 06 WW WW HH [09 ba == 2940 == cut area?] - HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == 0b or 03 == media type?] - 00 00 00 00 00 00 00 00 00 00 - - --> 03 1b 43 48 43 0a 00 01 00 01 WW WW HH HH 06 01 [ image header, modified, see above ] - 01 - -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 a2 7b 00 00 a2 7b - 00 00 02 f4 00 00 e6 b1 00 00 00 1a 00 03 00 e8 - 00 01 00 83 01 00 00 01 00 00 00 01 00 00 00 00 [ note the "01" after "83", and the extra two "01"s ] - 00 00 00 - --> [4K of plane data] --> ... --> [4K of plane data] --> [remainder of plane data + 17 bytes of 0xff] - --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query] -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 a2 7c 00 00 a2 7c [ note a2 7c vs a2 7b ] - 00 00 01 7a 00 00 e6 b3 00 00 00 1a 00 03 00 e8 [ note 01 7a vs 02 f4, e6 b3 vs e6 b1 ] - 00 01 00 83 01 00 00 00 00 01 00 01 00 00 00 00 [ note the moved '01' in the middle ] - 00 00 00 - --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [ status query ] -<- [51 octets, repeats] - - Possible Serial number query: - --> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00 -<- [32 octets] - - 00 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [[ Pascal string? ]] - 20 20 20 20 20 20 20 20 36 30 34 33 4d 32 38 31 [[ ..." 6043M281" ]] - --> 03 1b 43 48 43 0c 54 4f 4e 45 65 00 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - [[ Followed by reset. ]] - - Read tone curve data: - --> 03 1b 43 48 43 0c 54 4f 4e 45 72 01 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - --> 03 1b 43 48 43 0c 54 4f 4e 45 20 -<- [64 octets] - - 81 01 07 07 27 07 72 07 c8 07 f8 07 22 07 48 08 - 68 08 88 08 b3 08 db 08 f7 08 09 09 2e 09 49 09 - 65 09 80 09 aa 09 ca 09 e2 09 fa 09 12 0a 32 0a - 42 0a 66 0a 81 0a 9a 0a c3 0a d9 0a ee 0a 04 0b - --> 03 1b 43 48 43 0c 54 4f 4e 45 20 -<- [64 octets] - - [[ repeats for total of 24 packets. total of 1.5KiB. ]] - - Write tone curve data: - --> 03 1b 43 48 43 0c 54 4f 4e 45 77 01 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - --> 03 00 00 46 06 53 06 c0 06 07 07 37 07 5d 07 87 - 07 a1 07 c8 07 08 08 08 08 08 08 48 08 68 08 88 - 08 a9 08 b9 08 d9 08 f9 08 12 09 2e 09 49 09 70 - 09 89 08 99 09 ba 09 ca 08 da 09 0a 0a 24 0a 38 -<- [51 octets] - - [[ typical status response ]] - --> 03 0a 53 0a 66 0a 81 0a ... - .... --> 03 cf 38 0a 39 3d 39 79 39 96 39 b6 39 fb 39 01 - 34 0a 34 08 3a 0c 1a 10 3a -<- [51 octets] - - [[ typical status response ]] - - [[ total of 24 packets * 64, and then one final packet of 25: 1562 total. ]] - [[ It apepars the extra 25 bytes are to compensate for the leading '03' on - each of the 25 URBs. ]] - - *********************************************************************** - - Kodak 6850 Printer Comms: - - [[file header]] 03 1b 43 48 43 0a 00 XX 00 CC WW WW HH HH SS LL UU - - Note: 'XX' paper code is 0x04 for 4x6, 0x06 for 6x8 on the 6850! - - (See above for details on all other fields) - --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query] -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 21 75 00 00 08 52 - 00 00 01 29 00 00 3b 0a 00 00 00 0e 00 03 02 90 - 00 01 02 1d 03 00 00 00 00 01 00 01 00 00 00 00 - 00 00 00 - -> 03 1b 43 48 43 4c 00 00 00 00 00 00 00 00 00 00 [???] <- [51 octets] @@ -1084,199 +1219,4 @@ struct dyesub_backend kodak6800_backend = { 00 01 02 1c 00 00 00 00 00 01 00 01 00 00 00 00 00 00 00 --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query] -<- [51 octets -- same as status query before ] - --> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [media query] -<- [68 octets] - - 01 XX 00 00 00 00 00 06 06 WW WW MM MM 01 00 00 [MM MM == max printable size of media, 09 82 == 2434 for 6x8!] - 00 00 06 WW WW 09 ba 01 02 01 00 00 06 WW WW HH [09 ba == 2940 == cut area?] - HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == 0b or 03 == media type?] - 06 WW WW 09 ba 01 05 01 00 00 06 WW WW HH HH 01 - 04 00 00 00 - --> 03 1b 43 48 43 0a 00 04 00 01 07 34 04 d8 06 01 [ image header, modified, see above ] - 01 - -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 21 75 00 00 08 52 - 00 00 01 29 00 00 3b 0a 00 00 00 0e 00 03 02 90 - 00 01 02 1d 04 00 00 01 00 00 00 01 00 00 00 00 [ note the "04" after "1d", and the moved '01' ] - 00 00 00 - --> [4K of plane data] --> ... --> [4K of plane data] --> [remainder of plane data] - --> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query] -<- [51 octets] - - 01 02 01 00 00 00 00 00 00 00 21 76 00 00 08 53 [ note 21 76, 08 53, 01 2a incremented by 1 ] - 00 00 01 2a 00 00 3b 0c 00 00 00 0e 00 03 02 90 [ note 3b 0c incremeted by 2 ] - 00 01 02 1d 04 00 00 01 00 00 00 01 00 00 00 00 - 00 00 00 - - Possible Serial number query: - --> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00 - 00 -<- [32 octets] - - 00 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [[ Pascal string? ]] - 20 20 20 20 20 20 20 20 36 30 39 37 4b 53 34 39 [[ ..." 6097KS49" ]] - - Read tone curve data: - --> 03 1b 43 48 43 0c 54 4f 4e 45 72 01 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - --> 03 1b 43 48 43 0c 54 4f 4e 45 20 -<- [64 octets] - - 81 01 07 07 27 07 72 07 c8 07 f8 07 22 07 48 08 - 68 08 88 08 b3 08 db 08 f7 08 09 09 2e 09 49 09 - 65 09 80 09 aa 09 ca 09 e2 09 fa 09 12 0a 32 0a - 42 0a 66 0a 81 0a 9a 0a c3 0a d9 0a ee 0a 04 0b - --> 03 1b 43 48 43 0c 54 4f 4e 45 20 -<- [64 octets] - - [[ repeats for total of 24 packets. total of 1.5KiB. ]] - --> 03 1b 43 48 43 0c 54 4f 4e 45 65 00 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - - Maybe this resets the calibration table: - --> 03 1b 43 48 43 05 00 00 00 00 00 00 00 00 00 00 [???] -<- [34 octets] - - 01 00 04 00 00 00 01 00 01 00 02 00 00 00 01 00 - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 - - Write tone curve data: - --> 03 1b 43 48 43 0c 54 4f 4e 45 77 01 00 00 00 00 -<- [51 octets] - - [[ typical status response ]] - --> 03 00 00 46 06 53 06 c0 06 07 07 37 07 5d 07 87 - 07 a1 07 c8 07 08 08 08 08 08 08 48 08 68 08 88 - 08 a9 08 b9 08 d9 08 f9 08 12 09 2e 09 49 09 70 - 09 89 08 99 09 ba 09 ca 08 da 09 0a 0a 24 0a 38 -<- [51 octets] - - [[ typical status response ]] - --> 03 0a 53 0a 66 0a 81 0a ... - .... --> 03 cf 38 0a 39 3d 39 79 39 96 39 b6 39 fb 39 01 - 34 0a 34 08 3a 0c 1a 10 3a -<- [51 octets] - - [[ typical status response ]] - - [[ total of 24 packets * 64, and then one final packet of 25: 1562 total. ]] - [[ It apepars the extra 25 bytes are to compensate for the leading '03' on - each of the 25 URBs. ]] - - Also seen on the 6850: - -DEBUG: readback: - -01 02 03 00 00 00 01 00 00 01 5f 6f 00 01 5f 6f -00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 -00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 - -INIT/??? -DEBUG: readback: - -01 02 03 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f -00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 -00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 - -??? 6x8c - -DEBUG: readback: - -01 02 01 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f -00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 -00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 - -Seen on the 6850 with no media loaded: - -01 02 02 00 00 00 10 00 00 00 5d 1d 00 00 5d 1d -00 00 00 00 00 00 b7 cc 00 00 00 00 00 03 02 8c -00 01 02 1c 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 - -Seen on 6850 with 6R media (6x8) while offline: - -01 02 03 00 00 00 03 00 00 00 5d 1f 00 00 5d 1f -00 00 00 01 00 00 b7 d3 00 00 00 5c 00 03 02 8c -00 01 02 1c 00 00 00 00 00 01 00 01 00 00 00 00 -00 00 00 - -*/ - -/* Control Error codes: - -1 EEPROM error 1 - -2 EEPROM error 2 - -3 EEPROM error 3 - -4 DSP Inactive - -5 DSPCnt Inactive - -6 Download Sum Check Error (MainCnt) - -7 Download error (MainCnt) - -8 Download Sum Check Error (DSPCnt) - -9 Download Error (DSPCnt) - -10 ASCI error - -11 DRAM controller error - -12 User Tone Curve Table Sum Check error - -13 User Tone Curve Table Write error - -14 Current Tone Curve Table Sum Check error - -15 Current Tone Curve Table Write error - -16 User Tone Curve Table Sum Check error - -17 User Tone Curve Table Read-out error - -18 Current Tone Curve Table Sum Check error - -19 Current Tone Curve Table Read-out error - -20 User Tone Curve Reset error - -21 MainCnt Inactive - -25 ??? - -41 Comunication Error Main and DSP - */ diff --git a/backend_shinkos1245.c b/backend_shinkos1245.c index f254ab5..df9d108 100644 --- a/backend_shinkos1245.c +++ b/backend_shinkos1245.c @@ -97,7 +97,7 @@ struct shinkos1245_cmd_getid { struct shinkos1245_resp_getid { uint8_t id; /* 0x00 */ uint8_t data[23]; /* padded with 0x20 (space) */ - uint8_t reserved[8]; + uint8_t reserved[8]; // XXX actual serial number? } __attribute__((packed)); /* Set Printer ID -- Returns Status */ @@ -534,7 +534,7 @@ static int shinkos1245_get_media(struct shinkos1245_ctx *ctx) static int shinkos1245_get_printerid(struct shinkos1245_ctx *ctx, struct shinkos1245_resp_getid *resp) { - struct shinkos1245_cmd_getstatus cmd; + struct shinkos1245_cmd_getid cmd; int ret, num; shinkos1245_fill_hdr(&cmd.hdr); @@ -884,13 +884,13 @@ static void shinkos1245_dump_status(struct shinkos1245_resp_status *sts) // INFO("USB TypeFlag: %02x\n", sts->counters.control_flag); INFO("Bank 1 ID: %d\n", sts->counters2.bank1_id); - INFO("\tPrints: %d/%d (%d complete)\n", - sts->counters2.bank1_remain, sts->counters2.bank1_spec, - sts->counters2.bank1_complete); + INFO("\tPrints: %d/%d complete\n", + be16_to_cpu(sts->counters2.bank1_complete), + be16_to_cpu(sts->counters2.bank1_spec)); INFO("Bank 2 ID: %d\n", sts->counters2.bank2_id); - INFO("\tPrints: %d/%d (%d complete)\n", - sts->counters2.bank2_remain, sts->counters2.bank2_spec, - sts->counters2.bank2_complete); + INFO("\tPrints: %d/%d complete\n", + be16_to_cpu(sts->counters2.bank2_complete), + be16_to_cpu(sts->counters2.bank2_spec)); switch (sts->curve_status) { case CURVE_TABLE_STATUS_INITIAL: