1 /*
2 * Kodak Professional 1400/805 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 kodak1400_backend
40
41 #include "backend_common.h"
42
43 /* Program states */
44 enum {
45 S_IDLE = 0,
46 S_PRINTER_READY_Y,
47 S_PRINTER_SENT_Y,
48 S_PRINTER_READY_M,
49 S_PRINTER_SENT_M,
50 S_PRINTER_READY_C,
51 S_PRINTER_SENT_C,
52 S_PRINTER_READY_L,
53 S_PRINTER_SENT_L,
54 S_PRINTER_DONE,
55 S_FINISHED,
56 };
57
58 #define CMDBUF_LEN 96
59 #define READBACK_LEN 8
60
61 /* File header */
62 struct kodak1400_hdr {
63 uint8_t hdr[4];
64 uint16_t columns;
65 uint16_t null1;
66 uint16_t rows;
67 uint16_t null2;
68 uint32_t planesize;
69 uint32_t null3;
70 uint8_t matte;
71 uint8_t laminate;
72 uint8_t unk1; /* Always 0x01 */
73 uint8_t lam_strength;
74 uint8_t null4[12];
75 } __attribute__((packed));
76
77
78 /* Private data structure */
79 struct kodak1400_printjob {
80 struct kodak1400_hdr hdr;
81 uint8_t *plane_r;
82 uint8_t *plane_g;
83 uint8_t *plane_b;
84
85 int copies;
86 };
87
88 struct kodak1400_ctx {
89 struct libusb_device_handle *dev;
90 uint8_t endp_up;
91 uint8_t endp_down;
92 int type;
93
94 struct marker marker;
95 };
96
send_plane(struct kodak1400_ctx * ctx,const struct kodak1400_printjob * job,uint8_t planeno,uint8_t * planedata,uint8_t * cmdbuf)97 static int send_plane(struct kodak1400_ctx *ctx,
98 const struct kodak1400_printjob *job,
99 uint8_t planeno, uint8_t *planedata,
100 uint8_t *cmdbuf)
101 {
102 uint16_t temp16;
103 int ret;
104
105 if (planeno != 1) {
106 memset(cmdbuf, 0, CMDBUF_LEN);
107 cmdbuf[0] = 0x1b;
108 cmdbuf[1] = 0x74;
109 cmdbuf[2] = 0x00;
110 cmdbuf[3] = 0x50;
111
112 if ((ret = send_data(ctx->dev, ctx->endp_down,
113 cmdbuf, CMDBUF_LEN)))
114 return ret;
115 }
116
117 memset(cmdbuf, 0, CMDBUF_LEN);
118 cmdbuf[0] = 0x1b;
119 cmdbuf[1] = 0x5a;
120 cmdbuf[2] = 0x54;
121 cmdbuf[3] = planeno;
122
123 if (planedata) {
124 temp16 = htons(job->hdr.columns);
125 memcpy(cmdbuf+7, &temp16, 2);
126 temp16 = htons(job->hdr.rows);
127 memcpy(cmdbuf+9, &temp16, 2);
128 }
129
130 if ((ret = send_data(ctx->dev, ctx->endp_down,
131 cmdbuf, CMDBUF_LEN)))
132 return ret;
133
134 if (planedata) {
135 int i;
136 for (i = 0 ; i < job->hdr.rows ; i++) {
137 if ((ret = send_data(ctx->dev, ctx->endp_down,
138 planedata + i * job->hdr.columns,
139 job->hdr.columns)))
140 return ret;
141 }
142 }
143
144 memset(cmdbuf, 0, CMDBUF_LEN);
145 cmdbuf[0] = 0x1b;
146 cmdbuf[1] = 0x74;
147 cmdbuf[2] = 0x01;
148 cmdbuf[3] = 0x50;
149
150 if ((ret = send_data(ctx->dev, ctx->endp_down,
151 cmdbuf, CMDBUF_LEN)))
152 return ret;
153
154 return 0;
155 }
156
157 #define TONE_CURVE_SIZE 1552
kodak1400_set_tonecurve(struct kodak1400_ctx * ctx,char * fname)158 static int kodak1400_set_tonecurve(struct kodak1400_ctx *ctx, char *fname)
159 {
160 libusb_device_handle *dev = ctx->dev;
161 uint8_t endp_down = ctx->endp_down;
162 uint8_t endp_up = ctx->endp_up;
163
164 uint8_t cmdbuf[8];
165 uint8_t respbuf[64];
166 int ret = 0, num = 0;
167
168 INFO("Set Tone Curve from '%s'\n", fname);
169
170 uint16_t *data = malloc(TONE_CURVE_SIZE);
171
172 if (!data) {
173 ERROR("Memory Allocation Failure!\n");
174 return -1;
175 }
176
177 /* Read in file */
178 if ((ret = dyesub_read_file(fname, data, TONE_CURVE_SIZE, NULL))) {
179 ERROR("Failed to read Tone Curve file\n");
180 goto done;
181 }
182
183 /* Byteswap data to printer's format */
184 for (ret = 0; ret < (TONE_CURVE_SIZE-16)/2 ; ret++) {
185 data[ret] = cpu_to_le16(be16_to_cpu(data[ret]));
186 }
187 /* Null-terminate */
188 memset(data + (TONE_CURVE_SIZE-16)/2, 0, 16);
189
190 /* Clear tables */
191 memset(cmdbuf, 0, sizeof(cmdbuf));
192 cmdbuf[0] = 0x1b;
193 cmdbuf[1] = 0xa2;
194 if ((ret = send_data(dev, endp_down,
195 cmdbuf, 2))) {
196 ret = -3;
197 goto done;
198 }
199
200 ret = read_data(dev, endp_up,
201 respbuf, sizeof(respbuf), &num);
202
203 if (ret < 0)
204 goto done;
205 if (num != 8) {
206 ERROR("Short Read! (%d/%d)\n", num, 8);
207 ret = -4;
208 goto done;
209 }
210 if (respbuf[1] != 0x01) {
211 ERROR("Received unexpected response\n");
212 ret = -5;
213 goto done;
214 }
215
216 /* Set up the update command */
217 memset(cmdbuf, 0, sizeof(cmdbuf));
218 cmdbuf[0] = 0x1b;
219 cmdbuf[1] = 0xa0;
220 cmdbuf[2] = 0x02;
221 cmdbuf[3] = 0x03;
222 cmdbuf[4] = 0x06;
223 cmdbuf[5] = 0x10; /* 06 10 == TONE_CURVE_SIZE */
224 if ((ret = send_data(dev, endp_down,
225 cmdbuf, 6)))
226 goto done;
227
228 /* Send the payload over */
229 if ((ret = send_data(dev, endp_down,
230 (uint8_t *) data, TONE_CURVE_SIZE)))
231 goto done;
232
233 /* get the response */
234 ret = read_data(dev, endp_up,
235 respbuf, sizeof(respbuf), &num);
236
237 if (ret < 0)
238 goto done;
239 if (num != 8) {
240 ERROR("Short Read! (%d/%d)\n", num, 8);
241 ret = -6;
242 goto done;
243 }
244 if (respbuf[1] != 0x00) {
245 ERROR("Received unexpected response!\n");
246 ret = -7;
247 goto done;
248 }
249
250 done:
251 free(data);
252
253 return ret;
254 }
255
kodak1400_cmdline(void)256 static void kodak1400_cmdline(void)
257 {
258 DEBUG("\t\t[ -C filename ] # Set tone curve\n");
259 }
260
kodak1400_cmdline_arg(void * vctx,int argc,char ** argv)261 int kodak1400_cmdline_arg(void *vctx, int argc, char **argv)
262 {
263 struct kodak1400_ctx *ctx = vctx;
264 int i, j = 0;
265
266 if (!ctx)
267 return -1;
268
269 while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:")) >= 0) {
270 switch(i) {
271 GETOPT_PROCESS_GLOBAL
272 case 'C':
273 j = kodak1400_set_tonecurve(ctx, optarg);
274 break;
275 default:
276 break; /* Ignore completely */
277 }
278
279 if (j) return j;
280 }
281
282 return 0;
283 }
284
kodak1400_init(void)285 static void *kodak1400_init(void)
286 {
287 struct kodak1400_ctx *ctx = malloc(sizeof(struct kodak1400_ctx));
288 if (!ctx) {
289 ERROR("Memory Allocation Failure!\n");
290 return NULL;
291 }
292 memset(ctx, 0, sizeof(struct kodak1400_ctx));
293
294 return ctx;
295 }
296
kodak1400_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)297 static int kodak1400_attach(void *vctx, struct libusb_device_handle *dev, int type,
298 uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
299 {
300 struct kodak1400_ctx *ctx = vctx;
301
302 UNUSED(jobid);
303
304 ctx->dev = dev;
305 ctx->endp_up = endp_up;
306 ctx->endp_down = endp_down;
307 ctx->type = type;
308
309 ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
310 ctx->marker.name = "Unknown";
311 ctx->marker.levelmax = -1;
312 ctx->marker.levelnow = -2;
313
314 return CUPS_BACKEND_OK;
315 }
316
kodak1400_cleanup_job(const void * vjob)317 static void kodak1400_cleanup_job(const void *vjob)
318 {
319 const struct kodak1400_printjob *job = vjob;
320
321 if (job->plane_r)
322 free(job->plane_r);
323 if (job->plane_g)
324 free(job->plane_g);
325 if (job->plane_b)
326 free(job->plane_b);
327
328 free((void*)job);
329 }
330
kodak1400_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)331 static int kodak1400_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
332 struct kodak1400_ctx *ctx = vctx;
333 int i, ret;
334
335 struct kodak1400_printjob *job = NULL;
336
337 if (!ctx)
338 return CUPS_BACKEND_FAILED;
339
340 job = malloc(sizeof(*job));
341 if (!job) {
342 ERROR("Memory allocation failure!\n");
343 return CUPS_BACKEND_RETRY_CURRENT;
344 }
345 memset(job, 0, sizeof(*job));
346 job->copies = copies;
347
348 /* Read in then validate header */
349 ret = read(data_fd, &job->hdr, sizeof(job->hdr));
350 if (ret < 0 || ret != sizeof(job->hdr)) {
351 if (ret == 0)
352 return CUPS_BACKEND_CANCEL;
353 ERROR("Read failed (%d/%d/%d)\n",
354 ret, 0, (int)sizeof(job->hdr));
355 perror("ERROR: Read failed");
356 return CUPS_BACKEND_CANCEL;
357 }
358 if (job->hdr.hdr[0] != 'P' ||
359 job->hdr.hdr[1] != 'G' ||
360 job->hdr.hdr[2] != 'H' ||
361 job->hdr.hdr[3] != 'D') {
362 ERROR("Unrecognized data format!\n");
363 return CUPS_BACKEND_CANCEL;
364 }
365 job->hdr.planesize = le32_to_cpu(job->hdr.planesize);
366 job->hdr.rows = le16_to_cpu(job->hdr.rows);
367 job->hdr.columns = le16_to_cpu(job->hdr.columns);
368
369 /* Set up plane data */
370 job->plane_r = malloc(job->hdr.planesize);
371 job->plane_g = malloc(job->hdr.planesize);
372 job->plane_b = malloc(job->hdr.planesize);
373 if (!job->plane_r || !job->plane_g || !job->plane_b) {
374 ERROR("Memory allocation failure!\n");
375 return CUPS_BACKEND_RETRY_CURRENT;
376 }
377 for (i = 0 ; i < job->hdr.rows ; i++) {
378 int j;
379 uint8_t *ptr;
380 for (j = 0 ; j < 3 ; j++) {
381 int remain;
382 if (j == 0)
383 ptr = job->plane_r + i * job->hdr.columns;
384 else if (j == 1)
385 ptr = job->plane_g + i * job->hdr.columns;
386 else if (j == 2)
387 ptr = job->plane_b + i * job->hdr.columns;
388 else
389 ptr = NULL;
390
391 remain = job->hdr.columns;
392 do {
393 ret = read(data_fd, ptr, remain);
394 if (ret < 0) {
395 ERROR("Read failed (%d/%d/%u) (%d/%u @ %d)\n",
396 ret, remain, job->hdr.columns,
397 i, job->hdr.rows, j);
398 perror("ERROR: Read failed");
399 return CUPS_BACKEND_CANCEL;
400 }
401 ptr += ret;
402 remain -= ret;
403 } while (remain);
404 }
405 }
406
407 *vjob = job;
408
409 return CUPS_BACKEND_OK;
410 }
411
412 static uint8_t idle_data[READBACK_LEN] = { 0xe4, 0x72, 0x00, 0x00,
413 0x00, 0x00, 0x00, 0x00 };
414
kodak1400_main_loop(void * vctx,const void * vjob)415 static int kodak1400_main_loop(void *vctx, const void *vjob) {
416 struct kodak1400_ctx *ctx = vctx;
417
418 uint8_t rdbuf[READBACK_LEN], rdbuf2[READBACK_LEN];
419 uint8_t cmdbuf[CMDBUF_LEN];
420 int last_state = -1, state = S_IDLE;
421 int num, ret;
422 uint16_t temp16;
423 int copies;
424
425 const struct kodak1400_printjob *job = vjob;
426
427 if (!ctx)
428 return CUPS_BACKEND_FAILED;
429 if (!job)
430 return CUPS_BACKEND_FAILED;
431
432 copies = job->copies;
433
434 top:
435 if (state != last_state) {
436 if (dyesub_debug)
437 DEBUG("last_state %d new %d\n", last_state, state);
438 }
439
440 /* Send Status Query */
441 memset(cmdbuf, 0, CMDBUF_LEN);
442 cmdbuf[0] = 0x1b;
443 cmdbuf[1] = 0x72;
444
445 if ((ret = send_data(ctx->dev, ctx->endp_down,
446 cmdbuf, CMDBUF_LEN)))
447 return CUPS_BACKEND_FAILED;
448
449 /* Read in the printer status */
450 ret = read_data(ctx->dev, ctx->endp_up,
451 rdbuf, READBACK_LEN, &num);
452
453 if (ret < 0)
454 return CUPS_BACKEND_FAILED;
455 if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
456 memcpy(rdbuf2, rdbuf, READBACK_LEN);
457 } else if (state == last_state) {
458 sleep(1);
459 }
460 last_state = state;
461
462 /* Error handling */
463 if (rdbuf[4] || rdbuf[5]) {
464 ERROR("Error code reported by printer (%02x/%02x), terminating print\n",
465 rdbuf[4], rdbuf[5]);
466 return CUPS_BACKEND_STOP; // HOLD/CANCEL/FAILED? XXXX parse error!
467 }
468
469 fflush(stderr);
470
471 switch (state) {
472 case S_IDLE:
473 INFO("Printing started\n");
474
475 /* Send reset/attention */
476 memset(cmdbuf, 0, CMDBUF_LEN);
477 cmdbuf[0] = 0x1b;
478
479 if ((ret = send_data(ctx->dev, ctx->endp_down,
480 cmdbuf, CMDBUF_LEN)))
481 return CUPS_BACKEND_FAILED;
482
483 /* Send page setup */
484 memset(cmdbuf, 0, CMDBUF_LEN);
485 cmdbuf[0] = 0x1b;
486 cmdbuf[1] = 0x5a;
487 cmdbuf[2] = 0x53;
488 temp16 = be16_to_cpu(job->hdr.columns);
489 memcpy(cmdbuf+3, &temp16, 2);
490 temp16 = be16_to_cpu(job->hdr.rows);
491 memcpy(cmdbuf+5, &temp16, 2);
492
493 if ((ret = send_data(ctx->dev, ctx->endp_down,
494 cmdbuf, CMDBUF_LEN)))
495 return CUPS_BACKEND_FAILED;
496
497 /* Send lamination toggle? */
498 memset(cmdbuf, 0, CMDBUF_LEN);
499 cmdbuf[0] = 0x1b;
500 cmdbuf[1] = 0x59;
501 cmdbuf[2] = job->hdr.matte; // ???
502
503 if ((ret = send_data(ctx->dev, ctx->endp_down,
504 cmdbuf, CMDBUF_LEN)))
505 return CUPS_BACKEND_FAILED;
506
507 /* Send matte toggle */
508 memset(cmdbuf, 0, CMDBUF_LEN);
509 cmdbuf[0] = 0x1b;
510 cmdbuf[1] = 0x60;
511 cmdbuf[2] = job->hdr.laminate;
512
513 if (send_data(ctx->dev, ctx->endp_down,
514 cmdbuf, CMDBUF_LEN))
515 return CUPS_BACKEND_FAILED;
516
517 /* Send lamination strength */
518 memset(cmdbuf, 0, CMDBUF_LEN);
519 cmdbuf[0] = 0x1b;
520 cmdbuf[1] = 0x62;
521 cmdbuf[2] = job->hdr.lam_strength;
522
523 if ((ret = send_data(ctx->dev, ctx->endp_down,
524 cmdbuf, CMDBUF_LEN)))
525 return CUPS_BACKEND_FAILED;
526
527 /* Send unknown */
528 memset(cmdbuf, 0, CMDBUF_LEN);
529 cmdbuf[0] = 0x1b;
530 cmdbuf[1] = 0x61;
531 cmdbuf[2] = job->hdr.unk1; // ???
532
533 if ((ret = send_data(ctx->dev, ctx->endp_down,
534 cmdbuf, CMDBUF_LEN)))
535 return CUPS_BACKEND_FAILED;
536
537 state = S_PRINTER_READY_Y;
538 break;
539 case S_PRINTER_READY_Y:
540 INFO("Sending YELLOW plane\n");
541 if ((ret = send_plane(ctx, job, 1, job->plane_b, cmdbuf)))
542 return CUPS_BACKEND_FAILED;
543 state = S_PRINTER_SENT_Y;
544 break;
545 case S_PRINTER_SENT_Y:
546 if (!memcmp(rdbuf, idle_data, READBACK_LEN))
547 state = S_PRINTER_READY_M;
548 break;
549 case S_PRINTER_READY_M:
550 INFO("Sending MAGENTA plane\n");
551 if ((ret = send_plane(ctx, job, 2, job->plane_g, cmdbuf)))
552 return CUPS_BACKEND_FAILED;
553 state = S_PRINTER_SENT_M;
554 break;
555 case S_PRINTER_SENT_M:
556 if (!memcmp(rdbuf, idle_data, READBACK_LEN))
557 state = S_PRINTER_READY_C;
558 break;
559 case S_PRINTER_READY_C:
560 INFO("Sending CYAN plane\n");
561 if ((ret = send_plane(ctx, job, 3, job->plane_r, cmdbuf)))
562 return CUPS_BACKEND_FAILED;
563 state = S_PRINTER_SENT_C;
564 break;
565 case S_PRINTER_SENT_C:
566 if (!memcmp(rdbuf, idle_data, READBACK_LEN)) {
567 if (job->hdr.laminate)
568 state = S_PRINTER_READY_L;
569 else
570 state = S_PRINTER_DONE;
571 }
572 break;
573 case S_PRINTER_READY_L:
574 INFO("Laminating page\n");
575 if ((ret = send_plane(ctx, job, 4, NULL, cmdbuf)))
576 return CUPS_BACKEND_FAILED;
577 state = S_PRINTER_SENT_L;
578 break;
579 case S_PRINTER_SENT_L:
580 if (!memcmp(rdbuf, idle_data, READBACK_LEN))
581 state = S_PRINTER_DONE;
582 break;
583 case S_PRINTER_DONE:
584 INFO("Cleaning up\n");
585 /* Cleanup */
586 memset(cmdbuf, 0, CMDBUF_LEN);
587 cmdbuf[0] = 0x1b;
588 cmdbuf[1] = 0x74;
589 cmdbuf[2] = 0x00;
590 cmdbuf[3] = 0x50;
591
592 if ((ret = send_data(ctx->dev, ctx->endp_down,
593 cmdbuf, CMDBUF_LEN)))
594 return CUPS_BACKEND_FAILED;
595
596 state = S_FINISHED;
597 break;
598 default:
599 break;
600 };
601
602 if (state != S_FINISHED)
603 goto top;
604
605 /* Clean up */
606 if (terminate)
607 copies = 1;
608
609 INFO("Print complete (%d copies remaining)\n", copies - 1);
610
611 if (copies && --copies) {
612 state = S_IDLE;
613 goto top;
614 }
615
616 return CUPS_BACKEND_OK;
617 }
618
kodak1400_query_markers(void * vctx,struct marker ** markers,int * count)619 static int kodak1400_query_markers(void *vctx, struct marker **markers, int *count)
620 {
621 struct kodak1400_ctx *ctx = vctx;
622
623 *markers = &ctx->marker;
624 *count = 1;
625
626 return CUPS_BACKEND_OK;
627 }
628
629 /* Exported */
630 #define USB_VID_KODAK 0x040A
631 #define USB_PID_KODAK_1400 0x4022
632 #define USB_PID_KODAK_805 0x4034
633 #define USB_VID_MITSU 0x06D3
634 #define USB_PID_MITSU_3020D 0x038B
635 #define USB_PID_MITSU_3020DA 0x03AA
636
637 static const char *kodak1400_prefixes[] = {
638 "kodak1400", // Family driver, do NOT nuke!
639 "kodak-1400", "kodak-805", "mitsubishi-3020d", "mitsubishi-3020da",
640 // backwards compatibility
641 "kodak805", "mitsu3020d", "mitsu3020da",
642 // Extras.
643 "mitsubishi-3020dae", "mitsubishi-3020de", "mitsubishi-3020du",
644 NULL,
645 };
646
647 struct dyesub_backend kodak1400_backend = {
648 .name = "Kodak 1400/805",
649 .version = "0.40",
650 .uri_prefixes = kodak1400_prefixes,
651 .cmdline_usage = kodak1400_cmdline,
652 .cmdline_arg = kodak1400_cmdline_arg,
653 .init = kodak1400_init,
654 .attach = kodak1400_attach,
655 .cleanup_job = kodak1400_cleanup_job,
656 .read_parse = kodak1400_read_parse,
657 .main_loop = kodak1400_main_loop,
658 .query_markers = kodak1400_query_markers,
659 .devices = {
660 { USB_VID_KODAK, USB_PID_KODAK_1400, P_KODAK_1400_805, "Kodak", "kodak-1400"},
661 { USB_VID_KODAK, USB_PID_KODAK_805, P_KODAK_1400_805, "Kodak", "kodak-805"},
662 { USB_VID_MITSU, USB_PID_MITSU_3020D, P_KODAK_1400_805, NULL, "mitsubishi-3020d"},
663 { USB_VID_MITSU, USB_PID_MITSU_3020DA, P_KODAK_1400_805, NULL, "mitsubishi-3020da" },
664 { 0, 0, 0, NULL, NULL}
665 }
666 };
667
668 /* Kodak 1400/805 data format
669
670 Spool file consists of 36-byte header followed by row-interleaved BGR data.
671 Native printer resolution is 2560 pixels per row, and 3010 or 3612 rows.
672
673 Header:
674
675 50 47 48 44 "PGHD"
676 XX XX Number of columns, Little endian. Fixed at 2560.
677 00 00 NULL
678 XX XX Number of rows, Little Endian
679 00 00 NULL
680 XX XX XX XX Number of bytes per plane, Little Endian
681 00 00 00 00 NULL
682 XX 00 Glossy, 01 Matte (Note: Kodak805 only supports Glossy)
683 XX 01 to laminate, 00 to not.
684 01 Unknown, always set to 01
685 XX Lamination Strength:
686
687 3c Glossy
688 28 Matte +5
689 2e Matte +4
690 34 Matte +3
691 3a Matte +2
692 40 Matte +1
693 46 Matte
694 52 Matte -1
695 5e Matte -2
696 6a Matte -3
697 76 Matte -4
698 82 Matte -5
699
700 00 00 00 00 00 00 00 00 00 00 00 00 NULL
701
702 ************************************************************************
703
704 The data format actually sent to the Kodak 1400 is rather different.
705
706 All commands are null-padded to 96 bytes.
707 All readback values are 8 bytes long.
708
709 Multi-byte numbers are sent BIG ENDIAN.
710
711 Image data is sent via planes, one scanline per URB.
712
713 <-- 1b 72 # Status query
714 --> e4 72 00 00 00 00 00 00 # Idle response
715
716 <-- 1b 00 # Reset/attention?
717 <-- 1b 5a 53 0a 00 0b c2 # Setup (ie hdr.columns and hdr.rows)
718 <-- 1b 59 01 # ?? hdr.matte ?
719 <-- 1b 60 XX # hdr.lamination
720 <-- 1b 62 XX # hdr.lam_strength
721 <-- 1b 61 01 # ?? hdr.unk1 ?
722
723 <-- 1b 5a 54 01 00 00 00 0a 00 0b c2 # start of plane 1 data
724 <-- row 1
725 <-- row 2
726 <-- row last
727
728 <-- 1b 74 01 50 # ??
729
730 <-- 1b 72 # Status query
731 --> e4 72 00 00 00 00 50 59 # Printing plane 1
732 [ repeats until...]
733 <-- 1b 72 # Status query
734 --> e4 72 00 00 40 00 50 59 # Paper loaded?
735 [ repeats until...]
736 <-- 1b 72 # Status query
737 --> e4 72 00 00 00 00 50 59 # Printing plane 1
738 [ repeats until...]
739 <-- 1b 72 # Status query
740 --> e4 72 00 00 00 00 00 00 # Idle response
741
742 <-- 1b 74 00 50 # ??
743 <-- 1b 5a 54 02 00 00 00 0a 00 0b c2 # start of plane 2 data
744 <-- row 1
745 <-- row 2
746 <-- row last
747 <-- 1b 74 01 50 # ??
748
749 <-- 1b 72 # Status query
750 --> e4 72 00 00 00 00 50 4d # Printing plane 2
751 [ repeats until...]
752 <-- 1b 72 # Status query
753 --> e4 72 00 00 00 00 00 00 # Idle response
754
755 <-- 1b 74 00 50 # ??
756 <-- 1b 5a 54 03 00 00 00 0a 00 0b c2 # start of plane 3 data
757 <-- row 1
758 <-- row 2
759 <-- row last
760 <-- 1b 74 01 50 # ??
761
762 <-- 1b 72 # Status query
763 --> e4 72 00 00 00 00 50 43 # Printing plane 3
764 [ repeats until...]
765 <-- 1b 72 # Status query
766 --> e4 72 00 00 00 00 00 00 # Idle response
767
768 ## this block is only present if lamination is used
769
770 <-- 1b 74 00 50 # ??
771 <-- 1b 5a 54 04 # start of lamination
772 <-- 1b 74 01 50 # ??
773
774 <-- 1b 72 # Status query
775 --> e4 72 00 00 00 00 50 50 # Laminating
776 [ repeats until...]
777 <-- 1b 72 # Status query
778 --> e4 72 00 00 00 00 00 00 # Idle response
779
780 ## end lamination block
781
782 <-- 1b 74 00 50 # ??
783
784 [[ DONE ]]
785
786 Other readback codes seen:
787
788 e4 72 00 00 40 00 50 59 -- ?? paper jam?
789 e4 72 00 00 10 00 50 59 -- media red blink, error red blink, [media mismatch]]
790 e4 72 00 00 10 01 50 59 -- ???
791 e4 72 00 00 00 04 50 59 -- media red blink, error red [media too small for image ?]
792 e4 72 00 00 02 00 50 59 -- media off, error red. [out of paper]
793 e4 72 00 00 02 01 00 00 -- media off, error red. [out of paper]
794 e4 72 00 00 02 00 00 00 -- media off, error red. [out of paper]
795 e4 72 00 00 02 00 50 50 -- media on, error red. [paper jam while laminating]
796
797 *********************************************
798 Calibration data:
799
800 <-- 1b a2 # ?? Reset cal tables?
801 --> 00 01 00 00 00 00 00 00
802
803 <-- 1b a0 02 03 06 10 # 06 10 == 1552 bytes aka the CAL data.
804 <-- cal data
805
806 [[ Data is organized as three blocks of 512 bytes followed by
807 16 NULL bytes.
808
809 Each block appears to be 256 entries of 16-bit LE data,
810 so each input value is translated into a 16-bit number in the printer.
811
812 Assuming blocks are ordered BGR.
813
814 ]]
815
816 --> 00 00 00 00 00 00 00 00
817
818 */
819