diff options
author | June McEnroe <june@causal.agency> | 2018-11-07 21:28:37 -0500 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2018-11-07 21:28:37 -0500 |
commit | 507aced2e116a6acb6ffb83acddfab5545d40116 (patch) | |
tree | cb08651b4f4f9ae6cc672cebc31b32ac28942810 | |
parent | Add Low — Double Negative (diff) | |
download | src-507aced2e116a6acb6ffb83acddfab5545d40116.tar.gz src-507aced2e116a6acb6ffb83acddfab5545d40116.zip |
Implement all of MSR606
-rw-r--r-- | bin/man/msr606.1 | 105 | ||||
-rw-r--r-- | bin/msr606.c | 318 |
2 files changed, 294 insertions, 129 deletions
diff --git a/bin/man/msr606.1 b/bin/man/msr606.1 new file mode 100644 index 00000000..fc18635b --- /dev/null +++ b/bin/man/msr606.1 @@ -0,0 +1,105 @@ +.Dd November 7, 2018 +.Dt MSR606 1 +.Os "Causal Agency" +. +.Sh NAME +.Nm msr606 +.Nd magnetic stripe card reader/writer +. +.Sh SYNOPSIS +.Nm +.Op Fl RTWchiltwz +.Op Fl L Ar led +.Op Fl Z Ar zero +.Op Fl b Ar bpc +.Op Fl e Ar track +.Op Fl f Ar tty +. +.Sh DESCRIPTION +.Nm +operates the MSR606 magnetic stripe card reader/writer. +. +.Pp +The arguments are as follows: +.Bl -tag -width Ds +. +.It Fl L Ar led +Set LEDs. +The values for +.Ar led +are: +.Sy n +for none, +.Sy a +for all, +.Sy g +for green, +.Sy y +for yellow, +.Sy r +for red. +. +.It Fl R +Read raw data from a card to standard output. +. +.It Fl T +Perform a sensor test. +. +.It Fl W +Write raw data to a card from standard input. +. +.It Fl Z Ar zero +Set leading zero. +.Ar zero +is a comma-separated list of two numbers +indicating the leading zero setting +for tracks 1 & 3 +and track 2, +respectively. +. +.It Fl b Ar bpc +Set bits per character for each track. +.Ar bpc +is a comma-separated list of 3 numbers +indicating the BPC for each track. +Valid values range from 5 to 8. +. +.It Fl c +Print the coercivity status. +. +.It Fl e Ar track +Erase a card. +.Ar track +is a number from 1 to 7 +representing a 3-bit set +of tracks to erase. +. +.It Fl f Ar tty +Open the device +.Ar tty . +The default device is +.Pa /dev/ttyUSB0 . +. +.It Fl h +Set high coercivity. +. +.It Fl i +Reset the device. +. +.It Fl l +Set low coercivity. +. +.It Fl r +Read ISO format data from card to standard output. +. +.It Fl t +Perform communication and RAM tests. +Print the hardware model and firmware version. +This is the default operation. +. +.It Fl w +Write ISO format data to card from standard input. +. +.It Fl z +Print the leading zero setting. +.El 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; } } |