selphy_print/backend_shinkos1245.c
Solomon Peachy 261a86f0b6 s1245: Data structures
Still need to define flags and whatnot.
2015-02-08 13:17:33 -05:00

467 lines
11 KiB
C

/*
* Shinko/Sinfonia CHC-S1245 CUPS backend -- libusb-1.0 version
*
* (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
* LiveLink Technology [ www.livelinktechnology.net ]
*
* The latest version of this program can be found at:
*
* http://git.shaftnet.org/cgit/selphy_print.git
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* [http://www.gnu.org/licenses/gpl-3.0.html]
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "backend_common.h"
enum {
S_IDLE = 0,
S_PRINTER_READY_CMD,
S_PRINTER_SENT_DATA,
S_FINISHED,
};
/* Structure of printjob header. All fields are LITTLE ENDIAN */
struct s1245_printjob_hdr {
uint32_t len1; /* Fixed at 0x10 */
uint32_t model; /* Equal to the printer model (eg '1245' or '2145' decimal) */
uint32_t unk2; /* Null */
uint32_t unk3; /* Fixed at 0x01 */
uint32_t len2; /* Fixed at 0x64 */
uint32_t unk5; /* Null */
uint32_t media; /* Fixed at 0x10 */
uint32_t unk6; /* Null */
uint32_t method; /* Print Method */
uint32_t mode; /* Print Mode */
uint32_t unk7; /* Null */
int32_t mattedepth; /* 0x7fffffff for glossy, 0x00 +- 25 for matte */
uint32_t dust; /* Dust control */
uint32_t columns;
uint32_t rows;
uint32_t copies;
uint32_t unk10; /* Null */
uint32_t unk11; /* Null */
uint32_t unk12; /* Null */
uint32_t unk13; /* 0xceffffff */
uint32_t unk14; /* Null */
uint32_t unk15; /* 0xceffffff */
uint32_t dpi; /* Fixed at '300' (decimal) */
uint32_t unk16; /* 0xceffffff */
uint32_t unk17; /* Null */
uint32_t unk18; /* 0xceffffff */
uint32_t unk19; /* Null */
uint32_t unk20; /* Null */
uint32_t unk21; /* Null */
} __attribute__((packed));
/* Private data stucture */
struct shinkos1245_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
uint8_t jobid;
uint8_t fast_return;
struct s1245_printjob_hdr hdr;
uint8_t *databuf;
int datalen;
};
/* Printer data structures */
struct shinkos1245_cmd_hdr {
uint8_t prefix; /* 0x03 */
uint8_t hdr[4]; /* 0x1b 0x43 0x48 0x43 */
} __attribute__((packed));
struct shinkos1245_cmd_getid {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x12 */
uint8_t pad[11];
} __attribute__((packed));
struct shinkos1245_resp_getid {
uint8_t id; /* 0x00 */
uint8_t data[23]; /* padded with 0x20 (space) */
uint8_t reserved[8];
} __attribute__((packed));
struct shinkos1245_cmd_setid {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[2]; /* 0x0a 0x22 */
uint8_t id; /* 0x00 */
uint8_t data[23]; /* pad with 0x20 (space) */
} __attribute__((packed));
struct shinkos1245_cmd_print {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[2]; /* 0x0a 0x00 */
uint8_t id; /* 1-255 */
uint8_t count[2]; /* # Copies in BCD, 1-9999 */
uint16_t columns; /* Fixed at 2448 */
uint16_t rows;
uint8_t media; /* Fixed at 0x10 */
uint8_t mode; /* dust removal and lamination mode */
uint8_t combo;
} __attribute__((packed));
struct shinkos1245_cmd_getstatus {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x03 */
uint8_t pad[10];
} __attribute__((packed));
struct shinkos1245_resp_status {
uint8_t code;
uint8_t print_status;
uint8_t printer_status[6];
struct {
uint32_t lifetime; /* BE */
uint32_t maint; /* BE */
uint32_t media; /* BE */
uint32_t cutter; /* BE */
uint8_t reserved;
uint8_t ver_boot;
uint8_t ver_usb;
uint8_t control_flag;
} counters;
struct {
uint16_t main_boot;
uint16_t main_control;
uint16_t dsp_boot;
uint16_t dsp_control;
} versions;
struct {
uint8_t bank1_id;
uint8_t bank2_id;
uint16_t bank1_remain; /* BE */
uint16_t bank1_complete; /* BE */
uint16_t bank1_spec; /* BE */
uint16_t bank2_remain; /* BE */
uint16_t bank2_complete; /* BE */
uint16_t bank2_spec; /* BE */
} counters2;
uint8_t curve_status;
} __attribute__((packed));
struct shinkos1245_cmd_getmedia {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x1a/0x2a/0x3a for A/B/C */
uint8_t pad[10];
} __attribute__((packed));
struct shinkos1245_resp_media {
uint8_t code;
uint8_t reserved[5];
uint8_t count; /* 1-5 */
struct {
uint8_t code;
uint16_t columns; /* BE */
uint16_t rows; /* BE */
uint8_t type;
uint8_t set_type;
uint8_t reserved[3];
} media[5];
} __attribute__((packed));
struct shinkos1245_cmd_canceljob {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x13 */
uint8_t id; /* 1-255 */
uint8_t pad[9];
} __attribute__((packed));
struct shinkos1245_cmd_reset {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0xc0 */
uint8_t pad[10];
} __attribute__((packed));
struct shinkos1245_cmd_ttone {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0xc0 */
uint8_t tone[4]; /* 0x54 0x4f 0x4e 0x45 */
uint8_t cmd2[1]; /* 0x72/0x77/0x65/0x20 for read/write/end/data */
union {
struct {
uint8_t tone_table;
uint8_t param_table;
uint8_t pad[3];
} read_write;
struct {
uint8_t pad[5];
} end_data;
};
} __attribute__((packed));
struct shinkos1245_cmd_getmodel {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x02 */
uint8_t pad[10];
} __attribute__((packed));
struct shinkos1245_resp_getmodel {
uint8_t vendor_id[4];
uint8_t product_id[4];
uint8_t strings[40];
} __attribute__((packed));
struct shinkos1245_cmd_getmatte {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x20 */
uint8_t mode; /* Fixed at 0x00 */
uint8_t pad[9];
} __attribute__((packed));
struct shinkos1245_cmd_setmatte {
struct shinkos1245_cmd_hdr hdr;
uint8_t cmd[1]; /* 0x21 */
uint8_t mode; /* Fixed at 0x00 */
int8_t level; /* -25->+25 */
uint8_t pad[8];
} __attribute__((packed));
struct shinkos1245_resp_matte {
uint8_t code;
uint8_t mode;
uint8_t level;
uint8_t reserved[3];
} __attribute__((packed));
static void shinkos1245_cmdline(void)
{
}
int shinkos1245_cmdline_arg(void *vctx, int argc, char **argv)
{
struct shinkos1245_ctx *ctx = vctx;
int i, j = 0;
/* Reset arg parsing */
optind = 1;
opterr = 0;
while ((i = getopt(argc, argv, "")) >= 0) {
switch(i) {
default:
break; /* Ignore completely */
}
if (j) return j;
}
return 0;
}
static void *shinkos1245_init(void)
{
struct shinkos1245_ctx *ctx = malloc(sizeof(struct shinkos1245_ctx));
if (!ctx)
return NULL;
memset(ctx, 0, sizeof(struct shinkos1245_ctx));
/* Use Fast return by default in CUPS mode */
if (getenv("DEVICE_URI") || getenv("FAST_RETURN"))
ctx->fast_return = 1;
return ctx;
}
static void shinkos1245_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct shinkos1245_ctx *ctx = vctx;
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
/* Ensure jobid is sane */
ctx->jobid = (jobid & 0x7f) + 1;
}
static void shinkos1245_teardown(void *vctx) {
struct shinkos1245_ctx *ctx = vctx;
if (!ctx)
return;
if (ctx->databuf)
free(ctx->databuf);
free(ctx);
}
static int shinkos1245_read_parse(void *vctx, int data_fd) {
struct shinkos1245_ctx *ctx = vctx;
int ret;
uint8_t tmpbuf[4];
if (!ctx)
return CUPS_BACKEND_FAILED;
/* Read in then validate header */
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
if (ret < 0)
return ret;
if (ret < 0 || ret != sizeof(ctx->hdr))
return CUPS_BACKEND_CANCEL;
if (le32_to_cpu(ctx->hdr.len1) != 0x10 ||
le32_to_cpu(ctx->hdr.len2) != 0x64 ||
le32_to_cpu(ctx->hdr.dpi) != 300) {
ERROR("Unrecognized header data format!\n");
return CUPS_BACKEND_CANCEL;
}
ctx->hdr.model = le32_to_cpu(ctx->hdr.model);
switch(ctx->hdr.model != 1245) {
ERROR("Unrecognized printer (%d)!\n", ctx->hdr.model);
return CUPS_BACKEND_CANCEL;
}
/* Allocate space */
if (ctx->databuf) {
free(ctx->databuf);
ctx->databuf = NULL;
}
ctx->datalen = le32_to_cpu(ctx->hdr.rows) * le32_to_cpu(ctx->hdr.columns) * 3;
ctx->databuf = malloc(ctx->datalen);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_FAILED;
}
{
int remain = ctx->datalen;
uint8_t *ptr = ctx->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, ctx->datalen);
perror("ERROR: Read failed");
return ret;
}
ptr += ret;
remain -= ret;
} while (remain);
}
/* Make sure footer is sane too */
ret = read(data_fd, tmpbuf, 4);
if (ret != 4) {
ERROR("Read failed (%d/%d/%d)\n",
ret, 4, 4);
perror("ERROR: Read failed");
return ret;
}
if (tmpbuf[0] != 0x04 ||
tmpbuf[1] != 0x03 ||
tmpbuf[2] != 0x02 ||
tmpbuf[3] != 0x01) {
ERROR("Unrecognized footer data format!\n");
return CUPS_BACKEND_FAILED;
}
return CUPS_BACKEND_OK;
}
static int shinkos1245_main_loop(void *vctx, int copies) {
struct shinkos1245_ctx *ctx = vctx;
return CUPS_BACKEND_FAILED;
}
static int shinkos1245_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
{
buf[buf_len-1] = 0; /* ensure it's null terminated */
return CUPS_BACKEND_OK;
}
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S1245 0x0007
struct dyesub_backend shinkos1245_backend = {
.name = "Shinko/Sinfonia CHC-S1245",
.version = "0.01WIP",
.uri_prefix = "shinkos1245",
.cmdline_usage = shinkos1245_cmdline,
.cmdline_arg = shinkos1245_cmdline_arg,
.init = shinkos1245_init,
.attach = shinkos1245_attach,
.teardown = shinkos1245_teardown,
.read_parse = shinkos1245_read_parse,
.main_loop = shinkos1245_main_loop,
.query_serno = shinkos1245_query_serno,
.devices = {
{ USB_VID_SHINKO, USB_PID_SHINKO_S1245, P_SHINKO_S1245, ""},
{ 0, 0, 0, ""}
}
};
/* CHC-S1245 data format
Spool file consists of an 116-byte header, followed by RGB-packed data,
followed by a 4-byte footer. Header appears to consist of a series of
4-byte Little Endian words.
10 00 00 00 MM MM 00 00 00 00 00 00 01 00 00 00 MM == Model (ie 1245d)
64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == Media Size (0x10 fixed)
MM 00 00 00 PP 00 00 00 00 00 00 00 ZZ ZZ ZZ ZZ MM = Print Method (aka cut control), PP = Default/Glossy/Matte (0x01/0x03/0x05), ZZ == matte intensity (0x7fffffff for glossy, else 0x00000000 +- 25 for matte)
VV 00 00 00 WW WW 00 00 HH HH 00 00 XX 00 00 00 VV == dust; 0x00 default, 0x01 off, 0x02 on, XX == Copies
00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI, ie 300.
00 00 00 00 ce ff ff ff 00 00 00 00 00 00 00 00
00 00 00 00
[[Packed RGB payload of WW*HH*3 bytes]]
04 03 02 01 [[ footer ]]
*/