Skip to content

Commit

Permalink
Device Firmware Upgrade (DFU) support.
Browse files Browse the repository at this point in the history
* Adds "DFU Runtime" support while the application is in "HID"
  (normal) mode; this is controllable in `user_config.h` and defaults
  to 'off'. This allows a DFU tool to trigger a reboot into "DFU"
  mode.

* Adds "DFU Transfer" mode for the application, which avoids most
  normal setup steps and prepares the device for firmware/config
  upload or download. The board will stay in this mode for a maximum
  of 30 seconds, and will reboot if no successful DFU operation occurs
  within that time (or if a successful operation occurs.)

* Adds serial number reporting using the Pico SDK "unique_id" function
  which obtains the hardware serial number from the flash chip.

* Adds DFU 'upload' mode, allowing the user to obtain the current
  firmware or runtime configuration from the device.

* Adds DFU 'download' mode, allowing the user to flash new firmware or
  configuration to the device. The device will automatically reboot
  after the flash operation.

Since this is 'phase 1', it only supports DFU operations against the
board the host is attached to (A or B), it does not support operations
against the 'other' board over a single connection. This means that
upgrading firmware must be done twice, connecting to each board.
  • Loading branch information
kpfleming committed Mar 30, 2024
1 parent cf4c798 commit 817d0d3
Show file tree
Hide file tree
Showing 14 changed files with 917 additions and 192 deletions.
7 changes: 5 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ set(COMMON_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/led.c
${CMAKE_CURRENT_LIST_DIR}/src/uart.c
${CMAKE_CURRENT_LIST_DIR}/src/usb.c
${CMAKE_CURRENT_LIST_DIR}/src/hid.c
${CMAKE_CURRENT_LIST_DIR}/src/dfu.c
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
Expand All @@ -62,13 +64,14 @@ set(COMMON_LINK_LIBRARIES
hardware_gpio
hardware_pio

tinyusb_device
tinyusb_device
tinyusb_host
pico_multicore
Pico-PIO-USB
pico_unique_id
)

# Pico A - Keyboard (board_role = 0)
# Pico A - Keyboard (board_role = 0)
# B - Mouse (board_role = 1)

set(binaries board_A board_B)
Expand Down
207 changes: 207 additions & 0 deletions DFU.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Device Firmware Update over USB

DeskHop devices support [USB DFU (Device Firmware
Update)](https://en.wikipedia.org/wiki/USB#Device_Firmware_Upgrade_mechanism)
version
[1.1](https://web.archive.org/web/20141011015811/http://www.usb.org/developers/docs/devclass_docs/DFU_1.1.pdf). DFU
can be used to both upload (device to host) and download (host to
device) firmware and configuration data.

## Tools and modes

There are a variety of DFU tools available for various platforms. The
DeskHop implementation has been tested with [dfu-util version
0.11](https://dfu-util.sourceforge.net/). This tool is available as a
regular package in most Linux distributions; it can be installed on
macOS using Homebrew; and it can be installed on Windows using
packages from the project site.

All of the examples in this documentation use `dfu-util` but the
commands can be adapted to other tools.

On Linux systems, `dfu-util` requires root access, or sufficient
permissions to the USB devices to allow raw USB data transfers.

DFU operates in two modes: 'runtime' and 'transfer'.

### 'runtime' mode

DFU 'runtime' mode is an additional feature available during DeskHop's
normal operation (as a USB HID). This mode allows the host software to
trigger a switch to DFU 'transfer' mode in order to initiate uploads or
downloads. Because this can introduce a security concern, it is
disabled by default but can be enabled by setting `DFU_RT_ENABLED` to
`1` in `user_config.h` when building the DeskHop firmware.

### 'transfer' mode

DFU 'transfer' mode allows uploads and downloads. It can be entered from
DFU 'runtime' mode by using a DFU host tool to trigger a `DETACH`
operation, or by using the key sequences `Left Shift-Right Shift-F12-C`
(for board A) and `Left Shift-Right Shift-F12-D` (for board B).

Once this mode has been entered, the DeskHop will stay in the mode for
a maximum of 30 seconds, or until an upload or download has been
completed. Also note that once this mode has been entered on a board
the normal operation of that board (keyboard or mouse input, and
output to the host) will stop. Alternative input device(s) will need
to be connected to the host in order to issue commands to execute the
DFU transfer operations.

## Firwmare management with 'runtime' mode

### Backup/Archive

To backup the firmware from a DeskHop device:

(command run on host connected to board A)
```shell
$ dfu-util -a board_a_fw -d 2E8A:107C -U firmware_a.bin
```

(command run on host connected to board B)
```shell
$ dfu-util -a board_b_fw -d 2E8A:107C -U firmware_b.bin
```

These commands will switch the DeskHop into DFU 'transfer' mode,
upload the firmware from the DeskHop's flash memory, and then the
DeskHop will reboot back into normal operation.

### Upgrade

To upgrade the firmware on a DeskHop device:

(command run on host connected to board A)
```shell
$ dfu-util -a board_a_fw -d 2E8A:107C -D board_A.bin
```

(command run on host connected to board B)
```shell
$ dfu-util -a board_b_fw -d 2E8A:107C -U board_B.bin
```

The firmware filenames listed above are the usual names produced by
the DeskHop firmware build process; do not attempt to upload the
`.uf2`, `.elf`, or `.hex` versions of the firmware file, as doing so
will result in a non-operational DeskHop board and recovery will
require using the `BOOTSEL` button to boot the board into USB recovery
mode.

These commands will switch the DeskHop into DFU 'transfer' mode,
download the firmware into the DeskHop's flash memory, and then the
DeskHop will reboot back into normal operation.

## Firwmare management without 'runtime' mode

### Backup/Archive

To backup the firmware from a DeskHop device, switch one of the
DeskHop boards into 'transfer' mode using the key sequence documented
above. Within 30 seconds:

(command run on host connected to board A)
```shell
$ dfu-util -a board_a_fw -d 2E8A:XXXX -U firmware_a.bin
```

(command run on host connected to board B)
```shell
$ dfu-util -a board_b_fw -d 2E8A:XXXX -U firmware_b.bin
```

These commands will upload the firmware from the DeskHop's flash
memory, and then the DeskHop will reboot back into normal operation.

### Upgrade

To upgrade the firmware on a DeskHop device, switch one of the DeskHop
boards into 'transfer' mode using the key sequence documented
above. Within 30 seconds:

(command run on host connected to board A)
```shell
$ dfu-util -a board_a_fw -d 2E8A:107C -D board_A.bin
```

(command run on host connected to board B)
```shell
$ dfu-util -a board_b_fw -d 2E8A:107C -U board_B.bin
```

The firmware filenames listed above are the usual names produced by
the DeskHop firmware build process; do not attempt to upload the
`.uf2`, `.elf`, or `.hex` versions of the firmware file, as doing so
will result in a non-operational DeskHop board and recovery will
require using the `BOOTSEL` button to boot the board into USB recovery
mode.

These commands will download the firmware into the DeskHop's flash
memory, and then the DeskHop will reboot back into normal operation.

## Configuration management with 'runtime' mode

### Backup

To backup the configuration from a DeskHop device:

(command run on host connected to either board)
```shell
$ dfu-util -a config -d 2E8A:107C -U config.bin
```

This command will switch the DeskHop into DFU 'transfer' mode,
upload the configuration from the DeskHop's flash memory, and then
the DeskHop will reboot back into normal operation.

Note that the configuration data is a binary data structure; it is not
human-readable and there are no tools available to convert it into a
human-readable format.

### Restore

To restore the configuration on a DeskHop device:

(command run on host connected to either board)
```shell
$ dfu-util -a config -d 2E8A:107C -D config.bin
```

This command will switch the DeskHop into DFU 'transfer' mode,
download the configuration into the DeskHop's flash memory, and then
the DeskHop will reboot back into normal operation.

## Configuration management without 'runtime' mode

### Backup/Archive

To backup the configuration from a DeskHop device, switch one of the
DeskHop boards into 'transfer' mode using the key sequence documented
above. Within 30 seconds:

(command run on host connected to the board in 'transfer' mode)
```shell
$ dfu-util -a config -d 2E8A:XXXX -U config.bin
```

This command will upload the configuration from the DeskHop's flash
memory, and then the DeskHop will reboot back into normal operation.

Note that the configuration data is a binary data structure; it is not
human-readable and there are no tools available to convert it into a
human-readable format.

### Restore

To restore the configurartion on a DeskHop device, switch one of the DeskHop
boards into 'transfer' mode using the key sequence documented
above. Within 30 seconds:

(command run on host connected to the board in 'transfer' mode)
```shell
$ dfu-util -a config -d 2E8A:XXXX -D config.bin
```

This command will download the configuration into the DeskHop's flash
memory, and then the DeskHop will reboot back into normal operation.

0 comments on commit 817d0d3

Please sign in to comment.