Firmware Upgrade (DFU)¶
DFU (Device Firmware Upgrade) is the standard USB protocol for flashing firmware.
Present a DFU target that dfu-util can UPLOAD from (read out) or DOWNLOAD to
(write). Each target is a linear byte store - a file, a flash part, whatever you supply -
described by callbacks; the class runs the DFU 1.1 state machine and stores nothing itself.
A file-backed target¶
import time, usbip
from usbip.device import USBDevice
from usbip.classes.device import DFU
class FileTarget: # one DFU target backed by a file
name, i_string = "fw0", 0
def __init__(self, path):
self.f = open(path, "a+b", buffering=0)
self.length = self.f.seek(0, 2)
def write(self, off, data):
self.f.seek(off)
self.f.write(data)
self.length = max(self.length, off + len(data))
def read(self, off, size):
self.f.seek(off)
return self.f.read(min(size, max(0, self.length - off)))
def begin_download(self):
self.length = 0
def finish_download(self):
self.f.truncate(self.length)
dev = USBDevice(0x1209, 0x000F, product="USBIP DFU")
dev.add(DFU([FileTarget("firmware.bin")]))
dev.plug()
time.sleep(3600) # serve (Ctrl-C to stop)
#include <stdio.h>
#include <unistd.h>
#include "usbip-device.h"
#include "classes/dfu.h"
static uint32_t fw_len; /* bytes stored so far */
static int wr(void *c, uint32_t off, const uint8_t *d, uint32_t n) {
FILE *fp = c;
if (fseek(fp, (long)off, SEEK_SET) != 0 || fwrite(d, 1, n, fp) != n)
return DFU_STATUS_errWRITE;
if (off + n > fw_len)
fw_len = off + n;
return DFU_STATUS_OK;
}
static int rd(void *c, uint32_t off, uint8_t *d, uint32_t n) {
FILE *fp = c;
if (off >= fw_len)
return 0; /* end of image */
if (n > fw_len - off)
n = fw_len - off;
if (fseek(fp, (long)off, SEEK_SET) != 0)
return 0;
return (int)fread(d, 1, n, fp);
}
int main(void) {
FILE *fp = fopen("firmware.bin", "w+b");
setvbuf(fp, NULL, _IONBF, 0); /* reads and writes alternate */
usbip_device *g = usbip_device_create(0x1209, 0x000F);
dfu_target tgt = {
.name = "fw0",
.ctx = fp, /* passed back to wr/rd */
.write = wr,
.read = rd,
};
dfu_opts opts = {
.targets = &tgt,
.n_targets = 1,
};
dfu_add(g, &opts);
usbip_device_plug(g, NULL);
for (;;) sleep(1);
}
Flash it with dfu-util¶
dfu-util -l # lists the targets (each is an "alt setting")
dfu-util -a 0 -U readback.bin # UPLOAD target 0 (device -> file)
dfu-util -a 0 -D firmware.bin # DOWNLOAD to target 0 (file -> device)
Targets and alternate settings¶
Each target maps to a USB alternate setting - dfu-util -a N selects which one.
The class hands your write callback the incoming bytes in transfer_size chunks at
increasing offsets; return 0 for success or a DFU_STATUS_* code to report an error
to the host.
Full program: examples/dfu_device.py; in C, examples/device/dfu_device.c. API:
DFU.