summary refs log tree commit diff
path: root/bin/msr606.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2018-11-07 21:28:37 -0500
committerJune McEnroe <june@causal.agency>2018-11-07 21:28:37 -0500
commit507aced2e116a6acb6ffb83acddfab5545d40116 (patch)
treecb08651b4f4f9ae6cc672cebc31b32ac28942810 /bin/msr606.c
parentAdd Low — Double Negative (diff)
downloadsrc-507aced2e116a6acb6ffb83acddfab5545d40116.tar.gz
src-507aced2e116a6acb6ffb83acddfab5545d40116.zip
Implement all of MSR606
Diffstat (limited to 'bin/msr606.c')
-rw-r--r--bin/msr606.c318
1 files changed, 189 insertions, 129 deletions
diff --git a/bin/msr606.c b/bin/msr606.c
index 5b74bed9..9ea8b94e 100644
--- a/bin/msr606.c
+++ b/bin/msr606.c
@@ -16,199 +16,259 @@
 
 #include <err.h>
 #include <fcntl.h>
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sysexits.h>
 #include <termios.h>
 #include <unistd.h>
 
-static void writeAll(int fd, const uint8_t *ptr, size_t size) {
-	while (size) {
-		ssize_t ret = write(fd, ptr, size);
-		if (ret < 0) err(EX_IOERR, "write");
-		ptr += ret;
-		size -= ret;
-	}
+enum {
+	Esc = 0x1B,
+	FS  = 0x1C,
+};
+
+static const char *path = "/dev/ttyUSB0";
+static FILE *tty;
+
+static char ttyGet(void) {
+	int ch = fgetc(tty);
+	if (ferror(tty)) err(EX_IOERR, "%s", path);
+	if (ch == EOF) errx(EX_PROTOCOL, "unexpected EOF");
+	return ch;
 }
-static void readAll(int fd, uint8_t *ptr, size_t size) {
-	while (size) {
-		ssize_t ret = read(fd, ptr, size);
-		if (ret < 0) err(EX_IOERR, "read");
-		if (!ret) errx(EX_DATAERR, "unexpected eof");
-		ptr += ret;
-		size -= ret;
-	}
+
+static void ttyPut(char ch) {
+	fputc(ch, tty);
+	if (ferror(tty)) err(EX_IOERR, "%s", path);
 }
 
-static void req2(int fd, uint8_t c) {
-	uint8_t buf[] = { 0x1B, c };
-	writeAll(fd, buf, 2);
+static void msrReq(char req) {
+	ttyPut(Esc);
+	ttyPut(req);
+}
+static char msrRes(void) {
+	char esc = ttyGet();
+	if (esc != Esc) errx(EX_PROTOCOL, "response fail %hhX", esc);
+	return ttyGet();
 }
-static uint8_t res2(int fd) {
-	uint8_t buf[2];
-	readAll(fd, buf, 2);
-	if (buf[0] != 0x1B) errx(EX_PROTOCOL, "response fail %hhX", buf[0]);
-	return buf[1];
+static char msr(char req) {
+	msrReq(req);
+	return msrRes();
 }
 
-static void req3(int fd, uint8_t c, uint8_t d) {
-	uint8_t buf[] = { 0x1B, c, d };
-	writeAll(fd, buf, 3);
+static void msrReset(void) {
+	msrReq('a');
 }
-static struct Res3 { uint8_t c, d; } res3(int fd) {
-	uint8_t buf[3];
-	readAll(fd, buf, 3);
-	if (buf[0] != 0x1B) errx(EX_PROTOCOL, "response fail %hhX", buf[0]);
-	return (struct Res3) { buf[1], buf[2] };
+
+static void msrTest(void) {
+	char test = msr('e');
+	if (test != 'y') errx(EX_PROTOCOL, "test fail %hhX", test);
+
+	char ram = msr(0x87);
+	if (ram != '0') errx(EX_PROTOCOL, "ram fail %hhX", ram);
+
+	msrReq('t');
+	printf("model: %c%c\n", msrRes(), ttyGet());
+
+	printf("firmware: %hhu\n", msr('v'));
 }
 
-static void reset(int tty) {
-	req2(tty, 'a');
+static void msrSensorTest(void) {
+	char test = msr(0x86);
+	if (test != '0') errx(EX_PROTOCOL, "sensor fail %hhX", test);
 }
 
-static void test(int tty) {
-	uint8_t res;
+static void msrLED(char led) {
+	switch (led) {
+		break; case 'a': msrReq(0x82);
+		break; case 'g': msrReq(0x83);
+		break; case 'y': msrReq(0x84);
+		break; case 'r': msrReq(0x85);
+		break; default:  msrReq(0x81);
+	}
+}
 
-	req2(tty, 'e');
-	res = res2(tty);
-	if (res != 'y') errx(EX_PROTOCOL, "test fail %hhX", res);
+static void msrSetZero(char track1, char track2) {
+	msrReq('z');
+	ttyPut(track1);
+	ttyPut(track2);
+	char zero = msrRes();
+	if (zero != '0') errx(EX_PROTOCOL, "set leading zero fail %hhX", zero);
+}
 
-	req2(tty, 0x87);
-	res = res2(tty);
-	if (res != '0') errx(EX_PROTOCOL, "ram fail %hhX", res);
+static void msrGetZero(void) {
+	char track1 = msr('l');
+	char track2 = ttyGet();
+	printf("leading zero: %hhu,%hhu\n", track1, track2);
+}
 
-	req2(tty, 't');
-	struct Res3 model = res3(tty);
-	printf("model: %c%c\n", model.c, model.d);
+static void msrSetBPI(char track1, char track2, char track3) {
+	msrReq('b');
+	switch (track) {
+		break; case 1: ttyPut(bpi == 210 ? 0xA1 : 0xA0);
+		break; case 2: ttyPut(bpi == 210 ? 0xD2 : 0x4B);
+		break; case 3: ttyPut(bpi == 210 ? 0xC1 : 0xC0);
+		break; default: ttyPut(0);
+	}
+	char set = msrRes();
+	if (set != '0') errx(EX_PROTOCOL, "set BPI fail %hhX", set);
+}
 
-	req2(tty, 'v');
-	res = res2(tty);
-	printf("firmware: %hhu\n", res);
+static void msrSetBPC(char track1, char track2, char track3) {
+	msrReq('o');
+	ttyPut(track1);
+	ttyPut(track2);
+	ttyPut(track3);
+	char bpc = msrRes();
+	if (bpc != '0') errx(EX_PROTOCOL, "set BPC fail %hhX", bpc);
+	track1 = ttyGet();
+	track2 = ttyGet();
+	track3 = ttyGet();
+	printf("BPC: %hhu,%hhu,%hhu\n", track1, track2, track3);
 }
 
-static void sensorTest(int tty) {
-	req2(tty, 0x86);
-	uint8_t res = res2(tty);
-	if (res != '0') errx(EX_PROTOCOL, "sensor fail %hhX", res);
+static void msrHiCo(void) {
+	char co = msr('x');
+	if (co != '0') errx(EX_PROTOCOL, "hi-co fail %hhX", co);
 }
 
-static void led(int tty, char c) {
-	switch (c) {
-		break; case 'a': req2(tty, 0x82);
-		break; case 'g': req2(tty, 0x83);
-		break; case 'y': req2(tty, 0x84);
-		break; case 'r': req2(tty, 0x85);
-		break; default:  req2(tty, 0x81);
+static void msrLoCo(void) {
+	char co = msr('y');
+	if (co != '0') errx(EX_PROTOCOL, "lo-co fail %hhX", co);
+}
+
+static void msrGetCo(void) {
+	char co = msr('d');
+	switch (co) {
+		break; case 'h': printf("hi-co\n");
+		break; case 'l': printf("lo-co\n");
+		break; default:  errx(EX_PROTOCOL, "get co fail %hhX", co);
 	}
 }
 
-static void status(int tty) {
-	uint8_t res = res2(tty);
-	switch (res) {
-		break; case '0': return;
-		break; case '1': errx(EX_DATAERR, "read/write error");
-		break; case '2': errx(EX_DATAERR, "command format error");
-		break; case '4': errx(EX_DATAERR, "invalid command");
-		break; case '9': errx(EX_DATAERR, "invalid card swipe");
-		break; default:  errx(EX_PROTOCOL, "status fail %hhX", res);
+static void msrStatus(void) {
+	char status = msrRes();
+	switch (status) {
+		case '0': return;
+		case '1': errx(EX_DATAERR, "read/write error");
+		case '2': errx(EX_DATAERR, "command format error");
+		case '4': errx(EX_DATAERR, "invalid command");
+		case '9': errx(EX_DATAERR, "invalid card swipe");
+		default: errx(EX_PROTOCOL, "status fail %hhX", status);
 	}
 }
 
-static void readCard(int tty) {
-	req2(tty, 'r');
-	uint8_t res = res2(tty);
-	if (res != 's') errx(EX_PROTOCOL, "read fail %hhX", res);
+static void msrRead(void) {
+	char read = msr('r');
+	if (read != 's') errx(EX_PROTOCOL, "read fail %hhX", read);
 	for (;;) {
-		readAll(tty, &res, 1);
-		if (res == '?') {
-			readAll(tty, &res, 1);
-			if (res == 0x1C) break;
+		read = ttyGet();
+		if (read == '?') {
+			read = ttyGet();
+			if (read == FS) break;
 			printf("?");
-		} else {
-			printf("%c", res);
 		}
+		printf("%c", read);
 	}
-	status(tty);
+	msrStatus();
 }
 
-static void writeCard(int tty) {
-	req2(tty, 'w');
-	req2(tty, 's');
-	uint8_t buf[2];
-	ssize_t size;
-	while (0 < (size = read(STDIN_FILENO, buf, 2))) {
-		writeAll(tty, buf, 2);
+static void msrWrite(void) {
+	msrReq('w');
+	msrReq('s');
+	int write;
+	while (EOF != (write = getchar())) {
+		ttyPut(write);
 	}
-	if (size < 0) err(EX_IOERR, "(stdin)");
-	buf[0] = '?';
-	buf[1] = 0x1C;
-	writeAll(tty, buf, 2);
-	status(tty);
+	ttyPut('?');
+	ttyPut(FS);
+	msrStatus();
 }
 
-static void eraseCard(int tty, char c) {
-	req3(tty, 'c', c - '0');
-	uint8_t res = res2(tty);
-	if (res != '0') errx(EX_PROTOCOL, "erase fail %hhX", res);
+static void msrErase(char track) {
+	msrReq('c');
+	ttyPut(track);
+	char erase = msrRes();
+	if (erase != '0') errx(EX_PROTOCOL, "erase fail %hhX", erase);
 }
 
-static void setHiCo(int tty) {
-	req2(tty, 'x');
-	uint8_t res = res2(tty);
-	if (res != '0') errx(EX_PROTOCOL, "hi-co fail %hhX", res);
-}
-static void setLoCo(int tty) {
-	req2(tty, 'y');
-	uint8_t res = res2(tty);
-	if (res != '0') errx(EX_PROTOCOL, "lo-co fail %hhX", res);
+static void msrReadRaw(void) {
+	char read = msr('m');
+	if (read != 's') errx(EX_PROTOCOL, "read raw fail %hhX", read);
+	for (;;) {
+		read = ttyGet();
+		if (read == '?') {
+			read = ttyGet();
+			if (read == FS) break;
+			printf("?");
+		}
+		printf("%c", read);
+	}
+	msrStatus();
 }
-static void getCo(int tty) {
-	req2(tty, 'd');
-	uint8_t res = res2(tty);
-	switch (res) {
-		break; case 'h': printf("hi-co\n");
-		break; case 'l': printf("lo-co\n");
-		break; default:  errx(EX_PROTOCOL, "get co fail %hhX", res);
+
+static void msrWriteRaw(void) {
+	msrReq('n');
+	msrReq('s');
+	int write;
+	while (EOF != (write = getchar())) {
+		ttyPut(write);
 	}
+	ttyPut('?');
+	ttyPut(FS);
+	msrStatus();
+}
+
+static char parse(char **arg) {
+	char n = strtoul(*arg, arg, 0);
+	if ((*arg)[0]) (*arg)++;
+	return n;
 }
 
 int main(int argc, char *argv[]) {
-	const char *file = "/dev/ttyUSB0";
 	char func = 't';
-	const char *arg = NULL;
+	char *arg = NULL;
 
 	int opt;
-	while (0 < (opt = getopt(argc, argv, "L:RTce:f:hlrtw"))) {
+	while (0 < (opt = getopt(argc, argv, "L:RTWZ:b:cd:e:f:hilrtwz"))) {
 		switch (opt) {
-			break; case 'f': file = optarg;
+			break; case 'f': path = optarg;
 			break; case '?': return EX_USAGE;
 			break; default:  func = opt; arg = optarg;
 		}
 	}
 
-	int tty = open(file, O_RDWR);
-	if (tty < 0) err(EX_NOINPUT, "%s", file);
+	int fd = open(path, O_RDWR);
+	if (fd < 0) err(EX_NOINPUT, "%s", path);
 
 	struct termios attr;
-	int error = tcgetattr(tty, &attr);
+	int error = tcgetattr(fd, &attr);
 	if (error) err(EX_IOERR, "tcgetattr");
 
 	cfmakeraw(&attr);
-	error = tcsetattr(tty, TCSANOW, &attr);
+	error = tcsetattr(fd, TCSANOW, &attr);
 	if (error) err(EX_IOERR, "tcsetattr");
 
+	tty = fdopen(fd, "r+");
+	if (!tty) err(EX_IOERR, "fdopen");
+
 	switch (func) {
-		break; case 'L': led(tty, arg[0]);
-		break; case 'R': reset(tty);
-		break; case 'T': sensorTest(tty);
-		break; case 'c': getCo(tty);
-		break; case 'e': eraseCard(tty, arg[0]);
-		break; case 'h': setHiCo(tty);
-		break; case 'l': setLoCo(tty);
-		break; case 'r': readCard(tty);
-		break; case 't': test(tty);
-		break; case 'w': writeCard(tty);
+		break; case 'L': msrLED(arg[0]);
+		break; case 'R': msrReadRaw();
+		break; case 'T': msrSensorTest();
+		break; case 'W': msrWriteRaw();
+		break; case 'Z': msrSetZero(parse(&arg), parse(&arg));
+		break; case 'b': msrSetBPC(parse(&arg), parse(&arg), parse(&arg));
+		break; case 'c': msrGetCo();
+		break; case 'd': msrSetBPI(parse(&arg), parse(&arg));
+		break; case 'e': msrErase(arg[0] - '0');
+		break; case 'h': msrHiCo();
+		break; case 'i': msrReset();
+		break; case 'l': msrLoCo();
+		break; case 'r': msrRead();
+		break; case 't': msrTest();
+		break; case 'w': msrWrite();
+		break; case 'z': msrGetZero();
 		break; default:  return EX_USAGE;
 	}
 }