2013-12-03 22:21:44 -05:00
|
|
|
/*
|
2018-04-10 21:18:05 -04:00
|
|
|
* Citizen / DNP Photo Printer CUPS backend -- libusb-1.0 version
|
2013-12-03 22:21:44 -05:00
|
|
|
*
|
2023-03-19 21:33:55 -04:00
|
|
|
* (c) 2013-2023 Solomon Peachy <pizza@shaftnet.org>
|
2013-12-03 22:21:44 -05:00
|
|
|
*
|
2013-12-17 08:31:45 -05:00
|
|
|
* Development of this backend was sponsored by:
|
|
|
|
*
|
2014-06-03 20:43:31 -04:00
|
|
|
* Marco Di Antonio and [ ilgruppodigitale.com ]
|
|
|
|
* LiveLink Technology [ www.livelinktechnology.net ]
|
2016-02-08 17:53:28 -05:00
|
|
|
* A generous benefactor who wishes to remain anonymous
|
2013-12-17 08:31:45 -05:00
|
|
|
*
|
2013-12-03 22:21:44 -05:00
|
|
|
* The latest version of this program can be found at:
|
2013-12-10 08:54:07 -05:00
|
|
|
*
|
2021-01-23 10:47:01 -05:00
|
|
|
* https://git.shaftnet.org/cgit/selphy_print.git
|
2013-12-10 08:54:07 -05:00
|
|
|
*
|
2013-12-03 22:21:44 -05:00
|
|
|
* 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
|
2020-01-17 16:50:56 -05:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2013-12-03 22:21:44 -05:00
|
|
|
*
|
2017-11-17 13:34:26 -05:00
|
|
|
* SPDX-License-Identifier: GPL-3.0+
|
|
|
|
*
|
2013-12-03 22:21:44 -05:00
|
|
|
*/
|
|
|
|
|
2015-06-22 23:51:17 -04:00
|
|
|
//#define DNP_ONLY
|
2018-03-16 18:28:30 -04:00
|
|
|
//#define CITIZEN_ONLY
|
2016-02-07 09:09:42 -05:00
|
|
|
|
2017-07-10 20:15:56 -04:00
|
|
|
/* Enables caching of last print type to speed up
|
2016-02-07 09:09:42 -05:00
|
|
|
job pipelining. Without this we always have to
|
|
|
|
assume the worst */
|
|
|
|
//#define STATE_DIR "/tmp"
|
2015-06-22 23:51:17 -04:00
|
|
|
|
2015-08-13 21:09:56 -04:00
|
|
|
#define BACKEND dnpds40_backend
|
|
|
|
|
2013-12-03 22:21:44 -05:00
|
|
|
#include "backend_common.h"
|
|
|
|
|
2019-08-07 00:22:59 -04:00
|
|
|
#include <time.h>
|
|
|
|
|
2017-05-05 08:06:28 -04:00
|
|
|
/* Private data structure */
|
2018-06-15 14:55:03 -04:00
|
|
|
struct dnpds40_printjob {
|
2021-09-30 14:52:11 -04:00
|
|
|
struct dyesub_job_common common;
|
2020-01-21 11:08:26 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
uint8_t *databuf;
|
|
|
|
int datalen;
|
|
|
|
|
|
|
|
uint32_t dpi;
|
|
|
|
int matte;
|
|
|
|
int cutter;
|
|
|
|
uint32_t multicut;
|
|
|
|
int fullcut;
|
|
|
|
int printspeed;
|
|
|
|
int can_rewind;
|
2020-01-21 11:08:26 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
int buf_needed;
|
2019-05-16 20:56:43 -04:00
|
|
|
int cut_paper;
|
2018-06-15 14:55:03 -04:00
|
|
|
};
|
|
|
|
|
2021-06-09 19:43:06 -04:00
|
|
|
#define MFG_DNP 0
|
|
|
|
#define MFG_CITIZEN 1
|
|
|
|
#define MFG_MITSUBISHI 2
|
|
|
|
#define MFG_OTHER 3
|
|
|
|
|
2013-12-03 22:21:44 -05:00
|
|
|
struct dnpds40_ctx {
|
2020-08-11 20:27:26 -04:00
|
|
|
struct dyesub_connection *conn;
|
2013-12-03 22:21:44 -05:00
|
|
|
|
2021-06-09 19:43:06 -04:00
|
|
|
int mfg; /* see MFG_* */
|
2013-12-03 22:21:44 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
/* Version and whatnot */
|
2015-06-17 22:57:31 -04:00
|
|
|
char *serno;
|
|
|
|
char *version;
|
2015-06-13 17:20:19 -04:00
|
|
|
int ver_major;
|
|
|
|
int ver_minor;
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
/* State */
|
2016-08-21 09:50:05 -04:00
|
|
|
uint32_t media;
|
2019-09-21 20:59:05 -04:00
|
|
|
uint32_t media_subtype;
|
|
|
|
|
|
|
|
char media_text[32];
|
2016-08-21 09:50:05 -04:00
|
|
|
uint32_t duplex_media;
|
2019-05-16 20:56:43 -04:00
|
|
|
int duplex_media_status;
|
2016-08-21 09:50:05 -04:00
|
|
|
uint16_t media_count_new;
|
|
|
|
|
2015-09-03 01:22:56 -04:00
|
|
|
uint32_t last_multicut;
|
2016-08-21 09:50:05 -04:00
|
|
|
int last_matte;
|
2020-10-22 09:08:03 -04:00
|
|
|
int partialmatte;
|
2016-08-21 09:50:05 -04:00
|
|
|
|
2021-05-16 00:16:50 -04:00
|
|
|
int media_sticker;
|
2016-07-19 17:12:00 -04:00
|
|
|
int mediaoffset;
|
|
|
|
int correct_count;
|
2018-02-28 19:21:40 -05:00
|
|
|
int needs_mlot;
|
2016-08-21 09:50:05 -04:00
|
|
|
|
2019-05-16 20:56:43 -04:00
|
|
|
struct marker marker[2];
|
|
|
|
int marker_count;
|
2018-04-27 15:40:09 -04:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
/* Printer capabilities */
|
2017-01-05 16:08:55 -05:00
|
|
|
uint32_t native_width;
|
2018-06-15 14:56:41 -04:00
|
|
|
uint32_t max_height;
|
2020-03-09 18:55:52 -04:00
|
|
|
int supports_600dpi;
|
2015-06-13 17:20:19 -04:00
|
|
|
int supports_6x9;
|
|
|
|
int supports_2x6;
|
2015-06-13 22:34:54 -04:00
|
|
|
int supports_3x5x2;
|
2020-09-09 20:23:52 -04:00
|
|
|
int supports_a4x6;
|
2022-09-28 15:33:13 -04:00
|
|
|
int supports_45_34;
|
2015-06-13 17:20:19 -04:00
|
|
|
int supports_matte;
|
2016-12-27 09:29:46 -05:00
|
|
|
int supports_finematte;
|
2017-07-10 20:15:56 -04:00
|
|
|
int supports_luster;
|
2017-01-05 16:08:55 -05:00
|
|
|
int supports_advmatte;
|
2015-06-14 09:05:55 -04:00
|
|
|
int supports_fullcut;
|
|
|
|
int supports_rewind;
|
|
|
|
int supports_standby;
|
2020-03-09 19:04:29 -04:00
|
|
|
int supports_keepmode;
|
2015-06-22 18:46:26 -04:00
|
|
|
int supports_6x4_5;
|
2015-07-11 15:12:47 -04:00
|
|
|
int supports_mqty_default;
|
2015-08-06 09:54:49 -04:00
|
|
|
int supports_iserial;
|
2016-02-03 22:53:57 -05:00
|
|
|
int supports_6x6;
|
|
|
|
int supports_5x5;
|
2015-08-28 20:46:03 -04:00
|
|
|
int supports_counterp;
|
2016-01-21 19:16:52 -05:00
|
|
|
int supports_adv_fullcut;
|
2016-07-19 17:12:00 -04:00
|
|
|
int supports_mediaoffset;
|
2020-03-09 18:55:52 -04:00
|
|
|
int supports_ctrld_ext;
|
2017-01-05 16:08:55 -05:00
|
|
|
int supports_media_ext;
|
|
|
|
int supports_printspeed;
|
|
|
|
int supports_lowspeed;
|
|
|
|
int supports_highdensity;
|
2019-08-07 00:22:59 -04:00
|
|
|
int supports_systime;
|
2020-03-09 16:15:02 -04:00
|
|
|
int supports_mediaclassrfid;
|
2017-01-05 16:08:55 -05:00
|
|
|
int supports_gamma;
|
2013-12-03 22:21:44 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct dnpds40_cmd {
|
2013-12-16 20:15:48 -05:00
|
|
|
uint8_t esc; /* Fixed at ascii ESC, aka 0x1B */
|
|
|
|
uint8_t p; /* Fixed at ascii 'P' aka 0x50 */
|
2013-12-03 22:21:44 -05:00
|
|
|
uint8_t arg1[6];
|
|
|
|
uint8_t arg2[16];
|
|
|
|
uint8_t arg3[8]; /* Decimal value of arg4's length, or empty */
|
2013-12-08 07:14:27 -05:00
|
|
|
uint8_t arg4[0]; /* Extra payload if arg3 is non-empty
|
|
|
|
Doesn't have to be sent in the same URB */
|
2013-12-03 22:21:44 -05:00
|
|
|
|
2013-12-08 07:14:27 -05:00
|
|
|
/* All unused elements are set to 0x20 (ie ascii space) */
|
2013-12-03 22:21:44 -05:00
|
|
|
};
|
|
|
|
|
2016-02-03 22:48:54 -05:00
|
|
|
#define MULTICUT_5x3_5 1
|
|
|
|
#define MULTICUT_6x4 2
|
|
|
|
#define MULTICUT_5x7 3
|
|
|
|
#define MULTICUT_6x8 4
|
|
|
|
#define MULTICUT_6x9 5
|
|
|
|
#define MULTICUT_8x10 6
|
|
|
|
#define MULTICUT_8x12 7
|
|
|
|
#define MULTICUT_8x4 8
|
|
|
|
#define MULTICUT_8x5 9
|
|
|
|
#define MULTICUT_8x6 10
|
|
|
|
#define MULTICUT_8x8 11
|
|
|
|
#define MULTICUT_6x4X2 12
|
|
|
|
#define MULTICUT_8x4X2 13
|
|
|
|
#define MULTICUT_8x5X2 14
|
|
|
|
#define MULTICUT_8x6X2 15
|
|
|
|
#define MULTICUT_8x5_8x4 16
|
|
|
|
#define MULTICUT_8x6_8x4 17
|
|
|
|
#define MULTICUT_8x6_8x5 18
|
|
|
|
#define MULTICUT_8x8_8x4 19
|
|
|
|
#define MULTICUT_8x4X3 20
|
|
|
|
#define MULTICUT_8xA4LEN 21
|
|
|
|
#define MULTICUT_5x3_5X2 22
|
|
|
|
#define MULTICUT_6x6 27
|
|
|
|
#define MULTICUT_5x5 29
|
|
|
|
#define MULTICUT_6x4_5 30
|
|
|
|
#define MULTICUT_6x4_5X2 31
|
2017-01-05 16:08:55 -05:00
|
|
|
#define MULTICUT_8x7 32
|
|
|
|
#define MULTICUT_8x9 33
|
|
|
|
#define MULTICUT_A5 34
|
|
|
|
#define MULTICUT_A5X2 35
|
|
|
|
#define MULTICUT_A4x4 36
|
|
|
|
#define MULTICUT_A4x5 37
|
|
|
|
#define MULTICUT_A4x6 38
|
|
|
|
#define MULTICUT_A4x8 39
|
|
|
|
#define MULTICUT_A4x10 40
|
|
|
|
#define MULTICUT_A4 41
|
|
|
|
#define MULTICUT_A4x5X2 43
|
|
|
|
|
2019-08-07 00:22:59 -04:00
|
|
|
#define MULTICUT_4x4 47
|
|
|
|
#define MULTICUT_4x6 48
|
|
|
|
#define MULTICUT_4x8 49
|
|
|
|
#define MULTICUT_4_5x4_5 50
|
|
|
|
#define MULTICUT_4_5x6 51
|
|
|
|
#define MULTICUT_4_5x8 52
|
|
|
|
|
2022-10-03 15:50:23 -04:00
|
|
|
#define MULTICUT_4x3 53
|
|
|
|
#define MULTICUT_4x4_5 54
|
|
|
|
#define MULTICUT_4_5x3 55
|
|
|
|
// #define MULTICUT_??? 56 // XXX WTF is missing?
|
|
|
|
#define MULTICUT_4_5x4 57
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// XXX do these exist? Or are they just the larger print cut in two?
|
|
|
|
// #define MULTICUT_4x3X2
|
|
|
|
// #define MULTICUT_4x4X2
|
|
|
|
// #define MULTICUT_4_5x3X2
|
|
|
|
// #define MULTICUT_4_5x4X2
|
|
|
|
#endif
|
2022-09-29 09:48:38 -04:00
|
|
|
|
2016-02-03 22:48:54 -05:00
|
|
|
#define MULTICUT_S_SIMPLEX 100
|
|
|
|
#define MULTICUT_S_FRONT 200
|
|
|
|
#define MULTICUT_S_BACK 300
|
|
|
|
|
|
|
|
#define MULTICUT_S_8x10 6
|
|
|
|
#define MULTICUT_S_8x12 7
|
|
|
|
#define MULTICUT_S_8x4 8
|
|
|
|
#define MULTICUT_S_8x5 9
|
|
|
|
#define MULTICUT_S_8x6 10
|
|
|
|
#define MULTICUT_S_8x8 11
|
|
|
|
#define MULTICUT_S_8x4X2 13
|
|
|
|
#define MULTICUT_S_8x5X2 14
|
|
|
|
#define MULTICUT_S_8x6X2 15
|
|
|
|
#define MULTICUT_S_8x10_5 25
|
|
|
|
#define MULTICUT_S_8x10_75 26
|
|
|
|
#define MULTICUT_S_8x4X3 28 // different than roll type.
|
|
|
|
|
2020-01-25 07:15:02 -05:00
|
|
|
#ifndef min
|
2013-12-03 22:21:44 -05:00
|
|
|
#define min(__x, __y) ((__x) < (__y)) ? __x : __y
|
2020-01-25 07:15:02 -05:00
|
|
|
#endif
|
2013-12-03 22:21:44 -05:00
|
|
|
|
2019-07-14 09:20:17 -04:00
|
|
|
/* Legacy spool file support */
|
2019-07-14 23:51:32 -04:00
|
|
|
static int legacy_cw01_read_parse(struct dnpds40_printjob *job, int data_fd, int read_data);
|
|
|
|
static int legacy_dnp_read_parse(struct dnpds40_printjob *job, int data_fd, int read_data);
|
2019-07-15 22:14:59 -04:00
|
|
|
static int legacy_dnp620_read_parse(struct dnpds40_printjob *job, int data_fd, int read_data);
|
2019-07-15 23:31:32 -04:00
|
|
|
static int legacy_dnp820_read_parse(struct dnpds40_printjob *job, int data_fd, int read_data);
|
2019-08-07 00:22:59 -04:00
|
|
|
static int legacy_qw410_read_parse(struct dnpds40_printjob *job, int data_fd, int read_data);
|
2019-07-14 09:20:17 -04:00
|
|
|
|
2018-06-19 14:00:35 -04:00
|
|
|
static void dnpds40_cleanup_job(const void *vjob);
|
2019-05-16 20:56:43 -04:00
|
|
|
static int dnpds40_query_markers(void *vctx, struct marker **markers, int *count);
|
2018-04-10 21:18:05 -04:00
|
|
|
|
2018-06-16 18:50:26 -04:00
|
|
|
#define JOB_EQUIV(__x) if (job1->__x != job2->__x) goto done
|
|
|
|
|
2020-01-21 11:08:26 -05:00
|
|
|
/* NOTE: Does _not_ free the input jobs */
|
|
|
|
static void *dnp_combine_jobs(const void *vjob1,
|
|
|
|
const void *vjob2)
|
2018-06-16 18:50:26 -04:00
|
|
|
{
|
2020-01-21 11:08:26 -05:00
|
|
|
const struct dnpds40_printjob *job1 = vjob1;
|
|
|
|
const struct dnpds40_printjob *job2 = vjob2;
|
2018-06-16 18:50:26 -04:00
|
|
|
struct dnpds40_printjob *newjob = NULL;
|
|
|
|
uint32_t new_multicut;
|
|
|
|
uint16_t new_w, new_h;
|
2020-01-22 23:09:55 -05:00
|
|
|
int32_t gap_bytes;
|
2018-06-16 18:50:26 -04:00
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if (!job1 || !job2)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Make sure pertinent paremeters are the same */
|
|
|
|
JOB_EQUIV(dpi);
|
|
|
|
JOB_EQUIV(matte);
|
|
|
|
JOB_EQUIV(cutter);
|
|
|
|
JOB_EQUIV(fullcut);
|
|
|
|
JOB_EQUIV(multicut); // TODO: Support fancier modes for 8" models (eg 8x4+8x6, etc)
|
|
|
|
JOB_EQUIV(datalen); // <-- cheating a little?
|
|
|
|
// JOV_EQUIV(printspeed); <-- does it matter?
|
|
|
|
|
2020-01-22 23:09:55 -05:00
|
|
|
/* Any fancy cutter action means we pass */
|
|
|
|
if (job1->fullcut || job1->cutter > 120)
|
2018-06-16 18:50:26 -04:00
|
|
|
goto done;
|
2020-10-22 09:08:03 -04:00
|
|
|
/* Partial matte is no bueno */
|
|
|
|
if (job1->matte > 100 ||
|
|
|
|
job2->matte > 100)
|
|
|
|
goto done;
|
2018-06-16 18:50:26 -04:00
|
|
|
|
|
|
|
/* Make sure we can combine these two prints */
|
|
|
|
switch (job1->multicut) {
|
|
|
|
case MULTICUT_5x3_5:
|
|
|
|
new_multicut = MULTICUT_5x3_5X2;
|
|
|
|
new_w = 1920;
|
|
|
|
new_h = 2176;
|
|
|
|
gap_bytes = 0;
|
|
|
|
break;
|
|
|
|
case MULTICUT_6x4:
|
2020-01-22 22:23:00 -05:00
|
|
|
if (job1->cutter == 120) {
|
2018-06-16 18:50:26 -04:00
|
|
|
new_multicut = MULTICUT_6x8;
|
|
|
|
new_h = 2436;
|
2020-01-22 23:09:55 -05:00
|
|
|
gap_bytes = -44; /* Chop out the middle 44 rows */
|
2018-06-16 18:50:26 -04:00
|
|
|
} else {
|
|
|
|
new_multicut = MULTICUT_6x4X2;
|
|
|
|
new_h = 2498;
|
|
|
|
gap_bytes = 18;
|
|
|
|
}
|
|
|
|
new_w = 1920;
|
|
|
|
break;
|
|
|
|
case MULTICUT_6x4_5:
|
|
|
|
new_multicut = MULTICUT_6x4_5X2;
|
|
|
|
new_w = 1920;
|
|
|
|
new_h = 2802;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
|
|
|
case MULTICUT_8x4:
|
|
|
|
new_multicut = MULTICUT_8x4X2;
|
|
|
|
new_w = 2560;
|
|
|
|
new_h = 2502;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
|
|
|
case MULTICUT_8x5:
|
|
|
|
new_multicut = MULTICUT_8x5X2;
|
|
|
|
new_w = 2560;
|
|
|
|
new_h = 3102;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
2020-09-01 17:16:19 -04:00
|
|
|
case MULTICUT_A4x5:
|
|
|
|
new_multicut = MULTICUT_A4x5X2;
|
|
|
|
new_w = 2560;
|
|
|
|
new_h = 3102;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
2020-09-01 23:18:50 -04:00
|
|
|
case MULTICUT_A5:
|
|
|
|
new_multicut = MULTICUT_A5X2;
|
|
|
|
new_w = 2560;
|
|
|
|
new_h = 3598;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
2018-06-16 18:50:26 -04:00
|
|
|
case MULTICUT_8x6:
|
|
|
|
new_multicut = MULTICUT_8x6X2;
|
|
|
|
new_w = 2560;
|
|
|
|
new_h = 3702;
|
|
|
|
gap_bytes = 30;
|
|
|
|
break;
|
2022-10-03 15:50:23 -04:00
|
|
|
#if 0 // XXX Do these printers handle automatic multicut?
|
|
|
|
// if not, implement using FULL_CUTTER_CONTROL!
|
|
|
|
case MULTICUT_4x3:
|
|
|
|
new_multicut = MULTICUT_4x6;
|
|
|
|
new_w = 1408;
|
|
|
|
new_h = 1836;
|
|
|
|
gap_bytes = 36;
|
|
|
|
break;
|
|
|
|
case MULTICUT_4x4:
|
|
|
|
new_multicut = MULTICUT_4x8;
|
|
|
|
new_w = 1408;
|
|
|
|
new_h = 2436;
|
|
|
|
gap_bytes = 36;
|
|
|
|
break;
|
|
|
|
case MULTICUT_4_5x3:
|
|
|
|
new_multicut = MULTICUT_4_5x6;
|
|
|
|
new_w = 1408;
|
|
|
|
new_h = 1836;
|
|
|
|
gap_bytes = 36;
|
|
|
|
break;
|
|
|
|
case MULTICUT_4_5x4:
|
|
|
|
new_multicut = MULTICUT_4_5x8;
|
|
|
|
new_w = 1408;
|
|
|
|
new_h = 2436;
|
|
|
|
gap_bytes = 36;
|
|
|
|
break;
|
|
|
|
#endif
|
2018-06-16 18:50:26 -04:00
|
|
|
default:
|
|
|
|
/* Everything else is NOT handled */
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
gap_bytes *= new_w;
|
|
|
|
if (job1->dpi == 600) {
|
|
|
|
gap_bytes *= 2;
|
|
|
|
new_h *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG("Combining jobs to save media\n");
|
|
|
|
|
|
|
|
/* Okay, it's kosher to proceed */
|
|
|
|
|
|
|
|
newjob = malloc(sizeof(*newjob));
|
|
|
|
if (!newjob) {
|
|
|
|
ERROR("Memory allocation failure!\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
memcpy(newjob, job1, sizeof(*newjob));
|
|
|
|
|
2020-01-22 23:09:55 -05:00
|
|
|
newjob->databuf = malloc(((new_w*new_h+1024+54+10))*3+1024 + abs(gap_bytes));
|
2018-06-16 18:50:26 -04:00
|
|
|
newjob->datalen = 0;
|
|
|
|
newjob->multicut = new_multicut;
|
2020-01-21 11:08:26 -05:00
|
|
|
newjob->can_rewind = 0;
|
2021-09-30 14:52:11 -04:00
|
|
|
newjob->common.can_combine = 0;
|
2018-06-19 14:00:35 -04:00
|
|
|
if (!newjob->databuf) {
|
|
|
|
dnpds40_cleanup_job(newjob);
|
|
|
|
newjob = NULL;
|
|
|
|
ERROR("Memory allocation failure!\n");
|
|
|
|
goto done;
|
|
|
|
}
|
2018-06-16 18:50:26 -04:00
|
|
|
|
|
|
|
/* Copy data blocks from job1 */
|
|
|
|
uint8_t *ptr, *ptr2;
|
|
|
|
char buf[9];
|
|
|
|
ptr = job1->databuf;
|
|
|
|
while(ptr && ptr < (job1->databuf + job1->datalen)) {
|
|
|
|
int i;
|
|
|
|
buf[8] = 0;
|
|
|
|
memcpy(buf, ptr + 24, 8);
|
|
|
|
i = atoi(buf) + 32;
|
|
|
|
memcpy(newjob->databuf + newjob->datalen, ptr, i);
|
|
|
|
|
|
|
|
/* If we're on a plane data block... */
|
|
|
|
if (!memcmp("PLANE", newjob->databuf + newjob->datalen + 9, 5)) {
|
|
|
|
long planelen = (new_w * new_h) + 1088;
|
|
|
|
uint32_t newlen;
|
|
|
|
|
|
|
|
/* Fix up length in command */
|
|
|
|
snprintf(buf, sizeof(buf), "%08ld", planelen);
|
|
|
|
memcpy(newjob->databuf + newjob->datalen + 24, buf, 8);
|
|
|
|
|
|
|
|
/* Alter BMP header */
|
|
|
|
newlen = cpu_to_le32(planelen);
|
|
|
|
memcpy(newjob->databuf + newjob->datalen + 32 + 2, &newlen, 4);
|
|
|
|
|
|
|
|
/* alter DIB header */
|
|
|
|
newlen = cpu_to_le32(new_h);
|
|
|
|
memcpy(newjob->databuf + newjob->datalen + 32 + 22, &newlen, 4);
|
|
|
|
|
2020-01-22 23:09:55 -05:00
|
|
|
if (gap_bytes > 0) {
|
|
|
|
/* Insert gap/padding after first image */
|
2020-01-31 11:34:08 -05:00
|
|
|
memset(newjob->databuf + newjob->datalen + i, 0xff, gap_bytes);
|
2020-01-22 23:09:55 -05:00
|
|
|
newjob->datalen += gap_bytes;
|
|
|
|
} else {
|
2020-01-22 23:59:22 -05:00
|
|
|
// uint8_t *ptrA = newjob->databuf + newjob->datalen + 1088;
|
2020-01-22 23:09:55 -05:00
|
|
|
// /* Back off by 1/2 the gap */
|
|
|
|
// memmove(ptrA, ptrA - (gap_bytes / 2), (i - 1088) + gap_bytes/2);
|
|
|
|
/* And chop the end off by half the gap */
|
|
|
|
newjob->datalen += gap_bytes / 2;
|
|
|
|
}
|
2018-06-16 18:50:26 -04:00
|
|
|
|
2020-01-22 23:09:55 -05:00
|
|
|
/* Locate job2's PLANE -- Assume it's in the same place! */
|
2018-06-16 18:50:26 -04:00
|
|
|
ptr2 = job2->databuf + (ptr - job1->databuf);
|
2020-01-22 23:09:55 -05:00
|
|
|
|
2018-06-16 18:50:26 -04:00
|
|
|
/* Copy over job2's image data */
|
|
|
|
memcpy(newjob->databuf + newjob->datalen + i,
|
|
|
|
ptr2 + 32 + 1088, i - 32 - 1088);
|
2020-01-22 23:09:55 -05:00
|
|
|
|
|
|
|
if (gap_bytes < 0) {
|
|
|
|
uint8_t *ptrA = newjob->databuf + newjob->datalen + i;
|
|
|
|
/* Back off by 1/2 the gap */
|
|
|
|
memmove(ptrA, ptrA - (gap_bytes / 2), (i - 1088) + gap_bytes/2);
|
|
|
|
/* And chop the end off by half the gap */
|
|
|
|
newjob->datalen += gap_bytes / 2;
|
|
|
|
}
|
2018-06-16 18:50:26 -04:00
|
|
|
newjob->datalen += i - 32 - 1088; /* add in job2 length */
|
|
|
|
}
|
|
|
|
|
|
|
|
newjob->datalen += i;
|
|
|
|
ptr += i;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return newjob;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef JOB_EQUIV
|
|
|
|
|
2020-03-24 18:22:39 -04:00
|
|
|
static void dnpds40_build_cmd(struct dnpds40_cmd *cmd, const char *arg1, const char *arg2, uint32_t arg3_len)
|
2013-12-03 22:21:44 -05:00
|
|
|
{
|
|
|
|
memset(cmd, 0x20, sizeof(*cmd));
|
|
|
|
cmd->esc = 0x1b;
|
|
|
|
cmd->p = 0x50;
|
|
|
|
memcpy(cmd->arg1, arg1, min(strlen(arg1), sizeof(cmd->arg1)));
|
|
|
|
memcpy(cmd->arg2, arg2, min(strlen(arg2), sizeof(cmd->arg2)));
|
2013-12-16 20:15:48 -05:00
|
|
|
if (arg3_len) {
|
2020-03-22 20:58:39 -04:00
|
|
|
char buf[11]; /* Extra padding to shut up GCC 10 */
|
2014-02-11 20:11:33 -05:00
|
|
|
snprintf(buf, sizeof(buf), "%08u", arg3_len);
|
2013-12-16 20:15:48 -05:00
|
|
|
memcpy(cmd->arg3, buf, 8);
|
|
|
|
}
|
2013-12-03 22:21:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dnpds40_cleanup_string(char *start, int len)
|
|
|
|
{
|
|
|
|
char *ptr = strchr(start, 0x0d);
|
|
|
|
|
2014-02-11 20:49:08 -05:00
|
|
|
if (ptr && (ptr - start < len)) {
|
2013-12-03 22:21:44 -05:00
|
|
|
*ptr = 0x00; /* If there is a <CR>, terminate there */
|
2014-02-11 20:49:08 -05:00
|
|
|
len = ptr - start;
|
|
|
|
} else {
|
|
|
|
start[--len] = 0x00; /* force null-termination */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Trim trailing spaces */
|
|
|
|
while (len && start[len-1] == ' ') {
|
|
|
|
start[--len] = 0;
|
|
|
|
}
|
2013-12-03 22:21:44 -05:00
|
|
|
}
|
|
|
|
|
2019-12-13 15:23:25 -05:00
|
|
|
static const char *dnpds40_printer_type(int type, int mfg)
|
2016-07-15 18:54:02 -04:00
|
|
|
{
|
|
|
|
switch(type) {
|
2021-06-11 07:50:48 -04:00
|
|
|
case P_DNP_DS40: return mfg == MFG_CITIZEN? "CX" : "DS40";
|
|
|
|
case P_DNP_DS80: return mfg == MFG_CITIZEN? "CW" : (mfg == MFG_MITSUBISHI ? "CP3800" : "DS80");
|
2016-07-15 18:54:02 -04:00
|
|
|
case P_DNP_DS80D: return "DS80DX";
|
2021-06-11 07:50:48 -04:00
|
|
|
case P_DNP_DSRX1: return mfg == MFG_CITIZEN ? "CY" : "DSRX1";
|
|
|
|
case P_DNP_DS620: return mfg == MFG_CITIZEN ? "CX-02" : "DS620";
|
|
|
|
case P_DNP_DS820: return mfg == MFG_CITIZEN ? "CX-02W" : "DS820";
|
|
|
|
case P_DNP_QW410: return mfg == MFG_CITIZEN ? "CZ-01" : "QW410";
|
2018-04-10 21:18:05 -04:00
|
|
|
case P_CITIZEN_CW01: return "CW01";
|
2019-12-13 15:23:25 -05:00
|
|
|
case P_CITIZEN_OP900II: return "CW-02 / OP900ii";
|
2016-07-15 18:54:02 -04:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2021-05-16 00:16:50 -04:00
|
|
|
static const char *dnpds40_media_types(int media, int sticker)
|
2013-12-03 22:21:44 -05:00
|
|
|
{
|
2015-06-22 23:55:48 -04:00
|
|
|
switch (media) {
|
2016-06-12 12:43:12 -04:00
|
|
|
case 100: return "UNKNOWN100"; // seen in driver dumps
|
|
|
|
case 110: return "UNKNOWN110"; // seen in driver dumps
|
2019-08-07 00:22:59 -04:00
|
|
|
case 150: return "4x6 (PC)";
|
|
|
|
case 151: return "4x8";
|
|
|
|
case 160: return "4.5x6";
|
|
|
|
case 161: return "4.5x8";
|
2021-05-16 00:16:50 -04:00
|
|
|
case 200: return sticker ? "5x3.5 (L): Sticker" : "5x3.5 (L)";
|
|
|
|
case 210: return sticker ? "5x7 (2L) Sticker" : "5x7 (2L)";
|
|
|
|
case 300: return sticker ? "6x4 (PC) Sticker" : "6x4 (PC)";
|
|
|
|
case 310: return sticker ? "6x8 (A5) Sticker" : "6x8 (A5)";
|
|
|
|
case 400: return sticker ? "6x9 (A5W) Sticker" : "6x9 (A5W)";
|
2013-12-03 22:21:44 -05:00
|
|
|
case 500: return "8x10";
|
|
|
|
case 510: return "8x12";
|
2017-01-05 16:08:55 -05:00
|
|
|
case 600: return "A4";
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-29 11:48:41 -04:00
|
|
|
return "Unknown";
|
2017-01-05 16:08:55 -05:00
|
|
|
}
|
|
|
|
|
2019-05-16 20:56:43 -04:00
|
|
|
static const char *dnpds620_media_extension_code(int media)
|
2017-01-05 16:08:55 -05:00
|
|
|
{
|
|
|
|
switch (media) {
|
2019-09-21 20:59:05 -04:00
|
|
|
case 0: return "Normal Paper";
|
2021-05-16 00:16:50 -04:00
|
|
|
case 1: return "Sticker Paper";
|
2017-01-05 16:08:55 -05:00
|
|
|
case 99: return "Unknown Paper";
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-29 11:48:41 -04:00
|
|
|
return "Unknown";
|
2017-01-05 16:08:55 -05:00
|
|
|
}
|
|
|
|
|
2020-03-09 16:15:02 -04:00
|
|
|
static const char *rfid_media_subtypes(int media)
|
2017-01-05 16:08:55 -05:00
|
|
|
{
|
|
|
|
switch (media) {
|
2019-09-21 20:59:05 -04:00
|
|
|
case 1: return "SD";
|
2019-08-07 00:22:59 -04:00
|
|
|
case 2: return "PD";
|
2019-09-21 20:59:05 -04:00
|
|
|
case 3: return "PP";
|
2013-12-03 22:21:44 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-29 11:48:41 -04:00
|
|
|
return "Unknown";
|
2013-12-03 22:21:44 -05:00
|
|
|
}
|
|
|
|
|
2019-05-16 20:56:43 -04:00
|
|
|
static const char *dnpds80_duplex_media_types(int media)
|
2015-08-28 20:37:28 -04:00
|
|
|
{
|
|
|
|
switch (media) {
|
|
|
|
case 100: return "8x10.75";
|
|
|
|
case 200: return "8x12";
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-29 11:48:41 -04:00
|
|
|
return "Unknown";
|
2015-08-28 20:37:28 -04:00
|
|
|
}
|
|
|
|
|
2019-05-16 20:56:43 -04:00
|
|
|
#define DUPLEX_UNIT_PAPER_NONE 0
|
|
|
|
#define DUPLEX_UNIT_PAPER_PROTECTIVE 1
|
|
|
|
#define DUPLEX_UNIT_PAPER_PRESENT 2
|
|
|
|
|
|
|
|
static const char *dnpds80_duplex_paper_status(int media)
|
|
|
|
{
|
|
|
|
switch (media) {
|
|
|
|
case DUPLEX_UNIT_PAPER_NONE: return "No Paper";
|
|
|
|
case DUPLEX_UNIT_PAPER_PROTECTIVE: return "Protective Sheet";
|
|
|
|
case DUPLEX_UNIT_PAPER_PRESENT: return "Cut Paper Present";
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *dnpds80_duplex_statuses(int status)
|
2015-08-28 19:30:16 -04:00
|
|
|
{
|
|
|
|
switch (status) {
|
|
|
|
case 5000: return "No Error";
|
|
|
|
|
|
|
|
case 5500: return "Duplex Unit Not Connected";
|
|
|
|
|
|
|
|
case 5017: return "Paper Jam: Supply Sensor On";
|
|
|
|
case 5018: return "Paper Jam: Supply Sensor Off";
|
|
|
|
case 5019: return "Paper Jam: Slot Sensor On";
|
|
|
|
case 5020: return "Paper Jam: Slot Sensor Off";
|
|
|
|
case 5021: return "Paper Jam: Pass Sensor On";
|
|
|
|
case 5022: return "Paper Jam: Pass Sensor Off";
|
|
|
|
case 5023: return "Paper Jam: Shell Sensor 1 On";
|
|
|
|
case 5024: return "Paper Jam: Shell Sensor 1 Off";
|
|
|
|
case 5025: return "Paper Jam: Shell Sensor 2 On";
|
|
|
|
case 5026: return "Paper Jam: Shell Sensor 2 Off";
|
|
|
|
case 5027: return "Paper Jam: Eject Sensor On";
|
|
|
|
case 5028: return "Paper Jam: Eject Sensor Off";
|
|
|
|
case 5029: return "Paper Jam: Slot FG Sensor";
|
|
|
|
case 5030: return "Paper Jam: Shell FG Sensor";
|
|
|
|
|
|
|
|
case 5033: return "Paper Supply Sensor Off";
|
|
|
|
case 5034: return "Printer Feed Slot Sensor Off";
|
|
|
|
case 5035: return "Pinch Pass Sensor Off";
|
|
|
|
case 5036: return "Shell Pass Sensor 1 Off";
|
|
|
|
case 5037: return "Shell Pass Sensor 2 Off";
|
|
|
|
case 5038: return "Eject Sensor Off";
|
|
|
|
|
|
|
|
case 5049: return "Capstan Drive Control Error";
|
|
|
|
case 5065: return "Shell Roller Error";
|
|
|
|
|
|
|
|
case 5081: return "Pinch Open Error";
|
|
|
|
case 5082: return "Pinch Close Error";
|
|
|
|
case 5083: return "Pinch Init Error";
|
|
|
|
case 5084: return "Pinch Position Error";
|
|
|
|
|
|
|
|
case 5097: return "Pass Guide Supply Error";
|
|
|
|
case 5098: return "Pass Guide Shell Error";
|
|
|
|
case 5099: return "Pass Guide Eject Error";
|
|
|
|
case 5100: return "Pass Guide Init Error";
|
|
|
|
case 5101: return "Pass Guide Position Error";
|
|
|
|
|
|
|
|
case 5113: return "Side Guide Home Error";
|
|
|
|
case 5114: return "Side Guide Position Error";
|
|
|
|
case 5115: return "Side Guide Init Error";
|
|
|
|
|
|
|
|
case 5129: return "Act Guide Home Error";
|
|
|
|
|
|
|
|
case 5145: return "Shell Rotate Home Error";
|
|
|
|
case 5146: return "Shell Rotate Rev Error";
|
|
|
|
|
|
|
|
case 5161: return "Paper Feed Lever Down Error";
|
|
|
|
case 5162: return "Paper Feed Lever Lock Error";
|
|
|
|
case 5163: return "Paper Feed Lever Up Error";
|
|
|
|
|
|
|
|
case 5177: return "Cutter Home Error";
|
|
|
|
case 5178: return "Cutter Away Error";
|
|
|
|
case 5179: return "Cutter Init Error";
|
|
|
|
case 5180: return "Cutter Position Error";
|
|
|
|
|
|
|
|
case 5193: return "Paper Tray Removed";
|
|
|
|
case 5209: return "Cover Opened";
|
|
|
|
case 5241: return "System Error";
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-05 08:06:28 -04:00
|
|
|
return "Unknown Duplexer Error";
|
2015-08-28 19:30:16 -04:00
|
|
|
}
|
|
|
|
|
2019-05-16 20:56:43 -04:00
|
|
|
static const char *dnpds40_statuses(int status)
|
2013-12-03 22:32:08 -05:00
|
|
|
{
|
2015-08-28 19:30:16 -04:00
|
|
|
if (status >= 5000 && status <= 5999)
|
|
|
|
return dnpds80_duplex_statuses(status);
|
|
|
|
|
2015-06-23 19:25:23 -04:00
|
|
|
switch (status) {
|
2013-12-03 22:32:08 -05:00
|
|
|
case 0: return "Idle";
|
|
|
|
case 1: return "Printing";
|
|
|
|
case 500: return "Cooling Print Head";
|
|
|
|
case 510: return "Cooling Paper Motor";
|
2015-06-17 20:55:29 -04:00
|
|
|
case 900: return "Standby Mode";
|
2013-12-03 22:32:08 -05:00
|
|
|
case 1000: return "Cover Open";
|
|
|
|
case 1010: return "No Scrap Box";
|
|
|
|
case 1100: return "Paper End";
|
|
|
|
case 1200: return "Ribbon End";
|
2014-02-02 14:11:17 -05:00
|
|
|
case 1300: return "Paper Jam";
|
|
|
|
case 1400: return "Ribbon Error";
|
2013-12-03 22:32:08 -05:00
|
|
|
case 1500: return "Paper Definition Error";
|
|
|
|
case 1600: return "Data Error";
|
|
|
|
case 2000: return "Head Voltage Error";
|
2019-08-07 00:22:59 -04:00
|
|
|
case 2010: return "USB Power Supply Error";
|
2013-12-03 22:32:08 -05:00
|
|
|
case 2100: return "Head Position Error";
|
|
|
|
case 2200: return "Power Supply Fan Error";
|
|
|
|
case 2300: return "Cutter Error";
|
|
|
|
case 2400: return "Pinch Roller Error";
|
|
|
|
case 2500: return "Abnormal Head Temperature";
|
|
|
|
case 2600: return "Abnormal Media Temperature";
|
|
|
|
case 2610: return "Abnormal Paper Motor Temperature";
|
|
|
|
case 2700: return "Ribbon Tension Error";
|
|
|
|
case 2800: return "RF-ID Module Error";
|
2022-07-28 10:52:44 -04:00
|
|
|
case 2900: return "RS422 Communiation Error";
|
2013-12-03 22:32:08 -05:00
|
|
|
case 3000: return "System Error";
|
2021-08-19 06:36:10 -04:00
|
|
|
case 9999: return "Communication Failure"; /* Special */
|
2013-12-03 22:32:08 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-28 19:30:16 -04:00
|
|
|
return "Unknown Error";
|
2013-12-03 22:32:08 -05:00
|
|
|
}
|
|
|
|
|
2013-12-10 21:53:46 -05:00
|
|
|
static int dnpds40_do_cmd(struct dnpds40_ctx *ctx,
|
2013-12-11 07:50:31 -05:00
|
|
|
struct dnpds40_cmd *cmd,
|
|
|
|
uint8_t *data, int len)
|
2013-12-10 21:53:46 -05:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2013-12-10 21:53:46 -05:00
|
|
|
(uint8_t*)cmd, sizeof(*cmd))))
|
|
|
|
return ret;
|
|
|
|
|
2017-07-10 20:15:56 -04:00
|
|
|
if (data && len)
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2013-12-10 21:53:46 -05:00
|
|
|
data, len)))
|
|
|
|
return ret;
|
|
|
|
|
2014-04-20 11:51:06 -04:00
|
|
|
return CUPS_BACKEND_OK;
|
2013-12-10 21:53:46 -05:00
|
|
|
}
|
|
|
|
|
2017-01-05 16:08:55 -05:00
|
|
|
static uint8_t *dnpds40_resp_cmd2(struct dnpds40_ctx *ctx,
|
2013-12-04 10:31:41 -05:00
|
|
|
struct dnpds40_cmd *cmd,
|
2017-01-05 16:08:55 -05:00
|
|
|
int *len,
|
|
|
|
uint8_t *buf, uint32_t buf_len)
|
2013-12-04 10:31:41 -05:00
|
|
|
{
|
|
|
|
char tmp[9];
|
|
|
|
uint8_t *respbuf;
|
|
|
|
|
|
|
|
int ret, i, num = 0;
|
2013-12-08 07:14:27 -05:00
|
|
|
|
|
|
|
memset(tmp, 0, sizeof(tmp));
|
|
|
|
|
2017-01-05 16:08:55 -05:00
|
|
|
if ((ret = dnpds40_do_cmd(ctx, cmd, buf, buf_len)))
|
2013-12-04 10:31:41 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Read in the response header */
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = read_data(ctx->conn,
|
2013-12-21 22:55:33 -05:00
|
|
|
(uint8_t*)tmp, 8, &num);
|
|
|
|
if (ret < 0)
|
2013-12-04 10:31:41 -05:00
|
|
|
return NULL;
|
|
|
|
|
2013-12-21 22:55:33 -05:00
|
|
|
if (num != 8) {
|
|
|
|
ERROR("Short read! (%d/%d)\n", num, 8);
|
|
|
|
return NULL;
|
2013-12-11 07:50:31 -05:00
|
|
|
}
|
2013-12-04 10:31:41 -05:00
|
|
|
|
2013-12-11 07:50:31 -05:00
|
|
|
i = atoi(tmp); /* Length of payload in bytes, possibly padded */
|
2020-01-22 23:59:22 -05:00
|
|
|
respbuf = malloc(i + 1);
|
2015-06-23 20:32:41 -04:00
|
|
|
if (!respbuf) {
|
|
|
|
ERROR("Memory allocation failure (%d bytes)!\n", i);
|
|