From fe2cbc587cacbd23cc3fe9f94b8170cf377b43b5 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 17 Apr 2019 13:58:42 -0400 Subject: [PATCH] sonyupdneo: Add WIP backend for newer Sony printers Covers these models: * UP-DR80MD * UP-CR20SL * UP-D898 / UP-X898 Includes sample files generated by Windows drivers. Note that I do not have USB VID/PIDs for any these models, and the post-parsing code has not been tested. --- .gitignore | 1 + Makefile | 2 +- backend_common.c | 2 + backend_common.h | 3 + backend_sonyupd.c | 2 - backend_sonyupdneo.c | 354 ++++++++++++++++++++++++++++++ regression.csv | 20 +- testjobs/sony_upcr20l_4x6.raw | 3 + testjobs/sony_upd898-1280x960.raw | 3 + testjobs/sony_updr80md-a4.raw | 3 + 10 files changed, 383 insertions(+), 10 deletions(-) create mode 100644 backend_sonyupdneo.c create mode 100644 testjobs/sony_upcr20l_4x6.raw create mode 100644 testjobs/sony_upd898-1280x960.raw create mode 100644 testjobs/sony_updr80md-a4.raw diff --git a/.gitignore b/.gitignore index 1b6d6d7..febaba0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.so sonyupd +sonyupdneo kodak6800 kodak605 kodak1400 diff --git a/Makefile b/Makefile index 55b8e17..5304004 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ CPPFLAGS += -DURI_PREFIX=\"$(BACKEND_NAME)\" $(OLD_URI) CFLAGS += -funit-at-a-time # List of backends -BACKENDS = sonyupd kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 mitsu9550 shinkos6245 shinkos6145 canonselphyneo mitsup95d magicard mitsud90 +BACKENDS = sonyupd sonyupdneo kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 mitsu9550 shinkos6245 shinkos6145 canonselphyneo mitsup95d magicard mitsud90 # For the s6145 and mitsu70x backends CPPFLAGS += -DUSE_DLOPEN diff --git a/backend_common.c b/backend_common.c index c2ab330..218e572 100644 --- a/backend_common.c +++ b/backend_common.c @@ -667,6 +667,7 @@ abort: } extern struct dyesub_backend sonyupd_backend; +extern struct dyesub_backend sonyupdneo_backend; extern struct dyesub_backend kodak6800_backend; extern struct dyesub_backend kodak605_backend; extern struct dyesub_backend kodak1400_backend; @@ -694,6 +695,7 @@ static struct dyesub_backend *backends[] = { &shinkos6145_backend, &shinkos6245_backend, &sonyupd_backend, + &sonyupdneo_backend, &mitsu70x_backend, &mitsud90_backend, &mitsu9550_backend, diff --git a/backend_common.h b/backend_common.h index 555c896..821fd5d 100644 --- a/backend_common.h +++ b/backend_common.h @@ -155,6 +155,9 @@ enum { P_MAGICARD = 43, P_SONY_UPD895 = 44, P_SONY_UPD897 = 45, + P_SONY_UPD898 = 46, + P_SONY_UPCR20L = 47, + P_SONY_UPDR80 = 48, P_END, }; diff --git a/backend_sonyupd.c b/backend_sonyupd.c index 3153bb4..03c594c 100644 --- a/backend_sonyupd.c +++ b/backend_sonyupd.c @@ -606,7 +606,6 @@ static const char *sonyupd_prefixes[] = { #define USB_PID_SONY_UPCR10 0x0226 #define USB_PID_SONY_UPD895 0x0049 #define USB_PID_SONY_UPD897 0x01E7 -//#define USB_PID_SONY_UPD898 XXXXX // 0x589a? struct dyesub_backend sonyupd_backend = { .name = "Sony UP-D", @@ -627,7 +626,6 @@ struct dyesub_backend sonyupd_backend = { { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, NULL, "sony-upcr10l"}, { USB_VID_SONY, USB_PID_SONY_UPD895, P_SONY_UPD895, NULL, "sonyupd895"}, { USB_VID_SONY, USB_PID_SONY_UPD897, P_SONY_UPD897, NULL, "sony-upd897"}, -// { USB_VID_SONY, USB_PID_SONY_UPD898MD, P_SONY_UPD89x, NULL, "sonyupd898"}, { 0, 0, 0, NULL, NULL} } }; diff --git a/backend_sonyupdneo.c b/backend_sonyupdneo.c new file mode 100644 index 0000000..cbdbc86 --- /dev/null +++ b/backend_sonyupdneo.c @@ -0,0 +1,354 @@ +/* + * Sony UP-D series (new) Photo Printer CUPS backend -- libusb-1.0 version + * + * (c) 2019 Solomon Peachy + * + * The latest version of this program can be found at: + * + * http://git.shaftnet.org/cgit/selphy_print.git + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * [http://www.gnu.org/licenses/gpl-3.0.html] + * + * SPDX-License-Identifier: GPL-3.0+ + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define BACKEND sonyupdneo_backend + +#include "backend_common.h" + +/* Private data structures */ +struct updneo_printjob { + uint8_t *databuf; + int datalen; + + int copies_offset; + int payload_offset; + + int copies; + + uint16_t rows; + uint16_t cols; +}; + +struct updneo_ctx { + struct libusb_device_handle *dev; + uint8_t endp_up; + uint8_t endp_down; + int type; + + int native_bpp; + + struct marker marker; +}; + +/* Now for the code */ +static void* updneo_init(void) +{ + struct updneo_ctx *ctx = malloc(sizeof(struct updneo_ctx)); + if (!ctx) { + ERROR("Memory Allocation Failure!"); + return NULL; + } + memset(ctx, 0, sizeof(struct updneo_ctx)); + return ctx; +} + +static int updneo_attach(void *vctx, struct libusb_device_handle *dev, int type, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +{ + struct updneo_ctx *ctx = vctx; + + UNUSED(jobid); + + ctx->dev = dev; + ctx->endp_up = endp_up; + ctx->endp_down = endp_down; + ctx->type = type; + + if (ctx->type == P_SONY_UPD898) { + ctx->marker.color = "#000000"; /* Ie black! */ + ctx->native_bpp = 1; + } else { + ctx->marker.color = "#00FFFF#FF00FF#FFFF00"; + ctx->native_bpp = 3; + } + + ctx->marker.name = "Unknown"; + ctx->marker.levelmax = -1; + ctx->marker.levelnow = -2; + + return CUPS_BACKEND_OK; +} + +static void updneo_cleanup_job(const void *vjob) +{ + const struct updneo_printjob *job = vjob; + + if (job->databuf) + free(job->databuf); + + free((void*)job); +} + +static void updneo_teardown(void *vctx) { + struct updneo_ctx *ctx = vctx; + + if (!ctx) + return; + + free(ctx); +} + +#define MAX_PRINTJOB_LEN (3400*2392*3 + 2048) + +static int updneo_read_parse(void *vctx, const void **vjob, int data_fd, int copies) { + struct updneo_ctx *ctx = vctx; + int len, run = 1; + + struct updneo_printjob *job = NULL; + + if (!ctx) + return CUPS_BACKEND_FAILED; + + job = malloc(sizeof(*job)); + if (!job) { + ERROR("Memory allocation failure!\n"); + return CUPS_BACKEND_RETRY_CURRENT; + } + memset(job, 0, sizeof(*job)); + job->copies = copies; + + job->datalen = 0; + job->databuf = malloc(MAX_PRINTJOB_LEN); + if (!job->databuf) { + ERROR("Memory allocation failure!\n"); + updneo_cleanup_job(job); + return CUPS_BACKEND_RETRY_CURRENT; + } + + /* Read in data chunks. */ + while(run) { + int i; + + /* Read in data block header (256 bytes) */ + i = read(data_fd, job->databuf + job->datalen, 256); + if (i < 0) { + updneo_cleanup_job(job); + return CUPS_BACKEND_CANCEL; + } + if (i == 0) + break; + + /* Explicitly null terminate */ + job->databuf[job->datalen + 255] = 0; + + /* Parse header. Format: + + JOBSIZE=pdlname,blocklen,printsize,arg1,..,argN + + */ + + if (strncmp("JOBSIZE=", (char*) job->databuf + job->datalen, 8)) { + ERROR("Invalid spool format!\n"); + return CUPS_BACKEND_CANCEL; + } + i = 0; + + /* PDL */ + char *tok = strtok((char*)job->databuf + job->datalen + 8, "\r\n,"); + if (!tok) { + ERROR("Invalid spool format (PDL)!\n"); + return CUPS_BACKEND_CANCEL; + } + + /* Behavior based on the various blocks */ + if (!strncmp("PJL-T", tok, 5)) + run = 1; + else if (!strncmp("SONY-PDL-DS2", tok, 12)) + job->payload_offset = job->datalen; + +// DEBUG("Read block '%s' @ %d ...\n", tok, job->datalen); + + /* Payload length */ + tok = strtok(NULL, "\r\n,"); + if (!tok) { + ERROR("Invalid spool format (block length missing)!\n"); + return CUPS_BACKEND_CANCEL; + } + len = atoi(tok); + if (len == 0 || len > MAX_PRINTJOB_LEN) { + ERROR("Invalid spool format (block length %d)!\n", len); + return CUPS_BACKEND_CANCEL; + } +// DEBUG("...len '%d'\n", len); + + // parse the rest? + // 898MD: 6,0,0,0 + // D80MD: 4 + // CR20L: 64,0,0,0 + + /* Read in the data chunk */ + while(len > 0) { + i = read(data_fd, job->databuf + job->datalen, len); + if (i < 0) { + updneo_cleanup_job(job); + return CUPS_BACKEND_CANCEL; + } + if (i == 0) + break; + + job->datalen += i; + len -= i; + } + } + + if (!job->datalen) { + updneo_cleanup_job(job); + return CUPS_BACKEND_CANCEL; + } + + /* Sanity check job parameters */ + // rows * cols lines up with imgsize, and others? + + *vjob = job; + + return CUPS_BACKEND_OK; +} + +static int updneo_main_loop(void *vctx, const void *vjob) { + struct updneo_ctx *ctx = vctx; + int ret; + int copies; + + const struct updneo_printjob *job = vjob; + + if (!ctx) + return CUPS_BACKEND_FAILED; + if (!job) + return CUPS_BACKEND_FAILED; + + copies = job->copies; + +top: + + // Query printer status + // Sanity check job parameters vs printer status + // Check for idle + + // send over job + if ((ret = send_data(ctx->dev, ctx->endp_down, + job->databuf, job->datalen))) + return CUPS_BACKEND_FAILED; + + /* Wait for completion! */ +retry: + sleep(1); + + // Check for idle + if (fast_return /*&& ctx->stsbuf.printing > 0 */) { + INFO("Fast return mode enabled.\n"); + } else { + goto retry; + } + + /* Clean up */ + if (terminate) + copies = 1; + +// done: + INFO("Print complete (%d copies remaining)\n", copies - 1); + + if (copies && --copies) { + goto top; + } + + return CUPS_BACKEND_OK; +} + +static int updneo_cmdline_arg(void *vctx, int argc, char **argv) +{ + struct updneo_ctx *ctx = vctx; + int i, j = 0; + + if (!ctx) + return -1; + + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "s")) >= 0) { + switch(i) { + GETOPT_PROCESS_GLOBAL + } + + if (j) return j; + } + + return 0; +} + +static int updneo_query_markers(void *vctx, struct marker **markers, int *count) +{ + struct updneo_ctx *ctx = vctx; + + *markers = &ctx->marker; + *count = 1; + + // Do something? + + return CUPS_BACKEND_OK; +} + +static const char *sonyupdneo_prefixes[] = { + "sonyupdneo", + "sony-upd898", "sony-upcr20l", "sony-updr80", + NULL +}; + +/* Exported */ +#define USB_VID_SONY 0x054C +#define USB_PID_SONY_UPD898MD 0xabcd // 0x589a? +#define USB_PID_SONY_UPCR20L 0xbcde +#define USB_PID_SONY_UPDR80MD 0xcdef + +struct dyesub_backend sonyupdneo_backend = { + .name = "Sony UP-D Neo", + .version = "0.01WIP", + .uri_prefixes = sonyupdneo_prefixes, + .cmdline_arg = updneo_cmdline_arg, + .init = updneo_init, + .attach = updneo_attach, + .teardown = updneo_teardown, + .cleanup_job = updneo_cleanup_job, + .read_parse = updneo_read_parse, + .main_loop = updneo_main_loop, + .query_markers = updneo_query_markers, + .devices = { + { USB_VID_SONY, USB_PID_SONY_UPD898MD, P_SONY_UPD898, NULL, "sony-upd898"}, + { USB_VID_SONY, USB_PID_SONY_UPCR20L, P_SONY_UPCR20L, NULL, "sony-upcr20l"}, + { USB_VID_SONY, USB_PID_SONY_UPDR80MD, P_SONY_UPDR80, NULL, "sony-upd80"}, + { 0, 0, 0, NULL, NULL} + } +}; diff --git a/regression.csv b/regression.csv index d455e71..1fbb414 100644 --- a/regression.csv +++ b/regression.csv @@ -91,18 +91,24 @@ shinkos6245,0x10ce,0x001d,shinko_s6245_8x10.raw,0x11 shinkos6245,0x10ce,0x001d,shinko_s6245_8x10.raw,0x12 hitip910,0x0d16,0x000e,shinko_s6245_8x10.raw,0x11 # -# 'sonyupdr150' +# 'sonyupd' # sonyupcr10,0x054c,0x0226,sony_upcr10l_4x6.raw, -sonyupdr150,0x054c,0x01e8,sony_updr150_4x6.raw, -sonyupdr150,0x054c,0x01e8,sony_updr150_8x6.raw, -sonyupdr200,0x054c,0x035f,sony_updr200_2x6.raw, -sonyupdr200,0x054c,0x035f,sony_updr200_4x6.raw, -sony-upd895,0x054c,0x0049,sony_upd895-1280x960.raw, -sony-upd895,0x054c,0x0049,sony_upd895-1280x1280.raw, +sonyupdr150,0x054c,0x01e8,sony_updr150_4x6.raw, +sonyupdr150,0x054c,0x01e8,sony_updr150_8x6.raw, +sonyupdr200,0x054c,0x035f,sony_updr200_2x6.raw, +sonyupdr200,0x054c,0x035f,sony_updr200_4x6.raw, +sony-upd895,0x054c,0x0049,sony_upd895-1280x960.raw, +sony-upd895,0x054c,0x0049,sony_upd895-1280x1280.raw, sony-upd897,0x054c,0x01e7,sony_upd897-1280x960.raw, sony-upd897,0x054c,0x01e7,sony_upd897-1280x1280.raw, # +# 'sonyupdneo' +# +sony-updr80,0x054c,0xcdef,sony_updr80md-a4.raw, +sony-upcr20l,0x054c,0xbcde,sony_upcr20l_4x6.raw, +sony-upd898,0x054c,0xabcd,sony_upd898-1280x960.raw +# # 'mitsu9xxx' [9810/9820 need MATTE job] # #mitsu9000,0x06d3,0x0394,file_fixme, diff --git a/testjobs/sony_upcr20l_4x6.raw b/testjobs/sony_upcr20l_4x6.raw new file mode 100644 index 0000000..fc72526 --- /dev/null +++ b/testjobs/sony_upcr20l_4x6.raw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b8b9ed926000d03d367ac50ebe6e5a9fc97a7bb124e1d871e0ddd4b51918a2a +size 6274101 diff --git a/testjobs/sony_upd898-1280x960.raw b/testjobs/sony_upd898-1280x960.raw new file mode 100644 index 0000000..003863b --- /dev/null +++ b/testjobs/sony_upd898-1280x960.raw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b48bec730d942ba4917e6f7573d8626a0478c716adab7a3d33a83ac5edc453ea +size 658101 diff --git a/testjobs/sony_updr80md-a4.raw b/testjobs/sony_updr80md-a4.raw new file mode 100644 index 0000000..08cf551 --- /dev/null +++ b/testjobs/sony_updr80md-a4.raw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31005ac49e185d2028364cb3c5c9dcc8fb37bf3aac443af7a78093a4252ecbaf +size 24399861