summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2017-08-05 16:29:19 -0400
committerSolomon Peachy <pizza@shaftnet.org>2017-08-06 22:16:51 -0400
commitb71331d55f294efe32ceb3dc9ffec8a533ea95a0 (patch)
tree243b7c9d446e9b101daaa41a61742706a1fe472b
parenta89afbdc687ed0ca786d7c85a37046435dd3bb9d (diff)
downloadselphy_print-b71331d55f294efe32ceb3dc9ffec8a533ea95a0.tar.gz
selphy_print-b71331d55f294efe32ceb3dc9ffec8a533ea95a0.tar.bz2
selphy_print-b71331d55f294efe32ceb3dc9ffec8a533ea95a0.zip
Initial magiccard commit.
Status queries work! Still need to handle printjob parsing. And, for that matter, still havenm't figured out printjob encoding.
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--README17
-rw-r--r--backend_common.c2
-rw-r--r--backend_common.h1
-rw-r--r--backend_magicard.c359
6 files changed, 381 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 289a26e..59a0611 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ citizencw01
dyesub_backend
mitsu9550
mitsup95d
+magicard
diff --git a/Makefile b/Makefile
index 76cb7d0..ecda927 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ CPPFLAGS += -DURI_PREFIX=\"$(BACKEND_NAME)\"
CFLAGS += -funit-at-a-time
# List of backends
-BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 citizencw01 mitsu9550 shinkos6245 shinkos6145 canonselphyneo mitsup95d
+BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 shinkos1245 canonselphy mitsu70x kodak605 dnpds40 citizencw01 mitsu9550 shinkos6245 shinkos6145 canonselphyneo mitsup95d magicard
# For the s6145 and mitsu70x backends
CPPFLAGS += -DUSE_DLOPEN
diff --git a/README b/README
index 9df2f0f..9ff5f5e 100644
--- a/README
+++ b/README
@@ -69,6 +69,7 @@
Shinko CHC-S6245 (aka Sinfonia CE1)
Sony UP-CR10L (aka DNP DS-SL10)
Shinko CHC-S6145-5A (aka Sinfonia CS2-c)
+ Magicard Tango 2E
***************************************************************************
@@ -777,3 +778,19 @@ Notes:
-N [ A | B ] Reset Counter A/B
***************************************************************************
+ BACKEND=magicard
+
+ Work-in-progress printers:
+
+ Tango 2E
+ (All others)
+
+ This backend supports additional commands:
+
+ magicard [command [arg] ]
+
+ Valid commands:
+
+ -s Query printer status
+
+ ***************************************************************************
diff --git a/backend_common.c b/backend_common.c
index 0a49aae..220e0e3 100644
--- a/backend_common.c
+++ b/backend_common.c
@@ -574,6 +574,7 @@ extern struct dyesub_backend mitsu9550_backend;
extern struct dyesub_backend mitsup95d_backend;
extern struct dyesub_backend dnpds40_backend;
extern struct dyesub_backend cw01_backend;
+extern struct dyesub_backend magicard_backend;
static struct dyesub_backend *backends[] = {
&canonselphy_backend,
@@ -591,6 +592,7 @@ static struct dyesub_backend *backends[] = {
&mitsup95d_backend,
&dnpds40_backend,
&cw01_backend,
+ &magicard_backend,
NULL,
};
diff --git a/backend_common.h b/backend_common.h
index b44b7bb..fe8586e 100644
--- a/backend_common.h
+++ b/backend_common.h
@@ -127,6 +127,7 @@ enum {
P_DNP_DS620,
P_DNP_DS820,
P_FUJI_ASK300,
+ P_MAGICARD,
P_END,
};
diff --git a/backend_magicard.c b/backend_magicard.c
new file mode 100644
index 0000000..90af92c
--- /dev/null
+++ b/backend_magicard.c
@@ -0,0 +1,359 @@
+/*
+ * Magicard card printer family CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2017 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * 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>
+
+#define BACKEND magicard_backend
+
+#include "backend_common.h"
+
+/* Exported */
+#define USB_VID_MAGICARD 0x0C1F
+#define USB_PID_MAGICARD_TANGO2E 0x1800
+
+/* Private data structure */
+struct magicard_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ uint8_t type;
+
+ uint8_t *databuf;
+ int datalen;
+};
+
+struct magicard_cmd_header {
+ uint8_t guard[9]; /* 0x05 */
+ uint8_t guard2[1]; /* 0x01 */
+ uint8_t cmd[4]; /* 'REQ,' */
+ uint8_t subcmd[4]; /* '???,' */
+ uint8_t arg[4]; /* '???,' */
+ uint8_t footer[2]; /* 0x1c 0x03 */
+};
+
+struct magicard_resp_header {
+ uint8_t guard[1]; /* 0x01 */
+ uint8_t subcmd_arg[7]; /* '???,???' */
+ uint8_t data[0]; /* freeform resp */
+// uint8_t term[2]; /* 0x2c 0x03 terminates! */
+};
+
+struct magicard_requests {
+ char *key;
+ char *desc;
+ uint8_t type;
+};
+
+enum {
+ TYPE_UNKNOWN = 0,
+ TYPE_STRING,
+ TYPE_STRINGINT,
+ TYPE_IPADDR,
+ TYPE_YESNO,
+ TYPE_MODEL,
+};
+
+/* Data definitions */
+static struct magicard_requests magicard_sta_requests[] = {
+ { "MSR", "Serial Number", TYPE_STRING },
+ { "VRS", "Firmware Version", TYPE_STRING },
+ { "FDC", "Head Density", TYPE_STRINGINT },
+ { "FSP", "Image Start", TYPE_STRINGINT },
+ { "FEP", "Image End", TYPE_STRINGINT },
+ { "FPP", "Head Position", TYPE_STRINGINT },
+ { "MDL", "Model", TYPE_MODEL }, /* 0 == Standard. Others? */
+ { "PID", "USB PID", TYPE_STRINGINT },
+ { "MAC", "Ethernet MAC Address", TYPE_STRING },
+ { "DYN", "Dynamic Address", TYPE_YESNO }, /* 1 == yes, 0 == no */
+ { "IPA", "IP Address", TYPE_IPADDR }, /* ASCII signed integer */
+ { "SNM", "IP Netmask", TYPE_IPADDR }, /* ASCII signed integer */
+ { "GWY", "IP Gateway", TYPE_IPADDR }, /* ASCII signed integer */
+
+ { "TCQ", "Total Prints", TYPE_STRINGINT },
+ { "TCP", "Total Prints on Head", TYPE_STRINGINT },
+ { "TCN", "Total Cleaning Cycles", TYPE_STRINGINT },
+ { "CCQ", "Prints After Last Cleaning", TYPE_STRINGINT },
+ { NULL, NULL, 0 }
+};
+
+/* Helper functions */
+static int magicard_build_cmd(uint8_t *buf,
+ char *cmd, char *subcmd, char *arg)
+{
+ struct magicard_cmd_header *hdr = (struct magicard_cmd_header *) buf;
+
+ memset(hdr->guard, 0x05, sizeof(hdr->guard));
+ hdr->guard2[0] = 0x01;
+ memcpy(hdr->cmd, cmd, 3);
+ hdr->cmd[3] = ',';
+ memcpy(hdr->subcmd, subcmd, 3);
+ hdr->subcmd[3] = ',';
+ memcpy(hdr->arg, arg, 3);
+ hdr->arg[3] = ',';
+ hdr->footer[0] = 0x1c;
+ hdr->footer[1] = 0x03;
+
+ return sizeof(*hdr);
+}
+
+static uint8_t * magicard_parse_resp(uint8_t *buf, uint16_t len, uint16_t *resplen)
+{
+ struct magicard_resp_header *hdr = (struct magicard_resp_header *) buf;
+
+ *resplen = len - sizeof(hdr->guard) - sizeof(hdr->subcmd_arg) - 2;
+
+ return hdr->data;
+}
+
+static int magicard_query_status(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ int i;
+ uint8_t buf[256];
+
+ for (i = 0 ; ; i++) {
+ uint16_t resplen = 0;
+ uint8_t *resp;
+ int num = 0;
+
+ if (magicard_sta_requests[i].key == NULL)
+ break;
+
+ ret = magicard_build_cmd(buf, "REQ", "STA",
+ magicard_sta_requests[i].key);
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret)))
+ return ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ buf, sizeof(buf), &num);
+
+ if (ret < 0)
+ return ret;
+
+ resp = magicard_parse_resp(buf, num, &resplen);
+ resp[resplen] = 0;
+ switch(magicard_sta_requests[i].type) {
+ case TYPE_IPADDR: {
+ int32_t ipaddr;
+ uint8_t *addr = (uint8_t *) &ipaddr;
+ ipaddr = atoi((char*)resp);
+ INFO("%s:\t%d.%d.%d.%d\n",
+ magicard_sta_requests[i].desc,
+ addr[3], addr[2], addr[1], addr[0]);
+ break;
+ }
+ case TYPE_YESNO: {
+ int val = atoi((char*)resp);
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ val? "Yes" : "No");
+ break;
+ }
+ case TYPE_MODEL: {
+ int val = atoi((char*)resp);
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ val == 0? "Standard" : "Unknown");
+ break;
+ }
+ case TYPE_STRINGINT:
+ // treat differently?
+ case TYPE_STRING:
+ case TYPE_UNKNOWN:
+ default:
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ resp);
+ }
+ }
+
+ return ret;
+}
+
+/* Main driver */
+static void* magicard_init(void)
+{
+ struct magicard_ctx *ctx = malloc(sizeof(struct magicard_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct magicard_ctx));
+ return ctx;
+}
+
+static void magicard_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct magicard_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ ctx->type = lookup_printer_type(&magicard_backend,
+ desc.idVendor, desc.idProduct);
+
+}
+
+static void magicard_teardown(void *vctx) {
+ struct magicard_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+
+ free(ctx);
+}
+
+#define MAX_PRINTJOB_LEN 5218176 + 20*1024 /* 1016*642 * 4color * 2sides */
+static int magicard_read_parse(void *vctx, int data_fd) {
+ struct magicard_ctx *ctx = vctx;
+ int run = 1;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->databuf) {
+ free(ctx->databuf);
+ ctx->databuf = NULL;
+ }
+
+ ctx->datalen = 0;
+ ctx->databuf = malloc(MAX_PRINTJOB_LEN);
+ if (!ctx->databuf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ while(run) {
+// int i;
+ // cmd stream is 64 * 0x5a, followed by comma-separated
+ // commands. end of command list is 0x1c.
+ // then bulk data appended, using lengths specified in
+ // SZB, SZG, SZR, SZK.
+ // at end, 0x1c.
+ // Then one final command: 0x4b, 0x3a, 0x03. 'K:'
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int magicard_main_loop(void *vctx, int copies) {
+ struct magicard_ctx *ctx = vctx;
+ int ret;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+top:
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ctx->databuf, ctx->datalen)))
+ return CUPS_BACKEND_FAILED;
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void magicard_cmdline(void)
+{
+ DEBUG("\t\t[ -s ] # Query status\n");
+}
+
+static int magicard_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct magicard_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "s")) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ case 's':
+ j = magicard_query_status(ctx);
+ break;
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+struct dyesub_backend magicard_backend = {
+ .name = "Magicard family",
+ .version = "0.01WIP",
+ .uri_prefix = "magicard",
+ .cmdline_arg = magicard_cmdline_arg,
+ .cmdline_usage = magicard_cmdline,
+ .init = magicard_init,
+ .attach = magicard_attach,
+ .teardown = magicard_teardown,
+ .read_parse = magicard_read_parse,
+ .main_loop = magicard_main_loop,
+ .devices = {
+ { USB_VID_MAGICARD, USB_PID_MAGICARD_TANGO2E, P_MAGICARD, ""},
+ { USB_VID_MAGICARD, 0xFFFF, P_MAGICARD, ""},
+ { 0, 0, 0, ""}
+ }
+};
+
+/* Magicard family Spool file format
+
+*/