ref: a28c64afe2d7329cb68a41b277fa6645b81f312d
dir: /dump.c/
#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(); }