ref: 4ec6177689f8274f645ba24e9b8a52883c405608
dir: /stm32up.c/
#include <u.h> #include <libc.h> static int debug = 0; static uchar buf[256]; enum { Doinfo, Doread, Dowrite, Doerase, Doflash, Dogo, Doreadprot, Doreadunprot, Dowriteprot, Dowriteunprot, Docsum }; enum Uartcmd { Nop = 0x00, Full = 0xFF, Ack = 0x79, Nack = 0x1F, Conninit = 0x7F, Get = 0x00, Getversion = 0x01, Getid = 0x02, Read = 0x11, Go = 0x21, Write = 0x31, Erase = 0x43, Eraseext = 0x44, Special = 0x50, Specialext = 0x51, Writeprot = 0x63, Writeunprot = 0x73, Readprot = 0x82, Readunprot = 0x92, Checksum = 0xA1 // this is not yet implemented }; void stm_info(int dev) { if(debug) fprint(2, "acquiring device info\n"); // get the protocol version and commands buf[0] = Get; buf[1] = Full ^ Get; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write: %r\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'get' rejected\n"); exits("protoerr"); } if(readn(dev, buf, 14) == 0 || buf[0] != 11 || buf[13] != Ack) { fprint(2, "protocol error while getting device info\n"); exits("protoerr"); } fprint(2, "protocol version: %x\n", buf[1]); if(debug) { for(int i = 0; i < 14; i++) fprint(2, "0x%02x ", buf[i]); fprint(2, "\n"); } if(buf[2] != Get || buf[3] != Getversion || buf[4] != Getid || buf[5] != Read || buf[6] != Go || buf[7] != Write || (buf[8] != Erase && buf[8] != Eraseext) || buf[9] != Writeprot || buf[10] != Writeunprot || buf[11] != Readprot || buf[12] != Readunprot) { fprint(2, "command code mismatch, run with -d\n"); return; } // get the device id if(debug) fprint(2, "getting device id\n"); buf[0] = Getid; buf[1] = Full ^ Getid; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write\n"); exits("protoerr");; } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'get id' command rejected\n"); exits("protoerr");; } if(readn(dev, buf, 4) == 0 || buf[0] != 1 || buf[3] != Ack) { fprint(2, "protocol error while getting device id\n"); exits("protoerr");; } fprint(2, "device id: %x%x\n", buf[1], buf[2]); } void stm_protect(int dev, int acmd) { char *cmds; int cmd; switch(acmd) { case Doreadprot: cmd = Readprot; cmds = "read protect"; break; case Doreadunprot: cmd = Readunprot; cmds = "read unprotect"; break; case Dowriteunprot: cmd = Writeunprot; cmds = "write unprotect"; break; default: fprint(2, "stm_protect does not handle this command\n"); exits("apperr"); } if(debug) fprint(2, "%s device\n", cmds); buf[0] = cmd; buf[1] = Full ^ cmd; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write\n"); exits("deverr");; } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'%s' command rejected\n", cmds); exits("protoerr");; } buf[0] = Ack; if(write(dev, buf, 1) != 1) { fprint(2, "unable to ack %s", cmds); exits("deverr");; } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'%s' unable to ack\n", cmds); exits("protoerr");; } fprint(2, "%s done\n", cmds); } void stm_readpage(int dev, uvlong addr, uchar sz) // size - 1 { if(addr + (sz + 1) < addr) { fprint(2, "addr + sz < addr; please check values\n"); exits("protoerr"); } buf[0] = Read; buf[1] = Full ^ Read; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'read memory' command rejected\n"); exits("protoerr"); } // send the start address buf[0] = (addr >> 24) & 0xFF; buf[1] = (addr >> 16) & 0xFF; buf[2] = (addr >> 8) & 0xFF; buf[3] = addr & 0xFF; buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; if(write(dev, buf, 5) != 5) { fprint(2, "unable to write\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "read memory address rejected\n"); exits("protoerr"); } // send the size buf[0] = sz; buf[1] = Full ^ buf[0]; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "read command rejected; check address and count\n"); exits("protoerr"); } // read contents int c = readn(dev, buf, sz + 1); if(c != sz + 1) { fprint(2, "memory read error, address 0x%08llx, size-1 0x%02x, c %d\n", addr, sz, c); exits("apperr"); } write(1, buf, c); } void stm_writepage(int dev, uvlong addr, uchar sz) { if(addr + sz < addr) { fprint(2, "addr + sz < addr; please check values\n"); exits("protoerr"); } buf[0] = Write; buf[1] = Full ^ Write; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'write memory' command rejected 0x%02x\n", buf[0]); exits("protoerr"); } // send the start address buf[0] = (addr >> 24) & 0xFF; buf[1] = (addr >> 16) & 0xFF; buf[2] = (addr >> 8) & 0xFF; buf[3] = addr & 0xFF; buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; if(write(dev, buf, 5) != 5) { fprint(2, "unable to write\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "write memory address rejected\n"); exits("protoerr"); } // send the size buf[0] = sz - 1; if(write(dev, buf, 1) != 1) { fprint(2, "unable to write\n"); exits("deverr"); } // write contents int c = readn(0, buf, sz); if(c != sz) { fprint(2, "error reading stdin\n"); exits("apperr"); } if(write(dev, buf, c) != c) { fprint(2, "unable to write data\n"); exits("deverr"); } // write data checksum buf[0] = (sz - 1) ^ buf[0]; for(int i = 1; i < c; i++) buf[0] ^= buf[i]; if(write(dev, buf, 1) != 1) { fprint(2, "unable to write checksum\n"); exits("deverr"); } // ack the command and finish if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "write data rejected, got 0x%02x\n", buf[0]); exits("protoerr"); } } void stm_read(int dev, uvlong addr, uvlong sz) { if(sz == 0) { fprint(2, "read size cannot be 0\n"); exits("protoerr"); } if(addr + sz < addr) { fprint(2, "addr + sz < addr; please check values\n"); exits("protoerr"); } fprint(2, "reading device memory 0x%08llx, size: 0x%08llx\n", addr, sz); // start read memory command uvlong caddr = addr; uvlong csz = sz; while(caddr < (addr + sz)) { uchar rsz = 0xFF; if(csz < 0x100) rsz = csz - 1; stm_readpage(dev, caddr, rsz); caddr = caddr + (rsz + 1); csz = csz - (rsz + 1); } fprint(2, "memory read\n"); } void stm_write(int dev, uvlong addr, uvlong sz) { if(sz == 0) { fprint(2, "write size cannot be 0\n"); exits("protoerr"); } if(addr & 0x3 || sz & 0x3) { fprint(2, "address and lenght must be 4 byte aligned\n"); exits("apperr"); } if(addr + sz < addr) { fprint(2, "addr + sz < addr; please check values\n"); exits("protoerr"); } fprint(2, "writing device memory 0x%08llx, size: 0x%08llx\n", addr, sz); // start read memory command uvlong caddr = addr, laddr = addr; uvlong csz = sz; while(caddr < (addr + sz)) { uchar rsz = 0x20; if(csz < 0x20) rsz = csz; stm_writepage(dev, caddr, rsz); if(debug && caddr - laddr >= 2048) { fprint(2, "progress: 0x%08llx / 0x%08llx\n", caddr, addr + sz); laddr = caddr; } caddr = caddr + rsz; csz = csz - rsz; } fprint(2, "memory written\n"); } void stm_erase(int dev, uint n, uchar spage) { if(n > 256) { fprint(2, "unable to erase more than 256 pages\n"); exits("apperr"); } if(debug) fprint(2, "erasing memory, %d pages, start %d\n", n, spage); uchar csum = 0; // send erase command buf[0] = Erase; buf[1] = Full ^ Erase; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write: %r\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'erase' rejected\n"); exits("protoerr"); } buf[0] = n - 1; if(write(dev, buf, 1) != 1) { fprint(2, "unable to write: %r\n"); exits("deverr"); } // full erase if(n == 256) { if(debug) fprint(2, "trying a full erase\n"); buf[0] = 0; if(write(dev, buf, 1) != 1) { fprint(2, "unable to write: %r\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "unable to fully erase, got 0x%02x\n", buf[0]); exits("protoerr"); } if(debug) fprint(2, "performed a full erase\n"); return; } csum = n - 1; for(int i = 0; i < n; i++) { buf[i] = spage + i; csum ^= buf[i]; } buf[n] = csum; for(int i = 0; i < n + 1; i++) fprint(2, "0x%02x ", buf[i]); fprint(2, "\n"); if(write(dev, buf, (uint)n + 1) != (uint)n + 1) { fprint(2, "unable to write: %r\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'erase' rejected\n"); exits("protoerr"); } if(debug) fprint(2, "erased successfully performed\n"); } void stm_go(int dev, uvlong addr) { if(debug) fprint(2, "device requested to jump to 0x%08llx\n", addr); // get the protocol version and commands buf[0] = Go; buf[1] = Full ^ Go; if(write(dev, buf, 2) != 2) { fprint(2, "unable to write: %r\n"); exits("deverr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "'go' rejected\n"); exits("protoerr"); } // send the start address buf[0] = (addr >> 24) & 0xFF; buf[1] = (addr >> 16) & 0xFF; buf[2] = (addr >> 8) & 0xFF; buf[3] = addr & 0xFF; buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; if(write(dev, buf, 5) != 5) { fprint(2, "unable to write\n"); exits("protoerr"); } if(readn(dev, buf, 1) == 0 || buf[0] != Ack) { fprint(2, "go address rejected\n"); exits("protoerr"); } fprint(2, "device jumped to 0x%08llx\n", addr); } void stm_checksum(int dev) { } void usage(void) { fprint(2, "usage: %s [-d] [-D device] [-b baud] command args ..\n", argv0); fprint(2, " info\n"); fprint(2, " read addr size\n"); fprint(2, " write addr size\n"); fprint(2, " erase page n\n"); fprint(2, " flash addr size\n"); fprint(2, " go addr\n"); fprint(2, " readp, readunp, writeunp\n"); fprint(2, " TODO: writep,csum\n"); exits("usage"); } void main(int argc, char **argv) { char* devpath = "/dev/eia0"; char* baudstr = "9600"; char tmp[256]; int action = -1; int dev = -1; uvlong addr = 0; uvlong sz = 0; ARGBEGIN { case 'b': baudstr = ARGF(); break; case 'd': debug = 1; break; case 'D': devpath = EARGF(usage()); break; default: usage(); } ARGEND if(argv[0] == 0) usage(); if(!strcmp(argv[0], "info")) action = Doinfo; if(!strcmp(argv[0], "read")) { if(argv[1] == 0 || argv[2] == 0) usage(); addr = strtoull(argv[1], nil, 16); sz = strtoull(argv[2], nil, 16); action = Doread; } if(!strcmp(argv[0], "write")) { if(argv[1] == 0 || argv[2] == 0) usage(); addr = strtoull(argv[1], nil, 16); sz = strtoull(argv[2], nil, 16); action = Dowrite; } if(!strcmp(argv[0], "erase")) { if(argv[1] == 0 || argv[2] == 0) usage(); addr = strtoull(argv[1], nil, 16); sz = strtoull(argv[2], nil, 16); action = Doerase; } if(!strcmp(argv[0], "flash")) { if(argv[1] == 0 || argv[2] == 0) usage(); addr = strtoull(argv[1], nil, 16); sz = strtoull(argv[2], nil, 16); action = Doflash; } if(!strcmp(argv[0], "go")) { if(argv[1] == 0) usage(); addr = strtoull(argv[1], nil, 16); action = Dogo; } if(!strcmp(argv[0], "readp")) action = Doreadprot; if(!strcmp(argv[0], "readunp")) action = Doreadunprot; if(!strcmp(argv[0], "writeunp")) action = Doreadunprot; if(!strcmp(argv[0], "csum")) action = Docsum; if(action < 0) usage(); // set serial operating parameters if(debug) fprint(2, "setting modem to b%s 8E1\n", baudstr); int devctl = open(smprint("%sctl", devpath), OWRITE); if(devctl < 0) { fprint(2, "unable to open device ctl %sctl: %r\n", devpath); exits("deverr"); } sprint(tmp, "b%s\n", baudstr); if(write(devctl, tmp, 8) < 0) { fprint(2, "error: unable to set serial baud: %r\n"); exits("deverr"); } if(write(devctl, "l8\n", 3) < 0) { fprint(2, "error: unable to set serial length: %r\n"); exits("deverr"); } if(write(devctl, "pe\n", 3) < 0) { fprint(2, "error: unable to set serial parity: %r\n"); exits("deverr"); } if(write(devctl, "s1\n", 3) < 0) { fprint(2, "error: unable to set serial stop bits: %r\n"); exits("deverr"); } // if(write(devctl, "f\n", 3) < 0) { // fprint(2, "error: unable to flush the serial line: %r\n"); // exits("deverr"); // } if(debug) fprint(2, "modem set up accordingly\n"); close(devctl); // opening serial line if(debug) fprint(2, "opening %s\n", devpath); dev = open(devpath, ORDWR); if(dev < 0) { fprint(2, "unable to open device %s: %r\n", devpath); exits("deverr"); } // initiate connection; send Conninit, and wait for Ack if(debug) fprint(2, "initiating connection\n"); buf[0] = Conninit; if(write(dev, buf, 1) != 1) { fprint(2, "error writing while initiating\n"); exits("connerr"); } if(readn(dev, buf, 1) != 1 || buf[0] != Ack) { fprint(2, "connection could not be initiated, got %x\n", buf[0]); exits("connerr"); } // handle action switch(action) { case Doinfo: stm_info(dev); break; case Doread: stm_read(dev, addr, sz); break; case Dowrite: stm_write(dev, addr, sz); break; case Doerase: stm_erase(dev, addr, sz); break; case Doflash: stm_erase(dev, 256, 0); stm_write(dev, addr, sz); stm_go(dev, addr); break; case Doreadprot: case Doreadunprot: case Dowriteunprot: stm_protect(dev, action); break; case Dogo: stm_go(dev, addr); break; case Docsum: stm_checksum(dev); break; default: exits("apperr"); } if(debug) fprint(2, "exiting\n"); exits(nil); }