1 /*
2 * Sony UP-D series Photo Printer CUPS backend -- libusb-1.0 version
3 *
4 * (c) 2013-2019 Solomon Peachy <pizza@shaftnet.org>
5 *
6 * The latest version of this program can be found at:
7 *
8 * http://git.shaftnet.org/cgit/selphy_print.git
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 *
23 * [http://www.gnu.org/licenses/gpl-2.0.html]
24 *
25 * SPDX-License-Identifier: GPL-2.0+
26 *
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <signal.h>
38
39 #define BACKEND sonyupd_backend
40
41 #include "backend_common.h"
42
43 /* Printer status
44 --> 1b e0 00 00 00 00 XX 00 [[ XX is 0xe on UPD895, 0xf on others ]]
45 <-- this struct
46 */
47 struct sony_updsts {
48 uint8_t len; /* 0x0d/0x0e (ie number of bytes AFTER this one) */
49 uint8_t zero1; /* 0x00 */
50 uint8_t printing; /* UPD_PRINTING_* */
51 uint8_t remain; /* Number of remaining pages */
52 uint8_t zero2;
53 uint8_t sts1; /* UPD_STS1_* */
54 uint8_t sts2; /* seconday status */
55 uint8_t sts3; /* tertiary status */
56 uint16_t unk; /* seen 0x04a0 UP-CR10L, 0x04a8 on UP-DR150 */
57 uint16_t max_cols; /* BE */
58 uint16_t max_rows; /* BE */
59 uint8_t percent; /* 0-99, if job is printing (UP-D89x) */
60 } __attribute__((packed));
61
62 #define UPD_PRINTING_BW 0xe0 /* UPD-895/897 only */
63 #define UPD_PRINTING_Y 0x40
64 #define UPD_PRINTING_M 0x80
65 #define UPD_PRINTING_C 0xc0
66 #define UPD_PRINTING_O 0x20
67 #define UPD_PRINTING_IDLE 0x00
68
69 #define UPD_STS1_IDLE 0x00
70 #define UPD_STS1_DOOROPEN 0x08
71 #define UPD_STS1_NOPAPER 0x40
72 #define UPD_STS1_PRINTING 0x80
73
74 /* Private data structures */
75 struct upd_printjob {
76 uint8_t *databuf;
77 int datalen;
78
79 int copies;
80 uint16_t rows;
81 uint16_t cols;
82 uint32_t imglen;
83 };
84
85 struct upd_ctx {
86 struct libusb_device_handle *dev;
87 uint8_t endp_up;
88 uint8_t endp_down;
89 int type;
90
91 int native_bpp;
92
93 struct sony_updsts stsbuf;
94
95 struct marker marker;
96 };
97
98 /* Now for the code */
upd_init(void)99 static void* upd_init(void)
100 {
101 struct upd_ctx *ctx = malloc(sizeof(struct upd_ctx));
102 if (!ctx) {
103 ERROR("Memory Allocation Failure!");
104 return NULL;
105 }
106 memset(ctx, 0, sizeof(struct upd_ctx));
107 return ctx;
108 }
109
upd_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)110 static int upd_attach(void *vctx, struct libusb_device_handle *dev, int type,
111 uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
112 {
113 struct upd_ctx *ctx = vctx;
114
115 UNUSED(jobid);
116
117 ctx->dev = dev;
118 ctx->endp_up = endp_up;
119 ctx->endp_down = endp_down;
120 ctx->type = type;
121
122 if (ctx->type == P_SONY_UPD895 || ctx->type == P_SONY_UPD897) {
123 ctx->marker.color = "#000000"; /* Ie black! */
124 ctx->native_bpp = 1;
125 } else {
126 ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
127 ctx->native_bpp = 3;
128 }
129
130 ctx->marker.name = "Unknown";
131 ctx->marker.levelmax = -1;
132 ctx->marker.levelnow = -2;
133
134 return CUPS_BACKEND_OK;
135 }
136
upd_cleanup_job(const void * vjob)137 static void upd_cleanup_job(const void *vjob)
138 {
139 const struct upd_printjob *job = vjob;
140
141 if (job->databuf)
142 free(job->databuf);
143
144 free((void*)job);
145 }
146
147 // UP-DR200
148 // 2UPC-R203 3.5x5 (770)
149 // 2UPC-R204 4x6 (700)
150 // 2UPC-R205 5x7 (400)
151 // 2UPC-R206 6x8 (350)
152
153 // UP-DR150
154 // 2UPC-R153 (610)
155 // 2UPC-R154 (550)
156 // 2UPC-R155 (335)
157 // 2UPC-R156 (295)
158
159 // print order: ->YMCO->
160 // current prints (power on)
161 // total prints (lifetime)
162 // f/w version
163
upd895_statuses(uint8_t code)164 static char* upd895_statuses(uint8_t code)
165 {
166 switch (code) {
167 case UPD_STS1_IDLE:
168 return "Idle";
169 case UPD_STS1_DOOROPEN:
170 return "Door open";
171 case UPD_STS1_NOPAPER:
172 return "No paper";
173 case UPD_STS1_PRINTING:
174 return "Printing";
175 default:
176 return "Unknown";
177 }
178 }
179
sony_get_status(struct upd_ctx * ctx,struct sony_updsts * buf)180 static int sony_get_status(struct upd_ctx *ctx, struct sony_updsts *buf)
181 {
182 int ret, num = 0;
183 uint8_t query[7] = { 0x1b, 0xe0, 0, 0, 0, 0x0f, 0 };
184
185 if (ctx->type == P_SONY_UPD895)
186 query[5] = 0x0e;
187
188 if ((ret = send_data(ctx->dev, ctx->endp_down,
189 query, sizeof(query))))
190 return CUPS_BACKEND_FAILED;
191
192 ret = read_data(ctx->dev, ctx->endp_up, (uint8_t*) buf, sizeof(*buf),
193 &num);
194
195 if (ret < 0)
196 return CUPS_BACKEND_FAILED;
197 #if 0
198 if (ctx->type == P_SONY_UPD895 && ret != 14)
199 return CUPS_BACKEND_FAILED;
200 else if (ret != 15)
201 return CUPS_BACKEND_FAILED;
202 #endif
203
204 ctx->stsbuf.max_cols = be16_to_cpu(ctx->stsbuf.max_cols);
205 ctx->stsbuf.max_rows = be16_to_cpu(ctx->stsbuf.max_rows);
206
207 return CUPS_BACKEND_OK;
208 }
209
210 #define MAX_PRINTJOB_LEN (2048*2764*3 + 2048)
211
upd_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)212 static int upd_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
213 struct upd_ctx *ctx = vctx;
214 int len, run = 1;
215 uint32_t copies_offset = 0;
216 uint32_t param_offset = 0;
217 uint32_t data_offset = 0;
218
219 struct upd_printjob *job = NULL;
220
221 if (!ctx)
222 return CUPS_BACKEND_FAILED;
223
224 job = malloc(sizeof(*job));
225 if (!job) {
226 ERROR("Memory allocation failure!\n");
227 return CUPS_BACKEND_RETRY_CURRENT;
228 }
229 memset(job, 0, sizeof(*job));
230 job->copies = copies;
231
232 job->datalen = 0;
233 job->databuf = malloc(MAX_PRINTJOB_LEN);
234 if (!job->databuf) {
235 ERROR("Memory allocation failure!\n");
236 upd_cleanup_job(job);
237 return CUPS_BACKEND_RETRY_CURRENT;
238 }
239
240 while(run) {
241 int i;
242 int keep = 0;
243 i = read(data_fd, job->databuf + job->datalen, 4);
244 if (i < 0) {
245 upd_cleanup_job(job);
246 return CUPS_BACKEND_CANCEL;
247 }
248 if (i == 0)
249 break;
250
251 memcpy(&len, job->databuf + job->datalen, sizeof(len));
252 len = le32_to_cpu(len);
253
254 /* Filter out chunks we don't send to the printer */
255 if (len & 0xf0000000) {
256 switch (len) {
257 case 0xfffffff3:
258 if(dyesub_debug)
259 DEBUG("Block ID '%08x' (len %d)\n", len, 0);
260 len = 0;
261 if (ctx->type == P_SONY_UPDR150)
262 run = 0;
263 break;
264 case 0xfffffff7:
265 if(dyesub_debug)
266 DEBUG("Block ID '%08x' (len %d)\n", len, 0);
267 len = 0;
268 if (ctx->type == P_SONY_UPCR10)
269 run = 0;
270 break;
271 case 0xfffffff8: // 895
272 case 0xfffffff4: // 897
273 if(dyesub_debug)
274 DEBUG("Block ID '%08x' (len %d)\n", len, 0);
275 len = 0;
276 if (ctx->type == P_SONY_UPD895 || ctx->type == P_SONY_UPD897)
277 run = 0;
278 break;
279 case 0xffffff97:
280 if(dyesub_debug)
281 DEBUG("Block ID '%08x' (len %d)\n", len, 12);
282 len = 12;
283 break;
284 case 0xffffffef:
285 if (ctx->type == P_SONY_UPD895 || ctx->type == P_SONY_UPD897) {
286 if(dyesub_debug)
287 DEBUG("Block ID '%08x' (len %d)\n", len, 0);
288 len = 0;
289 break;
290 }
291 /* Intentional Fallthrough */
292 case 0xffffffeb:
293 case 0xffffffee:
294 case 0xfffffff5:
295 if(dyesub_debug)
296 DEBUG("Block ID '%08x' (len %d)\n", len, 4);
297 len = 4;
298 break;
299 case 0xffffffec:
300 if (ctx->type == P_SONY_UPD897) {
301 if(dyesub_debug)
302 DEBUG("Block ID '%08x' (len %d)\n", len, 4);
303 len = 4;
304 break;
305 }
306 /* Intentional Fallthrough */
307 default:
308 if(dyesub_debug)
309 DEBUG("Block ID '%08x' (len %d)\n", len, 0);
310 len = 0;
311 break;
312 }
313 } else {
314 /* Only keep these chunks */
315 if(dyesub_debug)
316 DEBUG("Data block (len %d)\n", len);
317 if (len > 0)
318 keep = 1;
319 }
320 if (keep)
321 job->datalen += sizeof(uint32_t);
322
323 /* Make sure we're not too large */
324 if (job->datalen + len > MAX_PRINTJOB_LEN) {
325 ERROR("Buffer overflow when parsing printjob! (%d+%d)\n",
326 job->datalen, len);
327 upd_cleanup_job(job);
328 return CUPS_BACKEND_CANCEL;
329 }
330
331 /* Read in the data chunk */
332 while(len > 0) {
333 i = read(data_fd, job->databuf + job->datalen, len);
334 if (i < 0) {
335 upd_cleanup_job(job);
336 return CUPS_BACKEND_CANCEL;
337 }
338 if (i == 0)
339 break;
340
341 /* Work out offset of copies command */
342 if (job->databuf[job->datalen] == 0x1b) {
343 int offset = 0;
344 if (i == 7)
345 offset = 4;
346
347 switch (job->databuf[job->datalen + 1]) {
348 case 0x15: /* Print dimensions */
349 param_offset = job->datalen + 16 + offset;
350 break;
351 case 0xee:
352 copies_offset = job->datalen + 7 + offset;
353 break;
354 case 0xe1: /* Image dimensions */
355 param_offset = job->datalen + 14 + offset;
356 break;
357 case 0xea:
358 data_offset = job->datalen + 6 + offset;
359 break;
360 default:
361 break;
362 }
363 }
364
365 if (keep)
366 job->datalen += i;
367 len -= i;
368 }
369 }
370 if (!job->datalen) {
371 upd_cleanup_job(job);
372 return CUPS_BACKEND_CANCEL;
373 }
374
375 /* Some models specify copies in the print job */
376 if (copies_offset) {
377 uint16_t tmp = copies;
378 tmp = cpu_to_be16(copies);
379 memcpy(job->databuf + copies_offset, &tmp, sizeof(tmp));
380 job->copies = 1;
381 }
382
383 /* Parse some other stuff */
384 if (param_offset) {
385 memcpy(&job->cols, job->databuf + param_offset, sizeof(uint16_t));
386 memcpy(&job->rows, job->databuf + param_offset + 2, sizeof(uint16_t));
387 job->cols = be16_to_cpu(job->cols);
388 job->rows = be16_to_cpu(job->rows);
389 }
390 if (data_offset) {
391 memcpy(&job->imglen, job->databuf + data_offset, sizeof(uint32_t));
392 job->imglen = be32_to_cpu(job->imglen);
393 }
394
395 /* Sanity check job parameters */
396 if (job->imglen != (uint32_t)(job->rows * job->cols * ctx->native_bpp))
397 {
398 ERROR("Job data length mismatch (%u vs %d)!\n",
399 job->imglen, job->rows * job->cols * ctx->native_bpp);
400 upd_cleanup_job(job);
401 return CUPS_BACKEND_CANCEL;
402 }
403
404 *vjob = job;
405
406 return CUPS_BACKEND_OK;
407 }
408
upd_main_loop(void * vctx,const void * vjob)409 static int upd_main_loop(void *vctx, const void *vjob) {
410 struct upd_ctx *ctx = vctx;
411 int i, ret;
412 int copies;
413
414 const struct upd_printjob *job = vjob;
415
416 if (!ctx)
417 return CUPS_BACKEND_FAILED;
418 if (!job)
419 return CUPS_BACKEND_FAILED;
420
421 copies = job->copies;
422
423 top:
424 /* Send Unknown CMD. Resets? */
425 if (ctx->type == P_SONY_UPD897) {
426 const uint8_t cmdbuf[7] = { 0x1b, 0x1f, 0, 0, 0, 0, 0 };
427 ret = send_data(ctx->dev, ctx->endp_down,
428 cmdbuf, sizeof(cmdbuf));
429 if (ret)
430 return CUPS_BACKEND_FAILED;
431 }
432
433 /* Query printer status */
434 ret = sony_get_status(ctx, &ctx->stsbuf);
435
436 if (ret)
437 return CUPS_BACKEND_FAILED;
438
439 /* Sanity check job parameters */
440 if (job->rows > ctx->stsbuf.max_rows ||
441 job->cols > ctx->stsbuf.max_cols) {
442 ERROR("Job dimensions (%u/%u) exceed printer max (%u/%u)\n",
443 job->cols, job->rows,
444 ctx->stsbuf.max_cols,
445 ctx->stsbuf.max_rows);
446 return CUPS_BACKEND_CANCEL;
447 }
448
449 /* Check for idle */
450 if (ctx->stsbuf.sts1 != 0x00) {
451 if (ctx->stsbuf.sts1 == 0x80) {
452 INFO("Waiting for printer idle...\n");
453 sleep(1);
454 goto top;
455 }
456 }
457
458 /* Send RESET */
459 if (ctx->type != P_SONY_UPD895) {
460 const uint8_t rstbuf[7] = { 0x1b, 0x16, 0, 0, 0, 0, 0 };
461 ret = send_data(ctx->dev, ctx->endp_down,
462 rstbuf, sizeof(rstbuf));
463 if (ret)
464 return CUPS_BACKEND_FAILED;
465 }
466
467 #if 0 /* Unknown query */
468 if (ctx->type == P_SONY_UPD897) {
469 // -> 1b e6 00 00 00 08 00
470 // <- ???
471 }
472 #endif
473
474 /* Send over job */
475 i = 0;
476 while (i < job->datalen) {
477 uint32_t len;
478 memcpy(&len, job->databuf + i, sizeof(len));
479 len = le32_to_cpu(len);
480
481 i += sizeof(uint32_t);
482
483 if ((ret = send_data(ctx->dev, ctx->endp_down,
484 job->databuf + i, len)))
485 return CUPS_BACKEND_FAILED;
486
487 i += len;
488 }
489
490 // XXX generate and send copy cmd instead of using the offset.
491 // 1b ee 00 00 00 02 00 NN NN (BE)
492
493 /* Wait for completion! */
494 retry:
495 sleep(1);
496
497 /* Check for idle */
498 ret = sony_get_status(ctx, &ctx->stsbuf);
499 if (ret)
500 return ret;
501
502 switch (ctx->stsbuf.sts1) {
503 case UPD_STS1_IDLE:
504 goto done;
505 case UPD_STS1_PRINTING:
506 break;
507 default:
508 ERROR("Printer error: %s (%02x)\n", upd895_statuses(ctx->stsbuf.sts1),
509 ctx->stsbuf.sts1);
510 return CUPS_BACKEND_STOP;
511 }
512
513 if (fast_return && ctx->stsbuf.printing != UPD_PRINTING_IDLE) {
514 INFO("Fast return mode enabled.\n");
515 } else {
516 goto retry;
517 }
518
519 /* Clean up */
520 if (terminate)
521 copies = 1;
522
523 done:
524 INFO("Print complete (%d copies remaining)\n", copies - 1);
525
526 if (copies && --copies) {
527 goto top;
528 }
529
530 return CUPS_BACKEND_OK;
531 }
532
upd895_dump_status(struct upd_ctx * ctx)533 static int upd895_dump_status(struct upd_ctx *ctx)
534 {
535 int ret = sony_get_status(ctx, &ctx->stsbuf);
536 if (ret < 0)
537 return CUPS_BACKEND_FAILED;
538
539 INFO("Printer status: %s (%02x)\n", upd895_statuses(ctx->stsbuf.sts1), ctx->stsbuf.sts1);
540 if (ctx->stsbuf.printing != UPD_PRINTING_IDLE &&
541 ctx->stsbuf.sts1 == UPD_STS1_PRINTING)
542 INFO("Remaining copies: %d\n", ctx->stsbuf.remain);
543
544 return CUPS_BACKEND_OK;
545 }
546
547
upd_cmdline(void)548 static void upd_cmdline(void)
549 {
550 DEBUG("\t\t[ -s ] # Query printer status\n");
551 }
552
upd_cmdline_arg(void * vctx,int argc,char ** argv)553 static int upd_cmdline_arg(void *vctx, int argc, char **argv)
554 {
555 struct upd_ctx *ctx = vctx;
556 int i, j = 0;
557
558 if (!ctx)
559 return -1;
560
561 while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "s")) >= 0) {
562 switch(i) {
563 GETOPT_PROCESS_GLOBAL
564 case 's':
565 j = upd895_dump_status(ctx);
566 break;
567 }
568
569 if (j) return j;
570 }
571
572 return 0;
573 }
574
upd_query_markers(void * vctx,struct marker ** markers,int * count)575 static int upd_query_markers(void *vctx, struct marker **markers, int *count)
576 {
577 struct upd_ctx *ctx = vctx;
578 int ret = sony_get_status(ctx, &ctx->stsbuf);
579
580 *markers = &ctx->marker;
581 *count = 1;
582
583 if (ret)
584 return CUPS_BACKEND_FAILED;
585
586 if (ctx->stsbuf.sts1 == 0x40 ||
587 ctx->stsbuf.sts1 == 0x08) {
588 ctx->marker.levelnow = 0;
589 STATE("+media-empty\n");
590 } else {
591 ctx->marker.levelnow = -3;
592 STATE("-media-empty\n");
593 }
594
595 return CUPS_BACKEND_OK;
596 }
597
598 static const char *sonyupd_prefixes[] = {
599 "sonyupd",
600 "sony-updr150", "sony-updr200", "sony-upcr10l",
601 "sony-upd895", "sony-upd897", "dnp-sl10",
602 // Backwards compatibility
603 "sonyupdr150",
604 "sonyupdr200", "sonyupcr10",
605 NULL
606 };
607
608 /* Exported */
609 #define USB_VID_SONY 0x054C
610 #define USB_PID_SONY_UPDR150 0x01E8
611 #define USB_PID_SONY_UPDR200 0x035F
612 #define USB_PID_SONY_UPCR10 0x0226
613 #define USB_PID_SONY_UPD895 0x0049
614 #define USB_PID_SONY_UPD897 0x01E7
615
616 struct dyesub_backend sonyupd_backend = {
617 .name = "Sony UP-D",
618 .version = "0.37",
619 .uri_prefixes = sonyupd_prefixes,
620 .cmdline_arg = upd_cmdline_arg,
621 .cmdline_usage = upd_cmdline,
622 .init = upd_init,
623 .attach = upd_attach,
624 .cleanup_job = upd_cleanup_job,
625 .read_parse = upd_read_parse,
626 .main_loop = upd_main_loop,
627 .query_markers = upd_query_markers,
628 .devices = {
629 { USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, NULL, "sony-updr150"},
630 { USB_VID_SONY, USB_PID_SONY_UPDR200, P_SONY_UPDR150, NULL, "sony-updr200"},
631 { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, NULL, "sony-upcr10l"},
632 { USB_VID_SONY, USB_PID_SONY_UPD895, P_SONY_UPD895, NULL, "sonyupd895"},
633 { USB_VID_SONY, USB_PID_SONY_UPD897, P_SONY_UPD897, NULL, "sony-upd897"},
634 { 0, 0, 0, NULL, NULL}
635 }
636 };
637
638 /* Sony spool file format
639
640 The spool file is a series of 4-byte commands, followed by optional
641 arguments. The purpose of the commands is unknown, but they presumably
642 instruct the driver to perform certain things.
643
644 If you treat these 4 bytes as a 32-bit little-endian number, if any of the
645 least significant 4 bits are non-zero, the value is is to
646 be interpreted as a driver command. If the most significant bits are
647 zero, the value signifies that the following N bytes of data should be
648 sent to the printer as-is.
649
650 Known driver "commands":
651
652 97 ff ff ff
653 eb ff ff ff ?? 00 00 00
654 ec ff ff ff ?? 00 00 00
655 ed ff ff ff ?? 00 00 00
656 ee ff ff ff ?? 00 00 00
657 ef ff ff ff XX 00 00 00 # XX == print size (0x01/0x02/0x03/0x04)
658 ef ff ff ff # On UP-D895/897
659 f3 ff ff ff
660 f4 ff ff ff # End of job on UP-D897
661 f5 ff ff ff YY 00 00 00 # YY == ??? (seen 0x01)
662 f7 ff ff ff # End of job on UP-D895
663
664 All printer commands start with 0x1b, and are at least 7 bytes long.
665 General Command format:
666
667 1b XX ?? ?? ?? LL 00 # XX is cmd, LL is data or response length.
668
669 UNKNOWN QUERY [possibly media?]
670
671 <- 1b 03 00 00 00 13 00
672 -> 70 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
673 00 00 00
674
675 UNKNOWN CMD (UP-DR & SL10 & UP-D895 & UP-DP10) [ possibly START ]
676
677 <- 1b 0a 00 00 00 00 00
678
679 PRINT DIMENSIONS
680
681 <- 1b 15 00 00 00 0d 00
682 <- 00 00 00 00 ZZ QQ QQ WW WW YY YY XX XX
683
684 QQ/WW/YY/XX are (origin_cols/origin_rows/cols/rows) in BE.
685 ZZ is 0x07 on UP-DR series, 0x01 on UP-D89x series.
686
687 RESET
688
689 <- 1b 16 00 00 00 00 00
690
691 UNKNOWN CMD (UP-DR & SL & UP-D897, may be PRINT START?)
692
693 <- 1b 17 00 00 00 00 00
694
695 UNKNOWN CMD
696
697 <- 1b 1f 00 00 00 00 00
698
699 SET PARAM
700
701 <- 1b c0 00 NN LL 00 00 # LL is response length, NN is number.
702 <- [ NN bytes]
703
704 QUERY PARAM
705
706 <- 1b c1 00 NN LL 00 00 # LL is response length, NN is number.
707 -> [ NN bytes ]
708
709 PARAMS SEEN:
710 03, len 5 [ 02 03 00 01 XX ] (UPDR200, 00 = normal, 02 is multicut/div2 print, 01 seen at end of stream too..
711 02, len 06 [ 02 02 00 03 00 00 ]
712 01, len 10 [ 02 01 00 06 00 02 00 00 00 00 ] (UP-D897)
713 00, len 5 [ 02 01 00 01 XX ] XX == Gamma table
714
715 STATUS QUERY
716
717 <- 1b e0 00 00 00 XX 00 # XX = 0xe (UP-D895), 0xf (All others)
718 -> [14 or 15 bytes, see 'struct sony_updsts' ]
719
720 IMAGE DIMENSIONS & OVERCOAT
721
722 <- 1b e1 00 00 00 0b 00
723 <- 00 ZZ QQ 00 00 00 00 XX XX YY YY # XX = cols, YY == rows, ZZ == 0x04 on UP-DP10, otherwise 0x80. QQ == 00 glossy, 08 texture (UP-DP10 + UP-DR150), 0c matte, +0x10 for "nocorrection" on UP-DR200..
724
725 UNKNOWN
726
727 <- 1b e5 00 00 00 08 00
728 <- 00 00 00 00 00 00 00 XX 00 # Seen 01, 12, 0d, etc.
729
730 UNKNOWN (UP-D897)
731
732 <- 1b e6 00 00 00 08 00
733 <- 07 00 00 00 00 00 00 00
734
735 DATA TRANSFER
736
737 <- 1b ea 00 00 00 00 ZZ ZZ ZZ ZZ 00 # ZZ is BIG ENDIAN
738 <- [ ZZ ZZ ZZ ZZ bytes of data ]
739
740 UNKNOWN CMD (UP-DR and UP-D)
741
742 <- 1b ed 00 00 00 00 00
743
744 UNKNOWN (UPDR series)
745
746 <- 1b ef 00 00 00 06 00
747 -> 05 00 00 00 00 22
748
749 COPIES
750
751 <- 1b ee 00 00 00 02 00
752 <- NN NN # Number of copies (BE, 1-???)
753
754 UNKNOWN (UPDR series)
755
756 <- 1b f5 00 00 00 02 00
757 <- ?? ??
758
759 ************************************************************************
760
761 The data stream sent to the printer consists of all the commands in the
762 spool file, plus a couple other ones that generate responses. It is
763 unknown if those additional commands are necessary. This is a typical
764 sequence:
765
766 [[ Sniff start of a UP-DR150 ]]
767
768 <- 1b e0 00 00 00 0f 00 [ STATUS QUERY ]
769 -> 0e 00 00 00 00 00 00 00 04 a8 08 00 0a a4 00
770 ----- -----
771 MAX_C MAX_R
772 <- 1b 16 00 00 00 00 00
773 -> "reset" ??
774
775 [[ begin job ]]
776
777 <- 1b ef 00 00 00 06 00
778 -> 05 00 00 00 00 22
779
780 <- 1b e5 00 00 00 08 00 ** In spool file
781 <- 00 00 00 00 00 00 01 00
782
783 <- 1b c1 00 02 06 00 00 [ Query Param 2, length 6 ]
784 -> 02 02 00 03 00 00
785
786 <- 1b ee 00 00 00 02 00 ** In spool file
787 <- 00 01
788
789 <- 1b 15 00 00 00 0d 00 ** In spool file
790 <- 00 00 00 00 07 00 00 00 00 08 00 0a a4
791
792 <- 1b 03 00 00 00 13 00
793 -> 70 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
794 00 00 00
795
796 <- 1b e1 00 00 00 0b 00 ** In spool file
797 <- 00 80 00 00 00 00 00 08 00 0a a4
798
799 <- 1b 03 00 00 00 13 00
800 -> 70 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00
801 00 00 00
802
803 <- 1b ea 00 00 00 00 00 ff 60 00 00 ** In spool file
804 <- [[ 0x0060ff00 bytes of data ]]
805
806 <- 1b e0 00 00 00 0f 00
807 -> 0e 00 00 00 00 00 00 00 04 a8 08 00 0a a4 00
808
809 <- 1b 0a 00 00 00 00 00 ** In spool file
810 <- 1b 17 00 00 00 00 00 ** In spool file
811
812 [[fin]]
813
814 **************
815
816 Sony UP-CL10 / DNP SL-10 spool format:
817
818 60 ff ff ff f8 ff ff ff fd ff ff ff
819 14 00 00 00
820 1b 15 00 00 00 0d 00 00 00 00 00 07 00 00 00 00 WW WW HH HH
821 fb ff ff ff f4 ff ff ff
822 0b 00 00 00
823 1b ea 00 00 00 00 SH SH SH SH 00
824 SL SL SL SL
825
826 [[ Data, rows * cols * 3 bytes ]]
827
828 f3 ff ff ff
829 0f 00 00 00
830 1b e5 00 00 00 08 00 00 00 00 00 00 00 00 00
831 12 00 00 00
832 1b e1 00 00 00 0b 00 00 80 00 00 00 00 00 WW WW HH HH
833 fa ff ff ff
834 09 00 00 00
835 1b ee 00 00 00 02 00 00 NN
836 07 00 00 00
837 1b 0a 00 00 00 00 00
838 f9 ff ff ff fc ff ff ff
839 07 00 00 00
840 1b 17 00 00 00 00 00
841 f7 ff ff ff
842
843 WW WW == Columns, Big Endian
844 HH HH == Rows, Big Endian
845 SL SL SL SL == Plane size, Little Endian (Rows * Cols * 3)
846 SH SH SH SH == Plane size, Big Endian (Rows * Cols * 3)
847 NN == Copies
848
849 **************
850
851 Sony UP-D895 spool format:
852
853 XX XX == cols, BE (fixed at 1280/0x500)
854 YY YY == rows, BE (798/0x031e,1038/0x040e,1475/0x05c3, 2484/09b4) @ 960/1280/1920/3840+4096
855 SS SS SS SS == data len (rows * cols, LE)
856 S' S' S' S' == data len (rows * cols, BE)
857 NN == copies (1 -> ??)
858 GG GG == ??? 0000/0050/011b/04aa/05aa at each resolution.
859 G' == Gamma 01 (soft), 03 (hard), 02 (normal)
860
861 9c ff ff ff 97 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff
862
863 14 00 00 00
864 1b 15 00 00 00 0d 00 00 00 00 00 01 GG GG 00 00 YY YY XX XX
865 0b 00 00 00
866 1b ea 00 00 00 00 S' S' S' S' 00
867 SS SS SS SS
868 ...DATA... (rows * cols)
869 ff ff ff ff
870 09 00 00 00
871 1b ee 00 00 00 02 00 00 NN
872 0f 00 00 00
873 1b e5 00 00 00 08 00 00 00 00 00 00 00 00 00
874 0c 00 00 00
875 1b c0 00 00 00 05 00 02 00 00 01 G'
876 11 00 00 00
877 1b c0 00 01 00 0a 00 02 01 00 06 00 00 00 00 00 00
878 12 00 00 00
879 1b e1 00 00 00 0b 00 00 08 00 GG GG 00 00 YY YY XX XX
880 07 00 00 00
881 1b 0a 00 00 00 00 00
882 fd ff ff ff f7 ff ff ff f8 ff ff ff
883
884 **************
885
886 Sony UP-D897 spool format:
887
888 NN NN == copies (00 for printer selected)
889 XX XX == cols (fixed @ 1280)
890 YY YY == rows
891 GG == gamma -- Table 2 == 2, Table 1 == 3, Table 3 == 1, Table 4 == 4
892 DD == "dark" +- 64.
893 LL == "light" +- 64.
894 AA == "advanced" +- 32.
895 SS == Sharpness 0-14
896 ZZ ZZ ZZ ZZ == Data length (BE)
897 Z` Z` Z` Z` == Data length (LE)
898
899
900 83 ff ff ff fc ff ff ff
901 fb ff ff ff f5 ff ff ff
902 f1 ff ff ff f0 ff ff ff
903 ef ff ff ff
904
905 14 00 00 00
906 1b 15 00 00 00 0d 00 00 00 00 00 01 00 a2 00 00 YY YY XX XX
907
908 0b 00 00 00
909 1b ea 00 00 00 00 ZZ ZZ ZZ ZZ 00
910
911 Z` Z` Z` Z`
912 ...DATA...
913
914 ea ff ff ff
915
916 09 00 00 00
917 1b ee 00 00 00 02 00 NN NN
918
919 ee ff ff ff 01 00 00 00
920
921 0e 00 00 00
922 1b e5 00 00 00 08 00 00 00 00 00 DD LL SS AA
923
924 eb ff ff ff ?? 00 00 00 <--- 02/05 5 at #3, 2 otherwise. Sharpness?
925
926 0c 00 00 00
927 1b c0 00 00 00 05 00 02 00 00 01 GG
928
929 ec ff ff ff ?? 00 00 00 <--- 01/00/02/01/01 Seen. Unknown.
930
931 11 00 00 00
932 1b c0 00 01 00 0a 00 02 01 00 06 00 00 00 00 00 00
933
934 ed ff ff ff 00 00 00 00
935
936 12 00 00 00
937 1b e1 00 00 00 0b 00 00 08 00 00 a2 00 00 YY YY XX XX
938
939 fa ff ff ff
940
941 07 00 00 00
942 1b 0a 00 00 00 00 00
943
944 fc ff ff ff fd ff ff ff ff ff ff ff
945
946 07 00 00 00
947 1b 17 00 00 00 00 00
948
949 f4 ff ff ff
950
951 ****************
952
953 UP-D895 comms protocol:
954
955 <-- 1b e0 00 00 00 0e 00
956 --> 0d 00 XX YY 00 SS 00 ZZ 00 00 10 00 05 00
957
958 XX : 0xe0 when printing, 0x00 otherwise.
959 YY : Number of remaining copies
960 SS : Status
961 0x00 = Idle
962 0x08 = Door open
963 0x40 = Paper empty
964 0x80 = Printing
965 ?? = Cooling down
966 ?? = Busy / Waiting
967 ZZ : Status2
968 0x01 = Print complete
969 0x02 = no prints yet
970
971 UP-D897 comms protocol:
972
973 <-- 1b e0 00 00 00 0f 00
974 --> 0e 00 XX YY 00 SS RR 01 02 02 10 00 05 00 PP
975
976 XX : 0xe0 when printing, 0x00 otherwise.
977 YY : Number of remaining copies
978 SS : Status
979 0x00 = Idle
980 ?? 0x08 = Door open
981 0x40 = Paper empty
982 0x80 = Printing
983 ?? = Cooling down
984 ?? = Busy / Waiting
985 RR : Status 2
986 0x00 = Okay
987 0x08 = ?? Error state?
988 0x80 = Printing
989 PP : Percentage complete (0-99)
990
991 Other commands seen:
992
993 <-- 1b 16 00 00 00 00 00 -- Reset
994
995 <-- 1b c1 00 01 00 0a 00 -- Query ID 1, legth 10
996 --> 02 01 00 06 00 02 00 00 00 00
997
998 <-- 1b c1 00 00 00 05 00 -- Query id 0, length 5
999 --> 02 01 00 01 03
1000
1001 <-- 1b e6 00 00 00 08 00
1002 --> 07 00 00 00 00 00 00 00
1003
1004 <-- 1b 17 00 00 00 00 00 -- Unknown?
1005
1006 UP-CR10L
1007
1008 2UPC-C13 (300)
1009 2UPC-C14 (200)
1010 2UPC-C15 (172)
1011
1012 Status progression when printing:
1013
1014 0e 00 00 00 00 00 00 00 04 a0 04 e0 07 38 00
1015 0e 00 00 01 00 80 00 01 04 a0 04 e0 07 38 64
1016 0e 00 40 01 00 80 00 01 04 a0 04 e0 07 38 64 <-- Y
1017 0e 00 80 01 00 80 00 01 04 a0 04 e0 07 38 64 <-- M
1018 0e 00 c0 01 00 80 00 01 04 a0 04 e0 07 38 64 <-- C
1019 0e 00 20 01 00 80 00 01 04 a0 04 e0 07 38 64 <-- O
1020 0e 00 20 01 00 80 00 01 04 a0 04 e0 07 38 00
1021 0e 00 00 01 00 80 00 01 04 a0 04 e0 07 38 00
1022 0e 00 00 00 00 00 00 00 04 a0 04 e0 07 38 00
1023
1024 */
1025