diff --git a/README b/README index cee7c8d..3311b1c 100644 --- a/README +++ b/README @@ -114,6 +114,10 @@ DEVICE_URI=someuri \ gutenprint52+usb job-id user title num-copies options [ filename ] + The backend generates output for CUPS to parse, including logging + print counts, and if the printer supports it, reporting media type and + remaining media counts. + *************************************************************************** Standalone usage: diff --git a/backend_canonselphy.c b/backend_canonselphy.c index eb66006..3ef56d3 100644 --- a/backend_canonselphy.c +++ b/backend_canonselphy.c @@ -91,9 +91,22 @@ 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 */ - int (*error_detect)(uint8_t *rdbuf); + int (*error_detect)(uint8_t *rdbuf); + char *(*pgcode_names)(uint8_t pgcode); }; +static char *generic_pgcode_names(uint8_t pgcode) +{ + switch(pgcode & 0xf) { + case 0x01: return "P"; + case 0x02: return "L"; + case 0x03: return "C"; + case 0x04: return "W"; + case 0x0f: return "None"; + default: return "Unknown"; + } +} + static int es1_error_detect(uint8_t *rdbuf) { if (rdbuf[1] == 0x01) { @@ -105,9 +118,11 @@ static int es1_error_detect(uint8_t *rdbuf) return 1; } else if (rdbuf[4] == 0x01 && rdbuf[5] == 0xff && rdbuf[6] == 0xff && rdbuf[7] == 0xff) { + ATTR("marker-levels=%d\n", 0); ERROR("No media loaded!\n"); return 1; } else if (rdbuf[0] == 0x0f) { + ATTR("marker-levels=%d\n", 0); ERROR("Out of media!\n"); return 1; } @@ -127,11 +142,13 @@ static int es2_error_detect(uint8_t *rdbuf) rdbuf[4] == 0x05 && rdbuf[5] == 0x05 && rdbuf[6] == 0x02) { + ATTR("marker-levels=%d\n", 0); ERROR("No media loaded!\n"); return 1; } if (rdbuf[0] == 0x14) { + ATTR("marker-levels=%d\n", 0); ERROR("Out of media!\n"); return 1; } @@ -145,6 +162,7 @@ static int es3_error_detect(uint8_t *rdbuf) if (rdbuf[10] == 0x0f) { ERROR("Communications Error\n"); } else if (rdbuf[10] == 0x01) { + ATTR("marker-levels=%d\n", 0); ERROR("No media loaded!\n"); } else { ERROR("Unknown error - %02x + %02x\n", @@ -153,6 +171,7 @@ static int es3_error_detect(uint8_t *rdbuf) return 1; } else if (rdbuf[8] == 0x03 && rdbuf[10] == 0x02) { + ATTR("marker-levels=%d\n", 0); ERROR("No media loaded!\n"); return 1; } else if (rdbuf[8] == 0x08 && @@ -182,10 +201,12 @@ static int es40_error_detect(uint8_t *rdbuf) if (rdbuf[3] == 0x01) ERROR("Generic communication error\n"); - else if (rdbuf[3] == 0x32) + else if (rdbuf[3] == 0x32) { + ATTR("marker-levels=%d\n", 0); ERROR("Cover open or media empty!\n"); - else + } else ERROR("Unknown error - %02x\n", rdbuf[3]); + return 1; } @@ -200,15 +221,18 @@ static int cp790_error_detect(uint8_t *rdbuf) ERROR("No paper tray loaded!\n"); return 1; } else if (rdbuf[3]) { - if ((rdbuf[3] & 0xf) == 0x02) // 0x12 0x22 + if ((rdbuf[3] & 0xf) == 0x02) { // 0x12 0x22 + ATTR("marker-levels=%d\n", 0); ERROR("No paper tray loaded!\n"); - else if ((rdbuf[3] & 0xf) == 0x03) // 0x13 0x23 + } else if ((rdbuf[3] & 0xf) == 0x03) { // 0x13 0x23 + ATTR("marker-levels=%d\n", 0); ERROR("Empty paper tray or feed error!\n"); - else if (rdbuf[3] == 0x11) + } else if (rdbuf[3] == 0x11) ERROR("Paper feed error!\n"); - else if (rdbuf[3] == 0x21) + else if (rdbuf[3] == 0x21) { + ATTR("marker-levels=%d\n", 0); ERROR("Ribbon depleted!\n"); - else + } else ERROR("Unknown error - %02x\n", rdbuf[3]); return 1; } @@ -216,19 +240,28 @@ static int cp790_error_detect(uint8_t *rdbuf) return 0; } +static char *cp10_pgcode_names(uint8_t pgcode) +{ + switch (pgcode) { + default: return "C"; + }; +} static int cp10_error_detect(uint8_t *rdbuf) { if (!rdbuf[2]) return 0; - if (rdbuf[2] == 0x80) + if (rdbuf[2] == 0x80) { + ATTR("marker-levels=%d\n", 0); ERROR("No ribbon loaded\n"); - else if (rdbuf[2] == 0x08) + } else if (rdbuf[2] == 0x08) { + ATTR("marker-levels=%d\n", 0); ERROR("Ribbon depleted!\n"); - else if (rdbuf[2] == 0x01) + } else if (rdbuf[2] == 0x01) { + ATTR("marker-levels=%d\n", 0); ERROR("No paper loaded!\n"); - else + } else ERROR("Unknown error - %02x\n", rdbuf[2]); return 1; } @@ -238,13 +271,15 @@ static int cpxxx_error_detect(uint8_t *rdbuf) if (!rdbuf[2]) return 0; - if (rdbuf[2] == 0x01) + if (rdbuf[2] == 0x01) { + ATTR("marker-levels=%d\n", 0); ERROR("Paper feed problem!\n"); - else if (rdbuf[2] == 0x04) + } else if (rdbuf[2] == 0x04) ERROR("Ribbon problem!\n"); - else if (rdbuf[2] == 0x08) + else if (rdbuf[2] == 0x08) { + ATTR("marker-levels=%d\n", 0); ERROR("Ribbon depleted!\n"); - else + } else ERROR("Unknown error - %02x\n", rdbuf[2]); return 1; } @@ -264,6 +299,7 @@ static struct printer_data selphy_printers[] = { .pgcode_offset = 3, .paper_code_offset = 6, .error_detect = es1_error_detect, + .pgcode_names = generic_pgcode_names, }, { .type = P_ES2_20, .model = "SELPHY ES2/ES20", @@ -279,6 +315,7 @@ static struct printer_data selphy_printers[] = { .pgcode_offset = 2, .paper_code_offset = 4, .error_detect = es2_error_detect, + .pgcode_names = generic_pgcode_names, }, { .type = P_ES3_30, .model = "SELPHY ES3/ES30", @@ -294,6 +331,7 @@ static struct printer_data selphy_printers[] = { .pgcode_offset = 2, .paper_code_offset = -1, .error_detect = es3_error_detect, + .pgcode_names = NULL, }, { .type = P_ES40, .model = "SELPHY ES40", @@ -309,6 +347,7 @@ static struct printer_data selphy_printers[] = { .pgcode_offset = 2, .paper_code_offset = 11, .error_detect = es40_error_detect, + .pgcode_names = generic_pgcode_names, }, { .type = P_CP790, .model = "SELPHY CP790", @@ -321,10 +360,10 @@ static struct printer_data selphy_printers[] = { .done_c_readback = { 0x00, 0x00, 0x10, 0x00, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }, .clear_error = { 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, .clear_error_len = 12, - // .paper_codes .pgcode_offset = 2, .paper_code_offset = -1, /* Uses a different technique */ .error_detect = cp790_error_detect, + .pgcode_names = generic_pgcode_names, }, { .type = P_CP_XXX, .model = "SELPHY CP Series (!CP-10/CP790)", @@ -337,10 +376,10 @@ static struct printer_data selphy_printers[] = { .done_c_readback = { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x00, 0x00, 0x00, 0x00, -1 }, .clear_error = { 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, .clear_error_len = 12, - // .paper_codes .pgcode_offset = 3, .paper_code_offset = 6, .error_detect = cpxxx_error_detect, + .pgcode_names = generic_pgcode_names, }, { .type = P_CP10, .model = "SELPHY CP-10", @@ -353,10 +392,10 @@ static struct printer_data selphy_printers[] = { .done_c_readback = { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, .clear_error = { 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, .clear_error_len = 12, - // .paper_codes - .pgcode_offset = -1, + .pgcode_offset = 2, .paper_code_offset = -1, .error_detect = cp10_error_detect, + .pgcode_names = cp10_pgcode_names, }, { .type = -1 }, }; @@ -763,6 +802,13 @@ static int canonselphy_main_loop(void *vctx, int copies) { if (ret < 0) return CUPS_BACKEND_FAILED; + ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); + ATTR("marker-high-levels=100\n"); + ATTR("marker-low-levels=10\n"); + ATTR("marker-names='%s'\n", ctx->printer->pgcode_names? ctx->printer->pgcode_names(rdbuf[ctx->printer->paper_code_offset]) : "Unknown"); + ATTR("marker-types=ribbonWax\n"); + ATTR("marker-levels=%d\n", -3); /* ie Unknown but OK */ + top: if (state != last_state) { @@ -983,7 +1029,7 @@ static int canonselphy_cmdline_arg(void *vctx, int argc, char **argv) struct dyesub_backend canonselphy_backend = { .name = "Canon SELPHY CP/ES", - .version = "0.90", + .version = "0.91", .uri_prefix = "canonselphy", .cmdline_arg = canonselphy_cmdline_arg, .init = canonselphy_init, diff --git a/backend_dnpds40.c b/backend_dnpds40.c index 4414b34..369b457 100644 --- a/backend_dnpds40.c +++ b/backend_dnpds40.c @@ -1195,8 +1195,8 @@ static int dnpds40_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); + ATTR("marker-names='%s'\n", dnpds40_media_types(ctx->media)); + ATTR("marker-types=ribbonWax\n"); } top: diff --git a/backend_kodak605.c b/backend_kodak605.c index 2acaac9..d2ed9ae 100644 --- a/backend_kodak605.c +++ b/backend_kodak605.c @@ -148,6 +148,20 @@ static char *bank_statuses(uint8_t v) } } +static const char *kodak68xx_mediatypes(int type) +{ + switch(type) { + case KODAK68x0_MEDIA_NONE: + return "No media"; + case KODAK68x0_MEDIA_6R: + case KODAK68x0_MEDIA_6TR2: + return "Kodak 6R"; + default: + return "Unknown"; + } + return "Unknown"; +} + #define CMDBUF_LEN 4 /* Private data stucture */ @@ -380,8 +394,8 @@ static int kodak605_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); + ATTR("marker-names='%s'\n", kodak68xx_mediatypes(ctx->media->type)); + ATTR("marker-types=ribbonWax\n"); INFO("Waiting for printer idle\n"); @@ -506,7 +520,7 @@ static void kodak605_dump_status(struct kodak605_ctx *ctx, struct kodak605_statu INFO("\t Remaining : Unknown\n"); } } - + INFO("Donor : %d%%\n", sts->donor); } diff --git a/backend_kodak6800.c b/backend_kodak6800.c index b7bb245..0604c81 100644 --- a/backend_kodak6800.c +++ b/backend_kodak6800.c @@ -240,6 +240,20 @@ struct kodak6800_ctx { uint8_t last_donor; }; +static const char *kodak68xx_mediatypes(int type) +{ + switch(type) { + case KODAK68x0_MEDIA_NONE: + return "No media"; + case KODAK68x0_MEDIA_6R: + case KODAK68x0_MEDIA_6TR2: + return "Kodak 6R"; + default: + return "Unknown"; + } + return "Unknown"; +} + /* Baseline commands */ static int kodak6800_do_cmd(struct kodak6800_ctx *ctx, void *cmd, int cmd_len, @@ -262,6 +276,8 @@ static int kodak6800_do_cmd(struct kodak6800_ctx *ctx, return 0; } + + static void kodak68x0_dump_mediainfo(struct kodak68x0_media_readback *media) { int i; @@ -1124,8 +1140,8 @@ static int kodak6800_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); + ATTR("marker-names='%s'\n", kodak68xx_mediatypes(ctx->media->type)); + ATTR("marker-types=ribbonWax\n"); INFO("Waiting for printer idle\n"); diff --git a/backend_mitsu70x.c b/backend_mitsu70x.c index e2d3e30..dc37c10 100644 --- a/backend_mitsu70x.c +++ b/backend_mitsu70x.c @@ -62,14 +62,19 @@ struct mitsu70x_ctx { int matte; - uint16_t jobid; + uint16_t jobid; uint16_t rows; uint16_t cols; + + uint16_t last_donor_l; + uint16_t last_donor_u; + int num_decks; + #ifdef ENABLE_CORRTABLES struct mitsu70x_corrdata *corrdata; struct mitsu70x_corrdatalens *corrdatalens; char *laminatefname; -#endif +#endif }; /* Printer data structures */ @@ -197,7 +202,7 @@ struct mitsu70x_status_deck { uint8_t temperature; uint8_t error_status[3]; uint8_t rsvd_a[10]; - + uint8_t media_brand; uint8_t media_type; uint8_t rsvd_b[2]; @@ -245,7 +250,7 @@ struct mitsu70x_hdr { uint8_t speed; uint8_t zero1[7]; - uint8_t deck; + uint8_t deck; /* 0 = default, 1 = lower, 2 = upper */ uint8_t zero2[7]; uint8_t laminate; /* 00 == on, 01 == off */ uint8_t laminate_mode; @@ -548,6 +553,20 @@ static char *mitsu70x_errors(uint8_t *err) return "Unknown error"; } +static const char *mitsu70x_media_types(uint8_t brand, uint8_t type) +{ + if (brand == 0xff && type == 0x02) + return "CKD746 (4x6)"; + else if (brand == 0xff && type == 0x0f) + return "CKD768 (6x8)"; + else if (brand == 0x61 && type == 0x8f) + return "CKK76R (6x8)"; + else if (brand == 0x6c && type == 0x8f) + return "CKK76R (6x8)"; + else + return "Unknown"; +} + #define CMDBUF_LEN 512 #define READBACK_LEN 256 @@ -583,7 +602,8 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev, ctx->type = lookup_printer_type(&mitsu70x_backend, desc.idVendor, desc.idProduct); -} + + ctx->last_donor_l = ctx->last_donor_u = 65535;} static void mitsu70x_teardown(void *vctx) { struct mitsu70x_ctx *ctx = vctx; @@ -639,7 +659,7 @@ repeat: return CUPS_BACKEND_CANCEL; } -#ifdef ENABLE_CORRTABLES +#ifdef ENABLE_CORRTABLES /* Figure out the correction data table to use */ if (ctx->type == P_MITSU_D70X) { struct mitsu70x_hdr *print = (struct mitsu70x_hdr *) &hdr[512]; @@ -774,7 +794,7 @@ static int mitsu70x_get_jobstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_jobs ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp)); return 4; } - + return 0; } @@ -807,7 +827,7 @@ static int mitsu70x_get_jobs(struct mitsu70x_ctx *ctx, struct mitsu70x_jobs *res ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp)); return 4; } - + return 0; } @@ -928,9 +948,10 @@ static int mitsu70x_set_sleeptime(struct mitsu70x_ctx *ctx, uint8_t time) static int mitsu70x_main_loop(void *vctx, int copies) { struct mitsu70x_ctx *ctx = vctx; struct mitsu70x_jobstatus jobstatus; + struct mitsu70x_printerstatus_resp resp; struct mitsu70x_jobs jobs; struct mitsu70x_hdr *hdr = (struct mitsu70x_hdr*) (ctx->databuf + sizeof(struct mitsu70x_hdr)); - + int ret; if (!ctx) @@ -938,28 +959,6 @@ static int mitsu70x_main_loop(void *vctx, int copies) { INFO("Waiting for printer idle...\n"); - ret = mitsu70x_get_jobs(ctx, &jobs); - if (ret) - return CUPS_BACKEND_FAILED; - -#if 0 - /* Tell CUPS about the consumables we report */ - if (ctx->type == P_MITSU_D70X && - ctx->num_decks == 2) { - ATTR("marker-colors=#00FFFF#FF00FF#FFFF00,#00FFFF#FF00FF#FFFF00\n"); - ATTR("marker-high-levels=100,100\n"); - ATTR("marker-low-levels=10,10\n"); - ATTR("marker-names=Ribbon,Ribbon\n"); - ATTR("marker-types=ink-ribbon,ribbon\n"); - } else { - ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); - ATTR("marker-high-levels=100\n"); - ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); - } -#endif - top: /* Query job status for jobid 0 (global) */ ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000); @@ -991,7 +990,7 @@ top: sleep(1); goto top; } - + /* See if we hit a printer error. */ if (jobstatus.error_status[0]) { ERROR("%s/%s -> %s: %02x/%02x/%02x\n", @@ -1004,11 +1003,43 @@ top: return CUPS_BACKEND_STOP; } + if (ctx->num_decks) + goto skip_status; + + /* Tell CUPS about the consumables we report */ + ret = mitsu70x_get_printerstatus(ctx, &resp); + if (ret) + return CUPS_BACKEND_FAILED; + + if (resp.upper.mecha_status[0] != MECHA_STATUS_INIT) + ctx->num_decks = 2; + else + ctx->num_decks = 1; + + if (ctx->type == P_MITSU_D70X && + ctx->num_decks == 2) { + ATTR("marker-colors=#00FFFF#FF00FF#FFFF00,#00FFFF#FF00FF#FFFF00\n"); + ATTR("marker-high-levels=100,100\n"); + ATTR("marker-low-levels=10,10\n"); + ATTR("marker-names='\"%s\"','\"%s\"'\n", + mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type), + mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type)); + ATTR("marker-types=ribbonWax,ribbonWax\n"); + } else { + ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); + ATTR("marker-high-levels=100\n"); + ATTR("marker-low-levels=10\n"); + ATTR("marker-names='%s'\n", + mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type)); + ATTR("marker-types=ribbonWax\n"); + } + +skip_status: /* Perform memory status query */ { struct mitsu70x_memorystatus_resp memory; INFO("Checking Memory availability\n"); - + ret = mitsu70x_get_memorystatus(ctx, &memory); if (ret) return CUPS_BACKEND_FAILED; @@ -1026,6 +1057,10 @@ top: } /* Make sure we don't have any jobid collisions */ + ret = mitsu70x_get_jobs(ctx, &jobs); + if (ret) + return CUPS_BACKEND_FAILED; + while (ctx->jobid == be16_to_cpu(jobs.jobid_0) || ctx->jobid == be16_to_cpu(jobs.jobid_1)) { ctx->jobid++; @@ -1039,7 +1074,7 @@ top: /* Set deck */ if (ctx->type == P_MITSU_D70X) { hdr->deck = 0; /* D70 use automatic deck selection */ - // XXX alternatively route it based on state and media? */ + /* XXX alternatively route it based on state and media? */ } else { hdr->deck = 1; /* All others only have a "lower" deck. */ } @@ -1092,22 +1127,37 @@ top: INFO("Waiting for printer to acknowledge completion\n"); do { + uint16_t donor_u, donor_l; + sleep(1); -#if 0 - // XXXX query printerstatus and dump deck remain/capacity.. + ret = mitsu70x_get_printerstatus(ctx, &resp); + if (ret) + return CUPS_BACKEND_FAILED; + + donor_l = be16_to_cpu(resp.lower.remain) * 100 / be16_to_cpu(resp.lower.capacity); + if (ctx->type == P_MITSU_D70X && ctx->num_decks == 2) { - ATTR("marker-levels=XXX,YYY\n"); + donor_u = be16_to_cpu(resp.upper.remain) * 100 / be16_to_cpu(resp.upper.capacity); + if (donor_l != ctx->last_donor_l || + donor_u != ctx->last_donor_u) { + ctx->last_donor_l = donor_l; + ctx->last_donor_u = donor_u; + ATTR("marker-levels=%d,%d\n", donor_l, donor_u); + } } else { - ATTR("marker-levels=XXX\n"); + if (donor_l != ctx->last_donor_l) { + ctx->last_donor_l = donor_l; + ATTR("marker-levels=%d\n", donor_l); + } } -#endif + /* Query job status for our used jobid */ ret = mitsu70x_get_jobstatus(ctx, &jobstatus, ctx->jobid); if (ret) return CUPS_BACKEND_FAILED; - + /* See if we hit a printer error. */ if (jobstatus.error_status[0]) { ERROR("%s/%s -> %s: %02x/%02x/%02x\n", @@ -1181,49 +1231,38 @@ static void mitsu70x_dump_printerstatus(struct mitsu70x_printerstatus_resp *resp buf[6] = 0; INFO("Component #%d ID: %s (checksum %04x)\n", i, buf, be16_to_cpu(resp->vers[i].checksum)); - } - if (resp->upper.mecha_status[0] == MECHA_STATUS_INIT) { /* IOW, Not present */ - INFO("Mechanical Status: %s\n", - mitsu70x_mechastatus(resp->lower.mecha_status)); - if (resp->lower.error_status[0]) { - INFO("Error Status: %s/%s -> %s\n", - mitsu70x_errorclass(resp->lower.error_status), - mitsu70x_errors(resp->lower.error_status), - mitsu70x_errorrecovery(resp->lower.error_status)); - } - INFO("Media type: %02x/%02x\n", - resp->lower.media_brand, - resp->lower.media_type); - INFO("Prints remaining: %03d/%03d\n", - be16_to_cpu(resp->lower.remain), - be16_to_cpu(resp->lower.capacity)); - } else { - INFO("Mechanical Status: Upper: %s\n" - " Lower: %s\n", - mitsu70x_mechastatus(resp->upper.mecha_status), - mitsu70x_mechastatus(resp->lower.mecha_status)); + } + + INFO("Lower Mechanical Status: %s\n", + mitsu70x_mechastatus(resp->lower.mecha_status)); + if (resp->lower.error_status[0]) { + INFO("Lower Error Status: %s/%s -> %s\n", + mitsu70x_errorclass(resp->lower.error_status), + mitsu70x_errors(resp->lower.error_status), + mitsu70x_errorrecovery(resp->lower.error_status)); + } + INFO("Lower Media type: %s (%02x/%02x)\n", + mitsu70x_media_types(resp->lower.media_brand, resp->lower.media_type), + resp->lower.media_brand, + resp->lower.media_type); + INFO("Lower Prints remaining: %03d/%03d\n", + be16_to_cpu(resp->lower.remain), + be16_to_cpu(resp->lower.capacity)); + + if (resp->upper.mecha_status[0] != MECHA_STATUS_INIT) { + INFO("Upper Mechanical Status: %s\n", + mitsu70x_mechastatus(resp->upper.mecha_status)); if (resp->upper.error_status[0]) { INFO("Upper Error Status: %s/%s -> %s\n", mitsu70x_errorclass(resp->upper.error_status), mitsu70x_errors(resp->upper.error_status), mitsu70x_errorrecovery(resp->upper.error_status)); - } - if (resp->lower.error_status[0]) { - INFO("Lower Error Status: %s/%s -> %s\n", - mitsu70x_errorclass(resp->lower.error_status), - mitsu70x_errors(resp->lower.error_status), - mitsu70x_errorrecovery(resp->lower.error_status)); - } - INFO("Media type: Lower: %02x/%02x\n" - " Upper: %02x/%02x\n", - resp->lower.media_brand, - resp->lower.media_type, + } + INFO("Upper Media type: %s (%02x/%02x)\n", + mitsu70x_media_types(resp->upper.media_brand, resp->upper.media_type), resp->upper.media_brand, resp->upper.media_type); - INFO("Prints remaining: Lower: %03d/%03d\n" - " Upper: %03d/%03d\n", - be16_to_cpu(resp->lower.remain), - be16_to_cpu(resp->lower.capacity), + INFO("Upper Prints remaining: %03d/%03d\n", be16_to_cpu(resp->upper.remain), be16_to_cpu(resp->upper.capacity)); } @@ -1248,7 +1287,7 @@ static int mitsu70x_query_status(struct mitsu70x_ctx *ctx) INFO("JOB1 status : %s\n", mitsu70x_jobstatuses(jobs.job1_status)); // XXX are there more? } - + return ret; } @@ -1267,12 +1306,12 @@ static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_u if (buf_len > 6) /* Will we ever have a buffer under 6 bytes? */ buf_len = 6; - + for (i = 0 ; i < buf_len ; i++) { *buf++ = le16_to_cpu(resp.serno[i]) & 0x7f; } *buf = 0; /* Null-terminate the returned string */ - + return ret; } @@ -1318,7 +1357,7 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv) /* Exported */ struct dyesub_backend mitsu70x_backend = { .name = "Mitsubishi CP-D70/D707/K60/D80", - .version = "0.39WIP", + .version = "0.40WIP", .uri_prefix = "mitsu70x", .cmdline_usage = mitsu70x_cmdline, .cmdline_arg = mitsu70x_cmdline_arg, diff --git a/backend_mitsu9550.c b/backend_mitsu9550.c index 26d2b53..3a84c9b 100644 --- a/backend_mitsu9550.c +++ b/backend_mitsu9550.c @@ -60,6 +60,7 @@ struct mitsu9550_ctx { uint16_t last_donor; uint16_t last_remain; + int marker_reported; }; /* Spool file structures */ @@ -155,6 +156,16 @@ struct mitsu9550_status2 { if (ret < 0) \ return CUPS_BACKEND_FAILED; \ \ + /* Tell CUPS about the consumables we report */ \ + if (!ctx->marker_reported) { \ + ctx->marker_reported = 1; \ + ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); \ + ATTR("marker-high-levels=100\n"); \ + ATTR("marker-low-levels=10\n"); \ + ATTR("marker-names='%s'\n", mitsu9550_media_types(media->type)); \ + ATTR("marker-types=ribbonWax\n"); \ + } \ + \ /* Sanity-check media response */ \ if (media->remain == 0 || media->max == 0) { \ ERROR("Printer out of media!\n"); \ @@ -334,6 +345,27 @@ static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int st return 0; } +static char *mitsu9550_media_types(uint8_t type) +{ + switch (type) { + case 0x01: + return "3.5x5"; + case 0x02: + return "4x6"; + case 0x03: + return "PC"; + case 0x04: + return "5x7"; + case 0x05: + return "6x9"; + case 0x06: + return "V"; + default: + return "Unknown"; + } + return NULL; +} + static int validate_media(int type, int cols, int rows) { switch(type) { case 0x01: /* 3.5x5 */ @@ -375,7 +407,7 @@ static int mitsu9550_main_loop(void *vctx, int copies) { struct mitsu9550_cmd cmd; uint8_t rdbuf[READBACK_LEN]; uint8_t *ptr; - + int ret; if (!ctx) @@ -387,17 +419,10 @@ static int mitsu9550_main_loop(void *vctx, int copies) { ptr = ctx->databuf; - /* Tell CUPS about the consumables we report */ - ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); - ATTR("marker-high-levels=100\n"); - ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); - top: if (ctx->type == P_MITSU_9550S) { int num; - + /* Send "unknown 1" command */ cmd.cmd[0] = 0x1b; cmd.cmd[1] = 0x53; @@ -406,7 +431,7 @@ top: if ((ret = send_data(ctx->dev, ctx->endp_down, (uint8_t*) &cmd, sizeof(cmd)))) return CUPS_BACKEND_FAILED; - + /* Send "unknown 2" command */ cmd.cmd[0] = 0x1b; cmd.cmd[1] = 0x4b; @@ -415,7 +440,7 @@ top: if ((ret = send_data(ctx->dev, ctx->endp_down, (uint8_t*) &cmd, sizeof(cmd)))) return CUPS_BACKEND_FAILED; - + ret = read_data(ctx->dev, ctx->endp_up, rdbuf, READBACK_LEN, &num); if (ret < 0) @@ -426,7 +451,7 @@ top: QUERY_STATUS(); /* Now it's time for the actual print job! */ - + if (ctx->type == P_MITSU_9550S) { cmd.cmd[0] = 0x1b; cmd.cmd[1] = 0x44; @@ -595,7 +620,7 @@ top: ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2 if (ret < 0) return CUPS_BACKEND_FAILED; - + ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status if (ret < 0) return CUPS_BACKEND_FAILED; @@ -617,33 +642,12 @@ top: sleep(1); } - + INFO("Print complete\n"); return CUPS_BACKEND_OK; } -static char *mitsu9550_media_types(uint8_t type) -{ - switch (type) { - case 0x01: - return "3.5x5"; - case 0x02: - return "4x6"; - case 0x03: - return "PC"; - case 0x04: - return "5x7"; - case 0x05: - return "6x9"; - case 0x06: - return "V"; - default: - return "Unknown"; - } - return NULL; -} - static void mitsu9550_dump_media(struct mitsu9550_media *resp) { INFO("Media type : %02x (%s)\n", @@ -660,7 +664,6 @@ static void mitsu9550_dump_status(struct mitsu9550_status *resp) be16_to_cpu(resp->copies)); INFO("Other status : %02x %02x %02x %02x %02x\n", resp->sts3, resp->sts4, resp->sts5, resp->sts6, resp->sts7); - } static int mitsu9550_query_media(struct mitsu9550_ctx *ctx) diff --git a/backend_shinkos2145.c b/backend_shinkos2145.c index e1a707b..9d9c1a9 100644 --- a/backend_shinkos2145.c +++ b/backend_shinkos2145.c @@ -182,7 +182,7 @@ struct s2145_print_cmd { #define PRINT_MEDIA_6x8 0x06 #define PRINT_MEDIA_2x6 0x07 -static char *print_medias (uint8_t v) { +static char *print_sizes (uint8_t v) { switch (v) { case PRINT_MEDIA_4x6: return "4x6"; @@ -909,7 +909,7 @@ static int get_fwinfo(struct shinkos2145_ctx *ctx) if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s2145_fwinfo_resp) - sizeof(struct s2145_status_hdr))) continue; - + INFO(" %s\t ver %02x.%02x\n", fwinfo_targets(i), resp->major, resp->minor); #if 0 @@ -940,7 +940,7 @@ static int get_errorlog(struct shinkos2145_ctx *ctx) ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd)); return ret; } - + if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s2145_errorlog_resp) - sizeof(struct s2145_status_hdr))) return -2; @@ -948,13 +948,13 @@ static int get_errorlog(struct shinkos2145_ctx *ctx) for (i = 0 ; i < resp->count ; i++) { INFO(" %02d: @ %08u prints : 0x%02x/0x%02x (%s)\n", i, le32_to_cpu(resp->items[i].print_counter), - resp->items[i].major, resp->items[i].minor, + resp->items[i].major, resp->items[i].minor, error_codes(resp->items[i].major, resp->items[i].minor)); } return 0; } -static int get_mediainfo(struct shinkos2145_ctx *ctx) +static int get_mediainfo(struct shinkos2145_ctx *ctx) { struct s2145_cmd_hdr cmd; struct s2145_mediainfo_resp *resp = (struct s2145_mediainfo_resp *) rdbuf; @@ -971,23 +971,23 @@ static int get_mediainfo(struct shinkos2145_ctx *ctx) ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd)); return ret; } - + if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s2145_mediainfo_resp) - sizeof(struct s2145_status_hdr))) return -2; INFO("Supported Media Information: %d entries:\n", resp->count); for (i = 0 ; i < resp->count ; i++) { INFO(" %02d: C 0x%02x (%s), %04dx%04d, M 0x%02x (%s), P 0x%02x (%s)\n", i, - resp->items[i].code, print_medias(resp->items[i].code), + resp->items[i].code, print_sizes(resp->items[i].code), le16_to_cpu(resp->items[i].columns), - le16_to_cpu(resp->items[i].rows), + le16_to_cpu(resp->items[i].rows), resp->items[i].media_type, media_types(resp->items[i].media_type), resp->items[i].print_type, print_methods(resp->items[i].print_type)); } return 0; } -static int get_user_string(struct shinkos2145_ctx *ctx) +static int get_user_string(struct shinkos2145_ctx *ctx) { struct s2145_cmd_hdr cmd; struct s2145_getunique_resp *resp = (struct s2145_getunique_resp*) rdbuf; @@ -1540,8 +1540,8 @@ static int shinkos2145_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); + ATTR("marker-names='Color'\n"); + ATTR("marker-types=ribbonWax\n"); // XXX check copies against remaining media! diff --git a/backend_shinkos6145.c b/backend_shinkos6145.c index 12663b0..cfb37e5 100644 --- a/backend_shinkos6145.c +++ b/backend_shinkos6145.c @@ -275,15 +275,17 @@ struct shinkos6145_ctx { uint8_t *databuf; size_t datalen; + uint8_t ribbon_type; + uint16_t last_donor; uint16_t last_remain; - + uint8_t *eeprom; size_t eepromlen; void *dl_handle; ImageProcessingFN ImageProcessing; - ImageAvrCalcFN ImageAvrCalc; + ImageAvrCalcFN ImageAvrCalc; struct shinkos6145_correctionparam *corrdata; size_t corrdatalen; @@ -869,13 +871,13 @@ struct s6145_status_resp { uint32_t count_head; uint32_t count_ribbon_left; uint32_t reserved; - + uint8_t bank1_printid; uint16_t bank1_remaining; uint16_t bank1_finished; uint16_t bank1_specified; uint8_t bank1_status; - + uint8_t bank2_printid; uint16_t bank2_remaining; uint16_t bank2_finished; @@ -884,7 +886,7 @@ struct s6145_status_resp { uint8_t reserved2[16]; uint8_t tonecurve_status; - uint8_t reserved3[6]; + uint8_t reserved3[6]; } __attribute__((packed)); #define BANK_STATUS_FREE 0x00 @@ -953,7 +955,7 @@ struct s6145_mediainfo_item { #define MEDIA_2x6 0x07 #define MEDIA_6x6 0x08 -static char *print_medias (uint8_t v) { +static char *print_sizes (uint8_t v) { switch (v) { case MEDIA_4x6: return "4x6"; @@ -981,7 +983,24 @@ static char *print_medias (uint8_t v) { #define RIBBON_6x8 0x04 #define RIBBON_6x9 0x05 -static char *print_ribbons (uint8_t v) { +static int ribbon_sizes (uint8_t v) { + switch (v) { + case RIBBON_4x6: + return 300; + case RIBBON_3_5x5: + return 340; + case RIBBON_5x7: + return 170; + case RIBBON_6x8: + return 150; + case RIBBON_6x9: + return 130; // XXX guessed + default: + return 300; // don't want 0. + } +} + +static const char *print_ribbons (uint8_t v) { switch (v) { case RIBBON_NONE: return "None"; @@ -1330,7 +1349,7 @@ static int get_mediainfo(struct shinkos6145_ctx *ctx) ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd)); return ret; } - + if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6145_mediainfo_resp) - sizeof(struct s6145_status_hdr))) return -2; @@ -1338,9 +1357,9 @@ static int get_mediainfo(struct shinkos6145_ctx *ctx) INFO("Supported Print Sizes: %d entries:\n", resp->count); for (i = 0 ; i < resp->count ; i++) { INFO(" %02d: C 0x%02x (%s), %04dx%04d, P 0x%02x (%s)\n", i, - resp->items[i].media_code, print_medias(resp->items[i].media_code), + resp->items[i].media_code, print_sizes(resp->items[i].media_code), le16_to_cpu(resp->items[i].columns), - le16_to_cpu(resp->items[i].rows), + le16_to_cpu(resp->items[i].rows), resp->items[i].print_method, print_methods(resp->items[i].print_method)); } return 0; @@ -2055,7 +2074,7 @@ static int shinkos6145_read_parse(void *vctx, int data_fd) { return CUPS_BACKEND_CANCEL; } - + if (ctx->databuf) { free(ctx->databuf); ctx->databuf = NULL; @@ -2131,7 +2150,7 @@ static int shinkos6145_main_loop(void *vctx, int copies) { ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd)); return CUPS_BACKEND_FAILED; } - + if (le16_to_cpu(media->hdr.payload_len) != (sizeof(struct s6145_mediainfo_resp) - sizeof(struct s6145_status_hdr))) return CUPS_BACKEND_FAILED; @@ -2153,9 +2172,10 @@ static int shinkos6145_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); - + ATTR("marker-names='%s'\n", print_ribbons(media->ribbon)); + ATTR("marker-types=ribbonWax\n"); + ctx->ribbon_type = media->ribbon; + // XXX check copies against remaining media? /* Query printer mode */ @@ -2164,7 +2184,7 @@ static int shinkos6145_main_loop(void *vctx, int copies) { ERROR("Failed to execute command\n"); return ret; } - + top: if (state != last_state) { if (dyesub_debug) @@ -2186,14 +2206,14 @@ top: if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) { uint16_t donor, remain; - + memcpy(rdbuf2, rdbuf, READBACK_LEN); INFO("Printer Status: 0x%02x (%s)\n", sts->hdr.status, status_str(sts->hdr.status)); /* Guessimate a percentage for the remaining media */ - donor = le32_to_cpu(sts->count_ribbon_left) * 100 / (le32_to_cpu(sts->count_ribbon_left)+le32_to_cpu(sts->count_paper)); + donor = le32_to_cpu(sts->count_ribbon_left) * 100 / ribbon_sizes(ctx->ribbon_type); if (donor != ctx->last_donor) { ctx->last_donor = donor; ATTR("marker-levels=%d\n", donor); @@ -2207,14 +2227,14 @@ top: if (sts->hdr.result != RESULT_SUCCESS) goto printer_error; if (sts->hdr.status == ERROR_PRINTER) - goto printer_error; + goto printer_error; } else if (state == last_state) { sleep(1); goto top; } last_state = state; - fflush(stderr); + fflush(stderr); switch (state) { case S_IDLE: diff --git a/backend_shinkos6245.c b/backend_shinkos6245.c index 7cb89dd..4cc4143 100644 --- a/backend_shinkos6245.c +++ b/backend_shinkos6245.c @@ -106,6 +106,7 @@ struct shinkos6245_ctx { uint16_t last_donor; uint16_t last_remain; + uint8_t ribbon_code; }; /* Structs for printer */ @@ -520,7 +521,7 @@ static char *error_codes(uint8_t major, uint8_t minor) return "Paper Jam: Precut Print Position Off"; case 0x20: return "Paper Jam: Precut Print Position On"; - + case 0x29: return "Paper Jam: Printing Paper Top On"; case 0x2A: @@ -703,13 +704,13 @@ struct s6245_status_resp { uint32_t count_head; uint32_t count_ribbon_left; uint32_t reserved; - + uint8_t bank1_printid; uint16_t bank1_remaining; uint16_t bank1_finished; uint16_t bank1_specified; uint8_t bank1_status; - + uint8_t bank2_printid; uint16_t bank2_remaining; uint16_t bank2_finished; @@ -718,7 +719,7 @@ struct s6245_status_resp { uint8_t reserved2[16]; uint8_t tonecurve_status; - uint8_t reserved3[6]; + uint8_t reserved3[6]; } __attribute__((packed)); #define BANK_STATUS_FREE 0x00 @@ -790,7 +791,7 @@ struct s6245_mediainfo_item { #define MEDIA_8x6_2 0x32 #define MEDIA_8x4_3 0x40 -static char *print_medias (uint8_t v) { +static const char *print_sizes (uint8_t v) { switch (v) { case MEDIA_8x10: return "8x10"; @@ -819,10 +820,36 @@ static char *print_medias (uint8_t v) { struct s6245_mediainfo_resp { struct s6245_status_hdr hdr; - uint8_t count; + uint8_t ribbon_code; + uint8_t reserved; + uint8_t count; struct s6245_mediainfo_item items[10]; /* Not all necessarily used */ } __attribute__((packed)); +static const char *ribbon_sizes (uint8_t v) { + switch (v) { + case 0x00: + return "None"; + case 0x11: + return "8x10"; + case 0x12: + return "8x12"; + default: + return "Unknown"; + } +} + +static int ribbon_counts (uint8_t v) { + switch (v) { + case 0x11: + return 120; + case 0x12: + return 100; + default: + return 120; + } +} + struct s6245_errorlog_resp { struct s6245_status_hdr hdr; uint16_t error_count; @@ -1113,14 +1140,15 @@ static int get_mediainfo(struct shinkos6245_ctx *ctx) ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd)); return ret; } - + if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6245_mediainfo_resp) - sizeof(struct s6245_status_hdr))) return -2; + INFO("Loaded Media Type: %s\n", ribbon_sizes(resp->ribbon_code)); INFO("Supported Media Information: %d entries:\n", resp->count); for (i = 0 ; i < resp->count ; i++) { INFO(" %02d: C 0x%02x (%s), %04dx%04d, P 0x%02x (%s)\n", i, - resp->items[i].media_code, print_medias(resp->items[i].media_code), + resp->items[i].media_code, print_sizes(resp->items[i].media_code), le16_to_cpu(resp->items[i].columns), le16_to_cpu(resp->items[i].rows), resp->items[i].print_method, print_methods(resp->items[i].print_method)); @@ -1473,10 +1501,10 @@ static void shinkos6245_attach(void *vctx, struct libusb_device_handle *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(&shinkos6245_backend, desc.idVendor, desc.idProduct); @@ -1643,6 +1671,7 @@ static int shinkos6245_main_loop(void *vctx, int copies) { ERROR("Incorrect media loaded for print!\n"); return CUPS_BACKEND_HOLD; } + ctx->ribbon_code = media->ribbon_code; /* Send Set Time */ { @@ -1676,9 +1705,9 @@ static int shinkos6245_main_loop(void *vctx, int copies) { ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); ATTR("marker-high-levels=100\n"); ATTR("marker-low-levels=10\n"); - ATTR("marker-names=Ribbon\n"); - ATTR("marker-types=ink-ribbon\n"); - + ATTR("marker-names='%s'\n", ribbon_sizes(ctx->ribbon_code)); + ATTR("marker-types=ribbonWax\n"); + // XXX check copies against remaining media! top: @@ -1709,7 +1738,7 @@ top: sts->hdr.status, status_str(sts->hdr.status)); /* Guessimate a percentage for the remaining media */ - donor = le32_to_cpu(sts->count_ribbon_left) * 100 / (le32_to_cpu(sts->count_ribbon_left)+le32_to_cpu(sts->count_paper)); + donor = le32_to_cpu(sts->count_ribbon_left) * 100 / ribbon_counts(ctx->ribbon_code); if (donor != ctx->last_donor) { ctx->last_donor = donor; ATTR("marker-levels=%d\n", donor); @@ -1721,7 +1750,7 @@ top: } if (sts->hdr.result != RESULT_SUCCESS) - goto printer_error; + goto printer_error; if (sts->hdr.error == ERROR_PRINTER) goto printer_error; } else if (state == last_state) { @@ -1730,7 +1759,7 @@ top: } last_state = state; - fflush(stderr); + fflush(stderr); switch (state) { case S_IDLE: @@ -1866,7 +1895,7 @@ static int shinkos6245_query_serno(struct libusb_device_handle *dev, uint8_t end struct dyesub_backend shinkos6245_backend = { .name = "Shinko/Sinfonia CHC-S6245", - .version = "0.06WIP", + .version = "0.07WIP", .uri_prefix = "shinkos6245", .cmdline_usage = shinkos6245_cmdline, .cmdline_arg = shinkos6245_cmdline_arg,