Gutenprint + CUPS backends for Dye Sublimation printers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
selphy_print/backend_hiti.c

2774 lines
71 KiB

/*
* HiTi Photo Printer CUPS backend -- libusb-1.0 version
*
* (c) 2019-2021 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
* https://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, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0+
*
*/
#define BACKEND hiti_backend
#include "backend_common.h"
/* For Integration into gutenprint */
#if defined(HAVE_CONFIG_H)
#include <config.h>
#endif
// We should use nanosleep everywhere properly.
#define __usleep(__x) { struct timespec t = { 0, (__x) * 1000 } ; nanosleep (&t, NULL); }
/* Private structures */
struct hiti_cmd {
uint8_t hdr; /* 0xa5 */
uint16_t len; /* (BE) everything after this field, minimum 3, max 6 */
uint8_t status; /* see CMD_STATUS_* */
uint16_t cmd; /* CMD_* (BE) */
uint8_t payload[]; /* 0-3 items */
} __attribute__((packed));
#define CMD_STATUS_OK 0x50
#define CMD_STATUS_OK2 0x51 /* Seen with ERDC_RLC on p51x */
#define CMD_STATUS_OK3 0x53 /* Seen with EPC_SP on p51x, sometimes? */
#define CMD_STATUS_BAD_CMD 0xd8 /* Seen with EFM_RD on p51x */
#define CMD_STATUS_UNK2 0xdb /* Seen with ESD_SEHT2 on p51x */
/* Request Device Characteristics */
#define CMD_RDC_RS 0x0100 /* Request Summary */
#define CMD_RDC_ROC 0x0104 /* Request Option Characteristics XX (1 resp) */
/* Printer Configuratio Control */
#define CMD_PCC_RP 0x0301 /* Reset Printer (1 arg) */
#define CMD_PCC_STP 0x030F /* Set Target Printer (1 arg) XX -- master or slave perhaps? */
/* Request Device Status */
#define CMD_RDS_RSS 0x0400 /* Request Status Summary */
#define CMD_RDS_RIS 0x0401 /* Request Input Status */
#define CMD_RDS_RIA 0x0403 /* Request Input Alert */
#define CMD_RDS_RJA 0x0405 /* Request Jam Alert */
#define CMD_RDS_ROIRA 0x0406 /* Request Operator Intervention Alert */
#define CMD_RDS_RW 0x0407 /* Request Warnings */
#define CMD_RDS_DSRA 0x0408 /* Request Device Serviced Alerts */
#define CMD_RDS_SA 0x040A /* Request Service Alerts */
#define CMD_RDS_RPS 0x040B /* Request Printer Statistics */
#define CMD_RDS_RSUS 0x040C /* Request Supplies Status */
/* Job Control */
#define CMD_JC_SJ 0x0500 /* Start Job (3 arg) */
#define CMD_JC_EJ 0x0501 /* End Job (3 arg) */
#define CMD_JC_QJC 0x0502 /* Query Job Completed (5 arg) XX */
#define CMD_JC_QQA 0x0503 /* Query Jobs Queued or Active (3 arg) */
#define CMD_JC_RSJ 0x0510 /* Resume Suspended Job (3 arg) XX */
/* Extended Read Device Characteristics */
#define CMD_ERDC_RS 0x8000 /* Request Summary */
#define CMD_ERDC_RCC 0x8001 /* Read Calibration Charcteristics */
#define CMD_ERDC_RPC 0x8005 /* Request Print Count (1 arg, 8 (51x) or 4 (52x,7xx) resp) */
#define CMD_ERDC_RLC 0x8006 /* Request LED calibration */
#define CMD_ERDC_RSN 0x8007 /* Read Serial Number (1 arg) */
#define CMD_ERDC_C_RPCS 0x8008 /* CS Request Printer Correction Status */
#define CMD_ERDC_RPIDM 0x8009 /* Request PID and Model Code */
#define CMD_ERDC_RTLV 0x800E /* Request T/L Voltage */
#define CMD_ERDC_RRVC 0x800F /* Read Ribbon Vendor Code */
#define CMD_ERDC_UNK 0x8010 /* Unknown Query RE */
#define CMD_ERDC_UNK2 0x8011 /* Unknown Query RE */
#define CMD_ERDC_RHA 0x801C /* Read Highlight Adjustment (6 resp) RE */
// 8008 seen in Windows Comm @ 3211 (0 len response)
// 8011 seen in Windows Comm @ 3369 (1 arg req (always 00), 4 len response)
/* Extended Format Data */
#define CMD_EFD_SF 0x8100 /* Sublimation Format */
#define CMD_EFD_CHS 0x8101 /* Color & Heating Setting (2 arg) */
#define CMD_EFD_C_CHS 0x8102 /* CS Color Heating Setting (3 arg) */
#define CMD_EFD_C_SIID 0x8103 /* CS Set Input ID (1 arg) */
/* Extended Page Control */
#define CMD_EPC_SP 0x8200 /* Start Page */
#define CMD_EPC_EP 0x8201 /* End Page */
#define CMD_EPC_SYP 0x8202 /* Start Yellow Plane */
#define CMD_EPC_SMP 0x8204 /* Start Magenta Plane */
#define CMD_EPC_SCP 0x8206 /* Start Cyan Plane */
#define CMD_EPC_C_SYP 0x8202 /* CS Start Yellow Page */
#define CMD_EPC_C_SMP 0x8203 /* CS Start Magenta Page */
#define CMD_EPC_C_SCP 0x8204 /* CS Start Cyan Page */
#define CMD_EPC_C_SBP 0x8205 /* CS Start Black Page */
#define CMD_EPC_C_SKP 0x8206 /* CS Start K Resin Page */
#define CMD_EPC_C_SLP 0x8207 /* CS Start Lamination Page */
#define CMD_EPC_C_SOP 0x8208 /* CS Start Overcoat Page */
#define CMD_EPC_C_SY2P 0x8209 /* CS Start Yellow2 Page */
#define CMD_EPC_C_SM2P 0x820A /* CS Start Magenta2 Page */
#define CMD_EPC_C_SC2P 0x820B /* CS Start Cyan2 Page */
#define CMD_EPC_C_SB2P 0x820C /* CS Start Black2 Page */
#define CMD_EPC_C_SK2P 0x820D /* CS Start K Resin2 Page */
#define CMD_EPC_C_SL2P 0x820E /* CS Start Lamination2 Page */
#define CMD_EPC_C_SO2P 0x820F /* CS Start Overcoat2 Page */
/* Extended Send Data */
#define CMD_ESD_SEHT2 0x8303 /* Send Ext Heating Table (2 arg) */
#define CMD_ESD_SEHT 0x8304 /* Send Ext Heating Table XX */
#define CMD_ESD_SEPD 0x8309 /* Send Ext Print Data (2 arg) + struct */
#define CMD_ESD_UNK 0x830A /* Unknown, seen on P51x (4 byte payload) */
#define CMD_ESD_SHPTC 0x830B /* Send Heating Parameters & Tone Curve XX (n arg) */
#define CMD_ESD_C_SHPTC 0x830C /* CS Send Heating Parameters & Tone Curve XX (n arg) */
/* Extended Flash/NVram */
#define CMD_EFM_RNV 0x8405 /* Read NVRam (1 arg) XX */
#define CMD_EFM_RD 0x8408 /* Read single location (2 arg) -- XXX RE not P51x */
#define CMD_EFM_SHA 0x840E /* Set Highlight Adjustment (5 arg) -- XXX RE */
/* Extended Security Control */
#define CMD_ESC_SP 0x8900 /* Set Password */
#define CMD_ESC_SSM 0x8901 /* Set Security Mode */
/* Extended Debug Mode */
#define CMD_EDM_CVD 0xE002 /* Common Voltage Drop Values (n arg) */
#define CMD_EDM_CPP 0xE023 /* Clean Paper Path (1 arg) XX */
#define CMD_EDM_C_MC2CES 0xE02E /* CS Move card to Contact Encoder Station */
#define CMD_EDM_C_MC2MES 0xE02F /* CS Move card to Mag Encoder Station */
#define CMD_EDM_C_MC2CLES 0xE030 /* CS Move card to ContactLess Encoder Station */
#define CMD_EDM_C_MC2EB 0xE031 /* CS Move card to Eject Box */
#define CMD_EDM_C_MC2H 0xE037 /* CS Move card to Hopper */
/* CMD_PCC_RP */
#define RESET_PRINTER 0x01
#define RESET_SOFT 0x02
/* 801C --> 0 args
<-- 6 bytes: 00 YY MM CC 00 00 (YMC is +- 31 decimal)
840E --> 5 args: YY MM CC 00 00 (YMC is +- 31 decimal)
<-- 1 arg: 00 (success, presumably)
Highlight Correction. Unclear if it's used by printer or by "driver"
*/
/* CMD_ERDC_RCC */
struct hiti_calibration {
uint8_t horiz;
uint8_t vert;
} __attribute__((packed));
/* CMD_ERDC_RPIDM */
struct hiti_rpidm {
uint16_t usb_pid; /* BE */
uint8_t region; /* See hiti_regions */
} __attribute__((packed));
/* CMD_EDRC_RS */
struct hiti_erdc_rs { /* All are BIG endian */
uint8_t unk; // 1e == 30, but struct is 29 length.
uint16_t stride; /* fixed at 0x0780/1920? Head width? */
uint16_t dpi_cols; /* fixed at 300 */
uint16_t dpi_rows; /* fixed at 300 */
uint16_t cols; /* 1844 for 6" media */
uint16_t rows; /* 1240 for 6x4" media */
uint8_t unk2[18]; // ff ff 4b 4b 4b 4b af 3c 4f 7b 19 08 5c 0a b4 64 af af
} __attribute__((packed));
/* CMD_JC_* */
struct hiti_job {
uint8_t lun; /* Logical Unit Number. Leave at 0 */
uint16_t jobid; /* BE */
} __attribute__((packed));
/* CMD_JC_QQA */
#define MAX_JOBS 4
struct hiti_job_qqa {
uint8_t count; /* 0-MAX_JOBS */
struct {
struct hiti_job job;
uint8_t status;
} row[MAX_JOBS]; /* Four jobs max outstanding */
} __attribute__((packed));
#define QQA_STATUS_PRINTING 0x00
#define QQA_STATUS_WAITING 0x01
#define QQA_STATUS_SUSPENDED 0x03
/* CMD_JC_QJC */
struct hiti_jc_qjc {
uint8_t lun; /* Logical Unit Number. Leave at 0 */
uint16_t jobid; /* BE */
uint16_t jobid2; /* BE, set to 1? */
} __attribute__((packed));
// repsonse is 6 bytes.
//. 5x3.5 1547 1072
//. 6x4 1844 1240
//. 6x9 1844 2740
//. 6x8/2 1844 2492
//. 6x8 1844 2434
//. 5x7 1548 2140
//. 5x7/2 1548 2152
//. 6x4/2 1844 1248
// 6x6 1844 1844
// 5x5 1540 1540 ? (1548?)
// 6x5 1844 1544
// 6x2 1844 ????
#define PRINT_TYPE_6x4 0
#define PRINT_TYPE_5x7 2
#define PRINT_TYPE_6x8 3
#define PRINT_TYPE_6x9 6
#define PRINT_TYPE_6x9_2UP 7
#define PRINT_TYPE_5x3_5 8
#define PRINT_TYPE_6x4_2UP 9
#define PRINT_TYPE_6x2 10
#define PRINT_TYPE_5x7_2UP 11
struct hiti_heattable_v1a { /* P51x (older) */
uint8_t y[2050]; /* 256 doubles, plus 2 byte checksum? */
uint8_t pad0[30];
uint8_t m[2050];
uint8_t pad1[30];
uint8_t c[2050];
uint8_t pad2[30];
uint8_t o[2050]; /* Overcoat Glossy */
uint8_t pad3[30];
uint8_t om[2050]; /* Overcoat Matte */
uint8_t pad4[30];
uint8_t cvd[582]; /* 58 u16 * 5 (y/m/c/o/om) + 2 byte checksum? */
uint8_t pad5[26];
} __attribute__((packed));
STATIC_ASSERT(sizeof(struct hiti_heattable_v1a) == 11008);
struct hiti_heattable_v1b { /* P51x (newer) */
uint8_t y_hdr[5]; // 01 01 04 00 00
uint8_t y[2050]; /* 256 doubles, 2 checksum */
uint8_t m_hdr[5]; // 02 01 04 00 00
uint8_t m[2050]; /* 256 doubles, 2 checksum */
uint8_t c_hdr[5]; // 03 01 04 00 00
uint8_t c[2050]; /* 256 doubles, 2 checksum */
uint8_t o_hdr[5]; // 04 01 04 00 00
uint8_t o[2050]; /* 256 doubles, 2 checksum */
uint8_t om_hdr[5]; // 05 01 04 00 00
uint8_t om[2050]; /* 256 doubles, 2 checksum */
uint8_t u_hdr[5]; // 07 01 04 00 00 // Unknown purpose
uint8_t u[2050]; /* 256 doubles, 2 checksum */ // unknown purpose
uint8_t cvd_hdr[5]; // 00 00 00 00 00
uint8_t cvd[582]; /* 58 u16 * 5 (y/m/c/o/om) + 2 byte checksum? */
} __attribute__((packed));
STATIC_ASSERT(sizeof(struct hiti_heattable_v1b) == 12917);
/* All fields are little endian */
struct hiti_heattable_entry_v2 {
uint16_t type;
uint8_t unknown;
uint16_t zero;
uint32_t offset;
} __attribute((packed));
struct hiti_heattable_hdr_v2 {
uint8_t num_headers;
struct hiti_heattable_entry_v2 entries[];
} __attribute((packed));
#define HEATTABLE_V2_MAX_SIZE (1024*128)
/* All fields are LE */
struct hiti_gpjobhdr {
uint32_t cookie; /* "GPHT" */
uint32_t hdr_len; /* Including the whole thing */
uint32_t model; /* Model family, in decimal */
uint32_t cols;
uint32_t rows;
uint32_t col_dpi;
uint32_t row_dpi;
uint32_t copies;
uint32_t quality; /* 0 for std, 1 for fine */
uint32_t code; /* PRINT_TYPE_* */
uint32_t overcoat; /* 1 for matte, 0 for glossy */
uint32_t payload_flag; /* See PAYLOAD_FLAG_* */
uint32_t payload_len;
} __attribute__((packed));
#define PAYLOAD_FLAG_YMCPLANAR 0x01
#define PAYLOAD_FLAG_NOCORRECT 0x02
#define HDR_COOKIE 0x54485047
/* CMD_EFD_SF for non-CS systems */
struct hiti_efd_sf {
/*@0 */ uint8_t mediaType; /* PRINT_TYPE_?? */
/*@1 */ uint16_t cols_res; /* BE, always 300dpi */
/*@3 */ uint16_t rows_res; /* BE, always 300dpi */
/*@5 */ uint16_t cols; /* BE */
/*@7 */ uint16_t rows; /* BE */
/*@9 */ int8_t rows_offset; /* Has to do with H_Offset calibration */
/*@10*/ int8_t cols_offset; /* Has to do wiwth V_Offset calibration */
/*@11*/ uint8_t colorSeq; /* always 0x87, but |= 0xc0 for matte. */
/*@12*/ uint8_t copies;
/*@13*/ uint8_t printMode; /* 0x08 baseline, |= 0x02 fine mode */
} __attribute__((packed));
/* CMD_ESD_SEPD -- Note it's different from the usual command flow */
struct hiti_extprintdata {
uint8_t hdr; /* 0xa5 */
uint16_t len; /* 24bit data length (+8) in BE format, first two bytes */
uint8_t status; /* 0x50 */
uint16_t cmd; /* 0x8309, BE */
uint8_t lenb; /* LSB of length */
uint16_t startLine; /* Starting line number, BE */
uint16_t numLines; /* Number of lines in block, BE, 3000 max. */
uint8_t payload[]; /* ie data length bytes */
} __attribute__((packed));
/* CMD_ESD_SEHT2 -- Note it's different from the usual command flow */
struct hiti_seht2 {
uint8_t hdr; /* 0xa5 */
uint16_t len; /* 24-bit data length (+5) in BE format, first two bytes */
uint8_t status; /* 0x50 */
uint16_t cmd; /* 0x8303, BE */
uint8_t lenb; /* LSB of length */
uint8_t plane;
} __attribute__((packed));
/* All multi-byte fields here are LE */
struct hiti_matrix {
/*@00*/ uint8_t row0[16]; // all 00
/*@10*/ uint8_t row1[6]; // 01 00 00 00 00 00
uint16_t cuttercount;
uint8_t align_v;
uint8_t aligh_h;
uint8_t row1_2[6]; // all 00
/*@20*/ uint8_t row2[16]; // no idea
/*@30*/ uint8_t error_index0; /* Value % 31 == NEWEST. Count back */
uint8_t errorcode[31];
/*@50*/ uint8_t row5[16]; // all 00, except [8] which is a5.
/*@60*/ char serno[16]; /* device serial number */
/*@70*/ uint16_t unclean_prints;
uint16_t cleanat[15]; // XX Guess?
/*@90*/ uint16_t supply_motor;
uint16_t take_motor;
uint8_t row9[12]; // all 00 except last, which is 0xa5
/*@a0*/ uint16_t errorcount[31];
uint8_t unk_rowd[2]; // seems to be 00 cc ?
/*@e0*/ uint16_t tpc_4x6;
uint16_t tpc_5x7;
uint16_t tpc_6x8;
uint16_t tpc_6x9;
uint8_t unk_rowe[8]; // all 00
/*@f0*/ uint16_t apc_4x6;
uint16_t apc_5x7;
uint16_t apc_6x8;
uint16_t apc_6x9;
uint8_t unk_rowf[4]; // all 00
uint8_t tphv_a;
uint8_t tphv_d;
uint8_t unk_rowf2[2]; // all 00
/* @100 */
} __attribute__((packed));
/* Private data structure */
struct hiti_printjob {
struct dyesub_job_common common;
uint8_t *databuf;
uint32_t datalen;
struct hiti_gpjobhdr hdr;
int blocks;
};
struct hiti_ctx {
struct dyesub_connection *conn;
int jobid;
char serno[32];
int erdc_rpc_len;
struct marker marker;
char version[256];
char id[256];
uint8_t matrix[256]; // XXX convert to struct matrix */
uint8_t supplies[5]; /* Ribbon */ // XXX convert to struct
uint8_t supplies2[4]; /* Paper */ // XXX convert to struct
struct hiti_calibration calibration;
uint8_t led_calibration[10]; // XXX convert to struct
uint8_t unk_8010[15]; // XXX
struct hiti_erdc_rs erdc_rs;
uint8_t hilight_adj[6]; // XXX convert to struct, not P51x!
uint8_t rtlv[2]; /* XXX figure out conversion/math? */
struct hiti_rpidm rpidm;
uint16_t ribbonvendor; // low byte = media subtype, high byte = type.
uint32_t media_remain; // XXX could be array?
uint8_t *heattable_buf;
struct hiti_heattable_v2 {
uint16_t type;
uint8_t *data;
uint32_t len;
} *heattable_v2;
uint8_t num_heattable_entries;
};
/* Prototypes */
static int hiti_doreset(struct hiti_ctx *ctx, uint8_t type);
static int hiti_query_job_qa(struct hiti_ctx *ctx, struct hiti_job *jobid, struct hiti_job_qqa *resp);
static int hiti_query_status(struct hiti_ctx *ctx, uint8_t *sts, uint32_t *err);
static int hiti_query_version(struct hiti_ctx *ctx);
static int hiti_query_matrix(struct hiti_ctx *ctx);
static int hiti_query_supplies(struct hiti_ctx *ctx);
static int hiti_query_tphv(struct hiti_ctx *ctx);
static int hiti_query_statistics(struct hiti_ctx *ctx);
static int hiti_query_calibration(struct hiti_ctx *ctx);
static int hiti_query_led_calibration(struct hiti_ctx *ctx);
static int hiti_query_ribbonvendor(struct hiti_ctx *ctx);
static int hiti_query_summary(struct hiti_ctx *ctx, struct hiti_erdc_rs *rds);
static int hiti_query_rpidm(struct hiti_ctx *ctx);
static int hiti_query_hilightadj(struct hiti_ctx *ctx);
static int hiti_query_unk8010(struct hiti_ctx *ctx);
static int hiti_query_counter(struct hiti_ctx *ctx, uint8_t arg, uint32_t *resp, int num);
static int hiti_query_markers(void *vctx, struct marker **markers, int *count);
static int hiti_query_serno(struct dyesub_connection *conn, char *buf, int buf_len);
static int hiti_docmd(struct hiti_ctx *ctx, uint16_t cmdid, uint8_t *buf, uint16_t buf_len, uint16_t *rsplen)
{
uint8_t cmdbuf[2048];
struct hiti_cmd *cmd = (struct hiti_cmd *)cmdbuf;
int ret, num = 0;
cmd->hdr = 0xa5;
cmd->len = cpu_to_be16(buf_len + 3);
cmd->status = CMD_STATUS_OK;
cmd->cmd = cpu_to_be16(cmdid);
if (buf && buf_len)
memcpy(cmd->payload, buf, buf_len);
/* Send over command */
if ((ret = send_data(ctx->conn, (uint8_t*) cmd, buf_len + 3 + 3))) {
return ret;
}
__usleep(10*1000);
/* Read back command */
ret = read_data(ctx->conn, cmdbuf, 6, &num);
if (ret)
return ret;
if (num != 6) {
ERROR("CMD Readback length mismatch (%d vs %d)!\n", num, 6);
return CUPS_BACKEND_FAILED;
}
/* Compensate for hdr len */
num = be16_to_cpu(cmd->len) - 3;
if (num > *rsplen) {
ERROR("Response too long for buffer (%d vs %d)!\n", num, *rsplen);
*rsplen = 0;
return CUPS_BACKEND_FAILED;
}
/* Check response */
if (cmd->status != CMD_STATUS_OK && cmd->status != CMD_STATUS_OK2 &&
cmd->status != CMD_STATUS_OK3) {
ERROR("Command %04x failed, code %02x\n", cmdid, cmd->status);
return CUPS_BACKEND_FAILED;
}
*rsplen = num;
return CUPS_BACKEND_OK;
}
static int hiti_docmd_resp(struct hiti_ctx *ctx, uint16_t cmdid,
uint8_t *buf, uint8_t buf_len,
uint8_t *respbuf, uint16_t *resplen)
{
int ret, num = 0;
uint16_t cmd_resp_len = *resplen;
ret = hiti_docmd(ctx, cmdid, buf, buf_len, &cmd_resp_len);
if (ret)
return ret;
if (cmd_resp_len > *resplen) {
ERROR("Response too long! (%d vs %d)\n", cmd_resp_len, *resplen);
*resplen = 0;
return CUPS_BACKEND_FAILED;
}
__usleep(10*1000);
/* Read back the data*/
int remain = *resplen;
int total = 0;
do {
ret = read_data(ctx->conn, respbuf + total, remain, &num);
if (ret)
return ret;
total += num;
remain -= num;
} while (remain > 0 && num == 64);
/* Sanity check */
if (total > *resplen) {
ERROR("Response too long for buffer (%d vs %d)!\n", total, *resplen);
*resplen = 0;
return CUPS_BACKEND_FAILED;
}
*resplen = total;
return CUPS_BACKEND_OK;
}
static int hiti_sepd(struct hiti_ctx *ctx, uint32_t buf_len,
uint16_t startLine, uint16_t numLines)
{
uint8_t cmdbuf[sizeof(struct hiti_extprintdata)];
struct hiti_extprintdata *cmd = (struct hiti_extprintdata *)cmdbuf;
int ret, num = 0;
buf_len += 8;
cmd->hdr = 0xa5;
cmd->len = cpu_to_be16(buf_len >> 8);
cmd->status = CMD_STATUS_OK;
cmd->cmd = cpu_to_be16(CMD_ESD_SEPD);
cmd->lenb = buf_len & 0xff;
cmd->startLine = cpu_to_be16(startLine);
cmd->numLines = cpu_to_be16(numLines);
/* Send over command */
if ((ret = send_data(ctx->conn, (uint8_t*) cmd, sizeof(*cmd)))) {
return ret;
}
__usleep(10*1000);
/* Read back command */
ret = read_data(ctx->conn, cmdbuf, 6, &num);
if (ret)
return ret;
if (num != 6) {
ERROR("CMD Readback length mismatch (%d vs %d)!\n", num, 6);
return CUPS_BACKEND_FAILED;
}
return CUPS_BACKEND_OK;
}
#define STATUS_IDLE 0x00
#define STATUS0_POWERON 0x01
#define STATUS0_RESEND_DATA 0x04
#define STATUS0_BUSY 0x80
#define STATUS1_SUPPLIES 0x01
#define STATUS1_PAPERJAM 0x02
#define STATUS1_INPUT 0x08
#define STATUS2_WARNING 0x02
#define STATUS2_DEVSERVICE 0x04
#define STATUS2_OPERATOR 0x08
static const char *hiti_status(uint8_t *sts)
{
if (sts[2] & STATUS2_WARNING)
return "Warning";
else if (sts[2] & STATUS2_DEVSERVICE)
return "Service Required";
else if (sts[2] & STATUS2_OPERATOR)
return "Operator Intervention Required";
else if (sts[1] & STATUS1_PAPERJAM)
return "Paper Jam";
else if (sts[1] & STATUS1_INPUT)
return "Input Alert";
else if (sts[1] & STATUS1_SUPPLIES)
return "Supply Alert";
else if (sts[0] & STATUS0_RESEND_DATA)
return "Resend Data";
else if (sts[0] & STATUS0_BUSY)
return "Busy";
else if (sts[0] & STATUS0_POWERON)
return "Powering On";
else if (sts[0] == STATUS_IDLE)
return "Accepting Jobs";
else
return "Unknown";
}
static const char *hiti_jobstatuses(uint8_t code)
{
switch (code) {
case QQA_STATUS_PRINTING: return "Printing";
case QQA_STATUS_WAITING: return "Waiting";
case QQA_STATUS_SUSPENDED: return "Suspended";
default: return "Unknown";
}
}
#define RIBBON_TYPE_4x6 0x01
#define RIBBON_TYPE_5x7 0x02
#define RIBBON_TYPE_6x9 0x03
#define RIBBON_TYPE_6x8 0x04
static const char* hiti_ribbontypes(uint8_t code)
{
switch (code) {
case RIBBON_TYPE_4x6: return "4x6";
case RIBBON_TYPE_5x7: return "5x7";
case RIBBON_TYPE_6x9: return "6x9";
case RIBBON_TYPE_6x8: return "6x8";
default: return "Unknown";
}
}
static unsigned int hiti_ribboncounts(uint8_t code)
{
switch(code) {
case RIBBON_TYPE_4x6: return 500;
case RIBBON_TYPE_5x7: return 290;
case RIBBON_TYPE_6x8: return 250;
case RIBBON_TYPE_6x9: return 220; // XXX guess
default: return 999;
}
}
#define PAPER_TYPE_5INCH 0x02
#define PAPER_TYPE_6INCH 0x01
#define PAPER_TYPE_NONE 0x00
static const char* hiti_papers(uint8_t code)
{
switch (code) {
case PAPER_TYPE_NONE : return "None";
case PAPER_TYPE_5INCH: return "5 inch";
case PAPER_TYPE_6INCH: return "6 inch";
default: return "Unknown";
}
}
static const char* hiti_regions(uint8_t code)
{
switch (code) {
case 0x11: return "GB";
case 0x12:
case 0x22: return "CN";
case 0x13: return "NA";
case 0x14: return "SA";
case 0x15: return "EU";
case 0x16: return "IN";
case 0x17: return "DB";
case 0xf0: // Seen on P510S
case 0x01: // Seen on P520L
default:
return "Unknown";
}
}
/* Supposedly correct for P720, P728, and P520 */
static const char *hiti_errors(uint32_t code)
{
switch(code) {
case 0x00000000: return "None";
/* Warning Alerts */
case 0x000100FE: return "Paper roll mismatch";
case 0x000300FE: return "Buffer underrun when printing";
case 0x000301FE: return "Command sequence error";
case 0x000302FE: return "NAND flash unformatted";
case 0x000303FE: return "NAND flash space insufficient";
case 0x000304FE: return "Heating parameter table incompatible";
case 0x000502FE: return "Dust box needs cleaning";
/* Device Service Required Alerts */
case 0x00030001: return "SRAM error";
case 0x00030101: return "Cutter error";
case 0x00030201: return "ADC error";
case 0x00030301: return "NVRAM R/W error";
case 0x00030302: return "SDRAM checksum error";
case 0x00030402: return "DSP code checksum error";
case 0x00030501: return "Cam TPH error";
case 0x00030502: return "NVRAM checksom error";
case 0x00030601: return "Cam pinch error";
case 0x00030602: return "SRAM checksum error";
case 0x00030701: return "Firmware write error";
case 0x00030702: return "Flash checksum error";
case 0x00030802: return "Wrong firmware checksum error";
case 0x00030901: return "ADC error in slave printer";
case 0x00030A01: return "Cam Platen error in slave printer";
case 0x00030B01: return "NVRAM R/W error in slave printer";
case 0x00030C02: return "NVRAM CRC error in slave printer";
case 0x00030D02: return "SDRAM checksum error in slave printer";
case 0x00030E02: return "SRAM checksum error in slave printer";
case 0x00030F02: return "FLASH checksum error in slave printer";
case 0x00031002: return "Wrong firmware checksum error in slave printer";
case 0x00031101: return "Communication error with slave printer";
case 0x00031201: return "NAND flash error";
case 0x00031302: return "Cutter error";
/* Operator Intervention Required Alerts */
case 0x00050001: return "Cover open";
case 0x00050101: return "Cover open";
/* Supplies Alerts */
case 0x00080004: return "Ribbon missing";
case 0x00080007: return "Ribbon newly inserted";
case 0x00080103: return "Ribbon exhausted";
case 0x00080104: return "Ribbon exhausted";
case 0x00080105: return "Ribbon malfunction";
case 0x00080204: return "Ribbon missing in slave printer";
case 0x00080207: return "Ribbon newly inserted in slave printer";
case 0x000802FE: return "Ribbon IC error";
case 0x00080303: return "Ribbon exhausted in slave printer";
case 0x000803FE: return "Ribbon not authenticated";
case 0x000804FE: return "Ribbon IC read/write error";
case 0x000805FE: return "Ribbon IC read/write error in slave printer";
case 0x000806FE: return "Unsupported ribbon";
case 0x000807FE: return "Unsupported ribbon in slave printer";
case 0x000808FE: return "Unknown ribbon";
case 0x000809FE: return "Unknown ribbon in slave printer";
/* Jam Alerts */
case 0x00030000: return "Paper jam";
case 0x0003000F: return "Paper jam";
case 0x00030200: return "Paper jam in paper path 01";
case 0x00030300: return "Paper jam in paper path 02";
case 0x00030400: return "Paper jam in paper path 03";
case 0x00030500: return "Paper jam in paper path 04";
case 0x00030600: return "Paper jam in paper path 05";
case 0x00030700: return "Paper jam in paper path 06";
case 0x00030800: return "Paper jam in paper path 07";
case 0x00030900: return "Paper jam in paper path 08";
case 0x00030A00: return "Paper jam in paper path 09";
/* Input Alerts */
case 0x00000008: return "Paper box missing";
case 0x00000100: return "Cover open";
case 0x00000101: return "Cover open failure";
case 0x00000200: return "Ribbon IC missing";
case 0x00000201: return "Ribbon missing";
case 0x00000202: return "Ribbon mismatch 01";
case 0x00000203: return "Security check fail";
case 0x00000204: return "Ribbon mismatch 02";
case 0x00000205: return "Ribbon mismatch 03";
case 0x00000300: return "Ribbon exhausted 01";
case 0x00000301: return "Ribbon exhausted 02";
case 0x00000302: return "Printing failure (jam?)";
case 0x00000400: return "Paper exhausted 01";
case 0x00000401: return "Paper exhausted 02";
case 0x00000402: return "Paper not ready";
case 0x00000500: return "Paper jam 01";
case 0x00000501: return "Paper jam 02";
case 0x00000502: return "Paper jam 03";
case 0x00000503: return "Paper jam 04";
case 0x00000504: return "Paper jam 05";
case 0x00000600: return "Paper mismatch";
case 0x00000700: return "Cam error 01";
case 0x00000800: return "Cam error 02";
case 0x00000900: return "NVRAM error";
case 0x00001000: return "IC error";
case 0x00001200: return "ADC error";
case 0x00001300: return "FW Check Error";
case 0x00001500: return "Cutter error";
#if 0 // XXX these seem inappropriate
case 0x00007538: return "Device attached to printer";
case 0x00007539: return "Printer is in mobile mode";
case 0x00007540: return "Printer is in standalone mode";
case 0x00007542: return "Firmware too old for Fine mode";
case 0x00007543: return "Firmware too old for 2x6 mode";
case 0x00007544: return "Firmware too old for Matte mode";
case 0x00007545: return "Firmware too old";
case 0x00007546: return "Firmware too old";
#endif
case 0x00008000: return "Paper out or feeding error";
case 0x00008008: return "Paper box missing";
case 0x00008010: return "Paper roll mismatch";
case 0x00080200: return "Ribbon type mismatch";
// case 0x10008000: return "Paper out or paper low"; /* XXX this won't work, high byte is cleared */
default: return "Unknown";
}
}
static int hiti_get_info(struct hiti_ctx *ctx)
{
int ret;
ret = hiti_query_tphv(ctx);
if (ret)
return ret;
ret = hiti_query_led_calibration(ctx);
if (ret)
return ret;
INFO("Printer ID: %s\n", ctx-