shithub: mtk

Download patch

ref: a28c64afe2d7329cb68a41b277fa6645b81f312d
author: Alex Musolino <musolinoa@gmail.com>
date: Sat Nov 28 23:26:52 EST 2020

initial commit

--- /dev/null
+++ b/bin2txt.c
@@ -1,0 +1,188 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+enum{
+	SecSz = 0x10000,
+	SecHdrSz = 0x200,
+};
+
+enum{
+	LogFmtUTC,
+	LogFmtValid,
+	LogFmtLatitude,
+	LogFmtLongitude,
+	LogFmtHeight,
+	LogFmtSpeed,
+	LogFmtHeading,
+	LogFmtDSta,
+	LogFmtDAge,
+	LogFmtPDOP,
+	LogFmtHDOP,
+	LogFmtVDOP,
+	LogFmtNSat,
+	LogFmtSId,
+	LogFmtElevation,
+	LogFmtAzimuth,
+	LogFmtSNR,
+	LogFmtRecReason,
+	LogFmtMillis,
+	LogFmtDistance,
+
+	NumLogFmtBits
+};
+
+typedef struct LogRecord LogRecord;
+struct LogRecord
+{
+	uvlong millis;
+	double latitude;
+	double longitude;
+	ulong speed;
+};
+
+typedef struct LogFmtBit LogFmtBit;
+struct LogFmtBit
+{
+	char *name;
+	uchar size;
+};
+
+static LogFmtBit logfmtbits[] = {
+	[LogFmtUTC]			{"UTC", 4},
+	[LogFmtValid]		{"VALID", 2},
+	[LogFmtLatitude]	{"LATITUDE", 8},
+	[LogFmtLongitude]	{"LONGITUDE", 8},
+	[LogFmtHeight]		{"HEIGHT", 4},
+	[LogFmtSpeed]		{"SPEED", 4},
+	[LogFmtHeading]		{"HEADING", 4},
+	[LogFmtDSta]		{"DSTA", 2},
+	[LogFmtDAge]		{"DAGE", 4},
+	[LogFmtPDOP]		{"PDOP", 2},
+	[LogFmtHDOP]		{"HDOP", 2},
+	[LogFmtVDOP]		{"VDOP", 2},
+	[LogFmtNSat]		{"NSAT", 2},
+	[LogFmtSId]			{"SID", 4},
+	[LogFmtElevation]	{"ELEVATION", 2},
+	[LogFmtAzimuth]		{"AZIMUTH", 2},
+	[LogFmtSNR]			{"SNR", 2},
+	[LogFmtRecReason]	{"RCR", 2},
+	[LogFmtMillis]		{"MILLISECOND", 2},
+	[LogFmtDistance]	{"DISTANCE", 8},
+};
+
+typedef struct SecHdr SecHdr;
+struct SecHdr
+{
+	ushort cnt;
+	ushort mode;
+	ulong fmt;
+	ulong period;
+	ulong distance;
+	ulong speed;
+	uchar failmask[32];
+};
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+ushort
+getu16le(uchar *buf)
+{
+	ushort h;
+
+	h = buf[1];
+	h <<= 8;
+	h |= buf[0];
+	return h;
+}
+
+ulong
+getu32le(uchar *buf)
+{
+	ulong w;
+
+	w = buf[3];
+	w <<= 8;
+	w |= buf[2];
+	w <<= 8;
+	w |= buf[1];
+	w <<= 8;
+	w |= buf[0];
+	return w;
+}
+
+static char*
+logfmtstr(ulong fmt)
+{
+	static char buf[256];
+	int i;
+	char *s, *e;
+
+	s = buf;
+	e = &buf[255];
+	buf[1] = '\0';
+
+	for(i = 0; i < NumLogFmtBits; i++){
+		if((fmt & ((ulong)1<<i)) != 0)
+			s = seprint(s, e, ",%s", logfmtbits[i].name);
+	}
+	return buf+1;
+}
+
+int
+parsesector(Biobufhdr *buf)
+{
+	uchar hdr[SecHdrSz];
+	int i;
+	long n;
+
+	n = Bread(buf, hdr, SecHdrSz);
+
+	if(n == 0)
+		return 0;
+
+	if(n != SecHdrSz)
+		return -1;
+
+	if(hdr[SecHdrSz - 6] != '*')
+		return -1;
+
+	for(i = SecHdrSz - 1; i >= SecHdrSz - 4; i--){
+		if(hdr[i] != 0xbb)
+			return -1;
+	}
+
+	print("count=%uhd\n", getu16le(hdr+0));
+	print("fmt=%08ulx (%s)\n", getu32le(hdr+2), logfmtstr(getu32le(hdr+2)));
+	print("\n");
+	return i;
+}
+
+void
+main(int argc, char **argv)
+{
+	Biobuf *buf;
+	int i;
+
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND;
+	if(argc != 0)
+		usage();
+	buf = Bfdopen(0, OREAD);
+	if(buf == nil)
+		sysfatal("Bfdopen: %r");
+	i = 0;
+	for(;;){
+		Bseek(buf, i*SecSz, 0);
+		if(parsesector(buf) == 0)
+			break;
+		i++;
+	}
+}
--- /dev/null
+++ b/cmd.c
@@ -1,0 +1,3 @@
+#include <u.h>
+#include <libc.h>
+
--- /dev/null
+++ b/config.c
@@ -1,0 +1,104 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "fns.h"
+
+typedef struct Dev Dev;
+
+struct Dev
+{
+	Biobuf *in;
+	Biobuf *out;
+};
+
+int debug;
+Dev dev;
+
+int
+dprint(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	if(!debug)
+		return 0;
+	va_start(args, fmt);
+	n = vfprint(2, fmt, args);
+	va_end(args);
+	return n;
+}
+
+static char*
+docmd(char *cmd, char *expect, int timeout)
+{
+	Bprint(dev.out, "%s*%02x\r\n", cmd, crc(cmd));
+	Bflush(dev.out);
+	return readline(dev.in, expect, timeout);
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s dev\n", argv0);
+	exits("usage");
+}
+
+static void
+identify(void)
+{
+	char *line;
+
+	line = docmd("$PMTK605", "$PMTK705,", 2);
+	if(strstr(line, ",BT-Q1000EX2,") == nil){
+		fprint(2, "mtk: unsupported device\n");
+		exits("unsupported");
+	}
+}
+
+static void
+setup(void)
+{
+	dprint("setting log interval to 0.1s\n");
+	docmd("$PMTK182,1,3,1", "$PMTK001,182,1,3", 2);
+
+	dprint("enabling logging\n");
+	docmd("$PMTK182,4", "$PMTK001,182,4,3", 2);
+}
+
+static Dev*
+devopen(Dev *dev, char *path)
+{
+	dev->in = Bopen(path, OREAD);
+	if(dev->in == nil)
+		goto Error;
+	dev->out = Bopen(path, OWRITE);
+	if(dev->out == nil)
+		goto Error;
+	return dev;
+Error:
+	if(dev->in)
+		Bterm(dev->in);
+	if(dev->out)
+		Bterm(dev->out);
+	return nil;
+}
+
+void
+main(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc != 1)
+		usage();
+
+	if(!devopen(&dev, argv[0]))
+		sysfatal("devopen: %r");
+	identify();
+	setup();
+	exits(nil);
+}
--- /dev/null
+++ b/crc.c
@@ -1,0 +1,15 @@
+#include <u.h>
+#include <libc.h>
+
+uchar
+crc(char *s)
+{
+	uchar crc;
+	int i, len;
+
+	crc = 0;
+	len = strlen(s);
+	for(i = 1; i < len; i++)
+		crc ^= s[i];
+	return crc;
+}
--- /dev/null
+++ b/dump.c
@@ -1,0 +1,336 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "fns.h"
+
+int debug;
+
+int
+dprint(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	if(!debug)
+		return 0;
+	va_start(args, fmt);
+	n = vfprint(2, fmt, args);
+	va_end(args);
+	return n;
+}
+
+typedef struct Dev Dev;
+typedef struct Nibbler Nibbler;
+
+struct Dev
+{
+	Biobuf *in;
+	Biobuf *out;
+};
+
+struct Nibbler
+{
+	uint len;
+	uint cap;
+	uchar *buf;
+	uchar tmp;
+	uchar idx;
+};
+
+static void
+initnibbler(Nibbler *n, uint cap)
+{
+	n->len = 0;
+	n->cap = cap;
+	n->buf = malloc(n->cap);
+	if(n->buf == nil)
+		sysfatal("out of memory");
+	n->idx = 0;
+}
+
+static void
+putnibble(Nibbler *n, uchar nibble)
+{
+	if(n->idx == 0)
+		n->tmp = nibble;
+	else{
+		if(n->len == n->cap){
+			n->cap *= 2;
+			n->buf = realloc(n->buf, n->cap);
+		}
+		n->buf[n->len++] = n->tmp << 4 | nibble;
+	}
+	n->idx = !n->idx;
+}
+
+static void
+resetnibbler(Nibbler *n)
+{
+	n->len = 0;
+	n->idx = 0;
+}
+
+static void
+freenibbler(Nibbler *n)
+{
+	free(n->buf);
+}
+
+Dev dev;
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s dev\n", argv0);
+	exits("usage");
+}
+
+static char*
+docmd(char *cmd, char *expect)
+{
+	Bprint(dev.out, "%s*%02x\r\n", cmd, crc(cmd));
+	Bflush(dev.out);
+	return readline(dev.in, expect, 5000);
+}
+
+static void
+identify(void)
+{
+	char *line;
+
+	line = docmd("$PMTK605", "$PMTK705,");
+	if(strstr(line, ",BT-Q1000EX2,") == nil){
+		fprint(2, "mtk: unsupported device\n");
+		exits("unsupported");
+	}
+}
+
+static char*
+strnchr(char *s, int n, char c)
+{
+	if(n <= 0)
+		return nil;
+	while(n-- > 0){
+		s = strchr(s, c);
+		if(s == nil)
+			break;
+		s++;
+	}
+	return s;
+}
+
+static uchar*
+parsebyte(char *s, uchar *buf)
+{
+	if(!isxdigit(*s)){
+		fprint(2, "parsebyte: expected hex digit, got %c\n", *s);
+		return nil;
+	}
+	if(isalpha(*s))
+		*buf = tolower(*s) - 'a' + 10;
+	else
+		*buf = *s - '0';
+	*buf <<= 4;
+	s++;
+	if(!isxdigit(*s)){
+		fprint(2, "parsebyte: expected hex digit, got %c\n", *s);
+		return nil;
+	}
+	if(isalpha(*s))
+		*buf |= tolower(*s) - 'a' + 10;
+	else
+		*buf |= *s - '0';
+	return ++buf;
+}
+
+static uchar*
+dordlogcmd(uchar *buf, ulong off, ulong len)
+{
+	ulong n;
+	uchar *ebuf;
+	char *f, *line;
+	char cmd[32];
+
+	snprint(cmd, sizeof(cmd), "$PMTK182,7,%08ulx,%08ulx", off, len);
+	line = docmd(cmd, "$PMTK182,8,");
+	//fprint(2, "log output: %s", line);
+	f = strnchr(line, 2, ',');
+	if(f == nil)
+		sysfatal("bad data log response");
+	f++;
+	n = strtoul(f, nil, 16);
+	if(n != off)
+		sysfatal("data log response for wrong offset");
+	f = strchr(f, ',');
+	if(f == nil)
+		sysfatal("empty data log response");
+	f++;
+	ebuf = buf + len;
+	while(buf < ebuf && *f != '*'){
+		if(parsebyte(f, buf) == nil)
+			sysfatal("parsebyte failed");
+		buf++;
+		f += 2;
+	}
+	return buf;
+}
+
+static void
+download(void)
+{
+	uchar *buf, *bp, *nbp;
+	ulong addr, maxaddr;
+	char *f, *line;
+
+	line = docmd("$PMTK182,2,7", "$PMTK182,3,7,");
+	dprint("got log status response! %s", line);
+
+	sleep(10);
+
+	line = docmd("$PMTK182,5", "$PMTK");
+	dprint("got log disable response! %s", line);
+
+	sleep(100);
+
+	line = docmd("$PMTK182,2,8", "$PMTK182,3,8,");
+	dprint("got flash usage response! %s", line);
+
+	f = strnchr(line, 3, ',');
+	if(f == nil)
+		sysfatal("unexpected response");
+	f++;
+	maxaddr = strtoul(f, nil, 16);
+	if(maxaddr == 0)
+		sysfatal("could not determine flash usage");
+	dprint("downloading %uldKB from device\n", (maxaddr+1)>>10);
+	buf = malloc(maxaddr + 1);
+	if(buf == nil)
+		sysfatal("could not allocate data buffer");
+	bp = buf;
+	addr = 0;
+	while(addr < maxaddr){
+		nbp = dordlogcmd(bp, addr, 0x100);
+		write(1, bp, nbp - bp);
+		addr += nbp - bp;
+		bp = nbp;
+		dprint("progess: %uld/%uld\n", addr, maxaddr);
+	}
+}
+
+static void
+dordlogcmd2(Nibbler *nblr, ulong off, ulong len)
+{
+	ulong n, chklen;
+	char *f, *line;
+	char cmd[32];
+
+	snprint(cmd, sizeof(cmd), "$PMTK182,7,%.8ulX,%.8ulX", off, len);
+dprint("cmd=%s\n", cmd);
+	line = docmd(cmd, "$PMTK182,8,");
+	goto Seek;
+	while(len > 0){
+		chklen = nblr->len;
+		while(*f != '*'){
+			if(!isxdigit(*f))
+				sysfatal("bad character in response");
+			if(isdigit(*f))
+				putnibble(nblr, *f - '0');
+			else
+				putnibble(nblr, toupper(*f) - 'A');
+			f++;
+		}
+		chklen = nblr->len - chklen;
+dprint("got %uld byte chunk\n", chklen);
+		len -= chklen;
+		off += chklen;
+		line = readline(dev.in, "$PMTK", 5000);
+	Seek:
+		if(strncmp(line, "$PMTK001,182,7,", 15) == 0){
+			dprint("@@@@ got ack!\n");
+			return;
+		}
+		if(strncmp(line, "$PMTK182,8", 10) != 0)
+			sysfatal("unexpected data log response");
+		dprint("log output: %s", line);
+		f = strnchr(line, 2, ',');
+		if(f == nil)
+			sysfatal("bad data log response");
+		f++;
+		n = strtoul(f, nil, 16);
+		//if(n != off)
+		//	sysfatal("data log response for wrong offset");
+		f = strchr(f, ',');
+		if(f == nil)
+			sysfatal("empty data log response");
+		f++;
+		while(n < off){
+			n++;
+			f += 2;
+		}
+	}
+}
+
+static void
+download2(void)
+{
+	Nibbler n;
+	ulong addr, maxaddr;
+	char *f, *line;
+
+	line = docmd("$PMTK182,2,7", "$PMTK182,3,7,");
+	dprint("got log status response! %s", line);
+
+	sleep(10);
+
+	line = docmd("$PMTK182,5", "$PMTK");
+	dprint("got log disable response! %s", line);
+
+	sleep(100);
+
+	line = docmd("$PMTK182,2,8", "$PMTK182,3,8,");
+	dprint("got flash usage response! %s", line);
+
+	f = strnchr(line, 3, ',');
+	if(f == nil)
+		sysfatal("unexpected response");
+	f++;
+	maxaddr = strtoul(f, nil, 16);
+	if(maxaddr == 0)
+		sysfatal("could not determine flash usage");
+	dprint("downloading %uld bytes from device\n", maxaddr+1);
+
+	initnibbler(&n, 0x400);
+	addr = 0;
+	maxaddr = 0x400;
+	while(addr < maxaddr){
+		dordlogcmd2(&n, addr, 0x400);
+		write(1, n.buf, n.len);
+		addr += n.len;
+		dprint("progess: %.2f\n", 100.0*addr/maxaddr);
+		resetnibbler(&n);
+	}
+	freenibbler(&n);
+}
+
+void
+main(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc != 1)
+		usage();
+	dev.in = Bopen(argv[0], OREAD);
+	if(dev.in == nil)
+		sysfatal("open: %r");
+	dev.out = Bopen(argv[0], OWRITE);
+	if(dev.out == nil)
+		sysfatal("open: %r");
+	identify();
+	download2();
+}
--- /dev/null
+++ b/erase.c
@@ -1,0 +1,119 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "fns.h"
+
+typedef struct Dev Dev;
+
+struct Dev
+{
+	Biobuf *in;
+	Biobuf *out;
+};
+
+int debug;
+Dev dev;
+
+int
+dprint(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	if(!debug)
+		return 0;
+	va_start(args, fmt);
+	n = vfprint(2, fmt, args);
+	va_end(args);
+	return n;
+}
+
+static char*
+docmd(char *cmd, char *expect, int timeout)
+{
+	Bprint(dev.out, "%s*%02x\r\n", cmd, crc(cmd));
+	Bflush(dev.out);
+	return readline(dev.in, expect, timeout);
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s dev\n", argv0);
+	exits("usage");
+}
+
+static void
+identify(void)
+{
+	char *line;
+
+	line = docmd("$PMTK605", "$PMTK705,", 2);
+	if(strstr(line, ",BT-Q1000EX2,") == nil){
+		fprint(2, "mtk: unsupported device\n");
+		exits("unsupported");
+	}
+}
+
+static void
+erase(void)
+{
+	char *line;
+
+	line = docmd("$PMTK182,2,7", "$PMTK182,3,7,", 2);
+	dprint("got log status response! %s", line);
+
+	line = docmd("$PMTK182,2,2", "$PMTK182,3,2,", 2);
+	dprint("got log format response! %s", line);
+
+	line = docmd("$PMTK182,5", "$PMTK001,182,5,3", 2);
+	dprint("got log disable response! %s", line);
+
+	sleep(10);
+
+	line = docmd("$PMTK182,6,1", "$PMTK001,182,6", 30);
+	dprint("got flash erase response! %s", line);
+
+	sleep(100);
+
+	line = docmd("$PMTK182,4", "$PMTK001,182,4,3", 2);
+	dprint("got log enable response! %s", line);
+}
+
+static Dev*
+devopen(Dev *dev, char *path)
+{
+	dev->in = Bopen(path, OREAD);
+	if(dev->in == nil)
+		goto Error;
+	dev->out = Bopen(path, OWRITE);
+	if(dev->out == nil)
+		goto Error;
+	return dev;
+Error:
+	if(dev->in)
+		Bterm(dev->in);
+	if(dev->out)
+		Bterm(dev->out);
+	return nil;
+}
+
+void
+main(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc != 1)
+		usage();
+
+	if(!devopen(&dev, argv[0]))
+		sysfatal("devopen: %r");
+	identify();
+	erase();
+	exits(nil);
+}
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,2 @@
+uchar crc(char*);
+char *readline(Biobufhdr*, char*, int);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,31 @@
+</$objtype/mkfile
+
+LIB=\
+	common.a$O\
+
+LIBOFILES=\
+	crc.$O\
+	cmd.$O\
+	read.$O\
+
+HFILES=\
+	dat.h\
+	fns.h\
+
+TARG=\
+	bin2txt\
+	config\
+	dump\
+	erase
+
+BIN=$home/bin/$objtype/mtk
+
+</sys/src/cmd/mkmany
+
+$BIN:
+	mkdir -p $BIN
+
+$BIN/%: $BIN
+
+common.a$O: $LIBOFILES
+	ar vu $LIB $newprereq
--- /dev/null
+++ b/read.c
@@ -1,0 +1,21 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+char*
+readline(Biobufhdr *in, char *expect, int timeout)
+{
+	static char *line = nil;
+
+	alarm(timeout * 1000);
+	for(;;){
+		if(line != nil)
+			free(line);
+		line = Brdstr(in, '\n', 0);
+		if(line != nil)
+		if(strncmp(line, expect, strlen(expect)) == 0)
+			break;
+	}
+	alarm(0);
+	return line;
+}