commit 926bf80f8c8e7da288281f0fdfefb1f8682bed93
parent 159e0f9fe7598d07371430e6a64168557b733360
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 27 Jul 2015 01:20:29 -0700
lpcboot: support lpc43xx dfu download
Diffstat:
M | tools/lpcboot.c | | | 111 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
1 file changed, 107 insertions(+), 4 deletions(-)
diff --git a/tools/lpcboot.c b/tools/lpcboot.c
@@ -49,10 +49,107 @@ struct device_info {
uint32_t ununsed2;
};
+#define DFU_DETACH 0
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+#define DFU_GETSTATE 5
+#define DFU_ABORT 6
+
+#define STATE_APP_IDLE 0x00
+#define STATE_APP_DETACH 0x01
+#define STATE_DFU_IDLE 0x02
+#define STATE_DFU_DOWNLOAD_SYNC 0x03
+#define STATE_DFU_DOWNLOAD_BUSY 0x04
+#define STATE_DFU_DOWNLOAD_IDLE 0x05
+#define STATE_DFU_MANIFEST_SYNC 0x06
+#define STATE_DFU_MANIFEST 0x07
+#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
+#define STATE_DFU_UPLOAD_IDLE 0x09
+#define STATE_DFU_ERROR 0x0a
+
+// 0xA1 getstatus: status[1] pollms[3] state[1] stridx[1]
+int dfu_status(usb_handle *usb, unsigned *state) {
+ uint8_t io[6];
+ if (usb_ctrl(usb, io, 0xA1, DFU_GETSTATUS, 0, 0, 6) != 6) {
+ fprintf(stderr, "dfu status: io error\n");
+ return -1;
+ }
+ if (io[0]) {
+ fprintf(stderr, "dfu status: 0x%02x\n", io[0]);
+ return io[0];
+ }
+ *state = io[4];
+ return 0;
+}
+
+static uint8_t lpcheader[16] = {
+ 0xda, 0xff, 0x40, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+int dfu_download(void *_data, unsigned sz) {
+ int once = 1;
+ uint8_t *data = _data;
+ usb_handle *usb;
+ unsigned state;
+ unsigned xfer;
+ uint16_t count = 0;
+ for (;;) {
+ usb = usb_open(0x1fc9, 0x000c, 0);
+ if (usb == 0) {
+ if (once) {
+ fprintf(stderr,"waiting for DFU device...\n");
+ once = 0;
+ }
+ } else {
+ break;
+ }
+ }
+ if (dfu_status(usb, &state)) return -1;
+ if (state != STATE_DFU_IDLE) {
+ fprintf(stderr, "dfu state not idle (0x%02x)?\n", state);
+ return -1;
+ }
+
+ // prepend isp header
+ data -= 16;
+ sz += 16;
+ memcpy(data, lpcheader, 16);
+
+ // send binary
+ while (sz > 0) {
+ fprintf(stderr,".");
+ xfer = (sz > 2048) ? 2048 : sz;
+ if (usb_ctrl(usb, data, 0x21, DFU_DNLOAD, count, 0, xfer) != xfer) {
+ fprintf(stderr,"\ndfu dnload: io error\n");
+ return -1;
+ }
+ count++;
+ data += xfer;
+ sz -= xfer;
+ if (dfu_status(usb, &state)) return -1;
+ if (state != STATE_DFU_DOWNLOAD_IDLE) {
+ fprintf(stderr,"\ndfu dnload state 0x%02x?!\n", state);
+ return -1;
+ }
+ }
+ if (usb_ctrl(usb, NULL, 0x21, DFU_DNLOAD, 0, 0, 0) != 0) {
+ fprintf(stderr,"\ndfu dnload2: io error\n");
+ return -1;
+ }
+ fprintf(stderr,"\ndone\n");
+ if (dfu_status(usb, &state)) return -1;
+ if (state == STATE_DFU_MANIFEST_WAIT_RESET) return 0;
+ fprintf(stderr,"dfu dnload2: state 0x%02x?!\n", state);
+ return -1;
+}
+
int main(int argc, char **argv) {
usb_handle *usb;
- char buf[32768];
- int fd, once = 1, sz = 0, dl = 0;
+ char buf[1024*1024+256];
+ int fd, once = 1, sz = 0, dl = 0, dfu = 0;
uint32_t cmd[3];
uint32_t rep[2];
struct device_info di;
@@ -75,6 +172,9 @@ int main(int argc, char **argv) {
cmd[1] = 'R';
} else if (!strcmp(argv[1],"app")) {
cmd[1] = 'A';
+ } else if (!strcmp(argv[1],"dfu")) {
+ dl = 1;
+ dfu = 1;
} else {
return usage();
}
@@ -83,7 +183,7 @@ int main(int argc, char **argv) {
if (argc < 3)
return usage();
fd = open(argv[2], O_RDONLY);
- sz = read(fd, buf, sizeof(buf));
+ sz = read(fd, buf + 256, sizeof(buf) - 256);
close(fd);
if ((fd < 0) || (sz < 1)) {
fprintf(stderr,"error: cannot read '%s'\n", argv[2]);
@@ -92,6 +192,9 @@ int main(int argc, char **argv) {
}
cmd[2] = sz;
+ if (dfu) {
+ return dfu_download(buf + 256, sz);
+ }
for (;;) {
usb = usb_open(0x18d1, 0xdb00, 0);
if (usb == 0) {
@@ -137,7 +240,7 @@ int main(int argc, char **argv) {
if (!dl)
break;
fprintf(stderr,"sending %d bytes...\n", sz);
- if (usb_write(usb, buf, sz) != sz) {
+ if (usb_write(usb, buf + 256, sz) != sz) {
fprintf(stderr,"download failure %d\n", sz);
return -1;
}