mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
19010: bootloaders/riotboot: add tinyUSB DFU support r=benpicco a=gschorcht ### Contribution description This PR provides - the tinyUSB DFU and DFU Runtime support and - the `riotboot_tinyusb_dfu` bootloader that uses the tinyUSB DFU mode to flash new application images. ~This PR includes PR #18983 for now to be compilable.~ ### Testing procedure 1. Use any board that supports the `riotboot´ and `tinyusb_device` features and flash the bootloader first, for example ``` BOARD=nucleo-f767zi make -C bootloaders/riotboot_tinyusb_dfu flash ``` and check that the `riotboot_tinyusb_dfu` bootloader is in DFU mode: ``` dfu-util --list ``` 3. Flash a first application using the following command: ``` FEATURES_REQUIRED=riotboot USEMODULE=tinyusb_dfu BOARD=nucleo-f767zi \ make -C tests/saul PROGRAMMER=dfu-util riotboot/flash-slot0 ``` and check that the application starts and is seen as upgradable: ``` dfu-util --list ``` 4. Restart the node in bootloader DFU mode by: ``` dfu-util -e ``` Flash a second application, for example ``` FEATURES_REQUIRED=riotboot USEMODULE=tinyusb_dfu BOARD=nucleo-f767zi \ make -C tests/shell PROGRAMMER=dfu-util riotboot/flash-slot1 ``` and check that the second application starts and is seen as upgradable: ``` dfu-util --list ``` ### Issues/PRs references ~Depends on PR #18983~ 19149: SECURITY: Describe that declassification is an option r=benpicco a=chrysn ### Contribution description Our security policy does not contain provisions for the case when what is reported is not what we consider an actual security issue. As it is described now, everything reported through security@ would go through the full treatment, including a point release. I'm not sure it belongs into the text itself (as it's more about how security reporters interact with the project than internals), but declassification should IMO be backed at least by 3 maintainers, and no strong NACK. ### Issues/PRs references #19141 followed that procedure after some chat on it on the maintainers channel. (In the discussion, I proposed declassification, with 2.5 people supporting it and one "I was about to, but can we be sure nobody is using it?" voice). Co-authored-by: Gunar Schorcht <gunar@schorcht.net> Co-authored-by: chrysn <chrysn@fsfe.org>
This commit is contained in:
commit
9ff9704fe5
@ -84,6 +84,10 @@ ifneq (,$(filter tinydtls_sock_dtls, $(USEMODULE)))
|
||||
USEPKG += tinydtls
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinyusb_%, $(USEMODULE)))
|
||||
USEPKG += tinyusb
|
||||
endif
|
||||
|
||||
# always select gpio (until explicit dependencies are sorted out)
|
||||
FEATURES_OPTIONAL += periph_gpio
|
||||
|
||||
|
@ -20,6 +20,14 @@ bottom of this file.
|
||||
|
||||
[security-gpg]: https://riot-os.org/assets/keys/security.asc
|
||||
|
||||
### Classification of a vulnerability
|
||||
|
||||
Unless the reporter explicitly requests not to do so,
|
||||
the RIOT security maintainers may declassify an issue
|
||||
if the issue is not deemed critical --
|
||||
for example when it requires an unlikely combination of circumstances and/or configuration options,
|
||||
or when it can only be exploited by a user who gains no additional privileges.
|
||||
|
||||
## Notification of a Vulnerability
|
||||
|
||||
After a fix is provided the security issue will be privately disclosed to the
|
||||
|
19
bootloaders/riotboot_tinyusb_dfu/Makefile
Normal file
19
bootloaders/riotboot_tinyusb_dfu/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
# Default RIOT bootloader
|
||||
APPLICATION = riotboot_tinyusb_dfu
|
||||
|
||||
# Add RIOTBOOT tinyUSB DFU integration
|
||||
USEMODULE += riotboot_tinyusb_dfu
|
||||
|
||||
# Use xtimer for scheduled reboot
|
||||
USEMODULE += ztimer
|
||||
USEMODULE += ztimer_init
|
||||
|
||||
# USB device vendor and product ID
|
||||
# pid.codes test VID/PID, not globally unique
|
||||
|
||||
# The VID/PID pair allocated for the RIOT bootloader
|
||||
# as allocated on https://pid.codes/1209/7D02/
|
||||
USB_VID ?= 1209
|
||||
USB_PID ?= 7D02
|
||||
|
||||
include ../riotboot_common.mk
|
86
bootloaders/riotboot_tinyusb_dfu/doc.txt
Normal file
86
bootloaders/riotboot_tinyusb_dfu/doc.txt
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
@defgroup pkg_tinyusb_dfu riotboot tinyUSB DFU
|
||||
@ingroup pkg_tinyusb
|
||||
@ingroup bootloaders
|
||||
|
||||
# Overview
|
||||
|
||||
`riotboot_tinyusb_dfu` is a variation of @ref bootloader_riotboot that adds
|
||||
USB device firmware upgrade (DFU) based on the tinyUSB device stack package.
|
||||
It uses a board's USB interface to allow firmware upgrades from inside the
|
||||
bootloader.
|
||||
|
||||
At startup, the DFU mode is entered when either
|
||||
|
||||
- none of the slots contains a valid firmware image, or
|
||||
- the first button was pressed when the board started (configurable at board
|
||||
level using @ref BTN_BOOTLOADER_PIN), or
|
||||
- the last running firmware asked the bootloader to go to DFU mode by using a
|
||||
magic number (see @ref RIOTBOOT_MAGIC_ADDR).
|
||||
|
||||
# Prerequisites
|
||||
|
||||
- The board must have functional USB support and has to support the
|
||||
`tinyusb_device` feature.
|
||||
- The board must have functional `riotboot` support, see
|
||||
@ref bootloader_riotboot.
|
||||
|
||||
# Flashing riotboot_tinyusb_dfu
|
||||
|
||||
The `riotboot_tinyusb_dfu` bootloader can be flashed using a regular programmer
|
||||
like any other application:
|
||||
|
||||
```
|
||||
$ make -C bootloaders/riotboot_tinyusb_dfu BOARD=... all flash
|
||||
```
|
||||
|
||||
Depending on your setup, you may need to select the right `PROGRAMMER`
|
||||
(and its details) in addition to your board.
|
||||
|
||||
# DFU mode
|
||||
|
||||
A device in riotboot DFU mode can be recognized in the USB device list by
|
||||
its VID/PID pair 1209:7d02:
|
||||
|
||||
```
|
||||
$ lsusb
|
||||
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
|
||||
Bus 001 Device 005: ID 138a:003f [...]
|
||||
Bus 001 Device 004: ID 8087:0a2b [...]
|
||||
Bus 001 Device 045: ID 1209:7d02 Generic USB device
|
||||
Bus 001 Device 001: ID 1d6b:0002 [...]
|
||||
```
|
||||
|
||||
When running in DFU mode, the bootloader allows writing to either of the
|
||||
two firmware slots.
|
||||
|
||||
When the device is attached and in DFU mode (or the current firmware uses the
|
||||
`tinyusb_dfu` module), new firmware can be flashed to slot 0 using:
|
||||
|
||||
```
|
||||
$ FEATURES_REQUIRED+=riotboot USEMODULE+=tinyusb_dfu make -C examples/saul BOARD=particle-xenon \
|
||||
PROGRAMMER=dfu-util USB_VID=1209 USB_PID=7d02 all riotboot/flash-slot0
|
||||
```
|
||||
|
||||
Instead of setting `USB_VID` and `USB_PID`, the variable `DFU_USB_ID` could also
|
||||
be used to specify the DFU device to be used.
|
||||
|
||||
```
|
||||
$ FEATURES_REQUIRED+=riotboot USEMODULE+=tinyusb_dfu make -C examples/saul BOARD=particle-xenon \
|
||||
PROGRAMMER=dfu-util DFU_USB_ID=1209:7d02 all riotboot/flash-slot0
|
||||
```
|
||||
|
||||
Note that when building and flashing a different slot (e.g. `flash-slot1`),
|
||||
not only is the image built for that slot, but also `dfu-util` gets passed
|
||||
`--alt 1` (via the `DFU_ALT` build variable) to store it in the right place.
|
||||
|
||||
# Entering DFU mode
|
||||
|
||||
When RIOT applications are built with `USEMODULE=tinyusb_dfu`,
|
||||
they implement what is called "runtime mode" in DFU.
|
||||
|
||||
In runtime mode, it is visible to the `dfu-util` that they are upgradable.
|
||||
On firmware upgrades, the build system can send a command via USB to enter
|
||||
DFU mode. This can also be done manually using `dfu-util -e`.
|
||||
|
||||
*/
|
86
bootloaders/riotboot_tinyusb_dfu/main.c
Normal file
86
bootloaders/riotboot_tinyusb_dfu/main.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* Inria
|
||||
* 2020 Mesotic SAS
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup bootloaders
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief RIOT-based bootloader with USB-DFU support
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Francisco Acosta <francisco.acosta@inria.fr>
|
||||
* @author Dylan Laduranty <dylan.laduranty@mesotic.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "panic.h"
|
||||
#include "riotboot/slot.h"
|
||||
#include "riotboot/usb_dfu.h"
|
||||
#include "ztimer.h"
|
||||
|
||||
#include "riotboot/bootloader_selection.h"
|
||||
|
||||
#ifdef BTN_BOOTLOADER_PIN
|
||||
#include "periph/gpio.h"
|
||||
#endif
|
||||
|
||||
static bool _bootloader_alternative_mode(void)
|
||||
{
|
||||
#ifdef BTN_BOOTLOADER_PIN
|
||||
gpio_init(BTN_BOOTLOADER_PIN, BTN_BOOTLOADER_MODE);
|
||||
return (bool)gpio_read(BTN_BOOTLOADER_PIN) != BTN_BOOTLOADER_INVERTED;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernel_init(void)
|
||||
{
|
||||
uint32_t version = 0;
|
||||
int slot = -1;
|
||||
|
||||
for (unsigned i = 0; i < riotboot_slot_numof; i++) {
|
||||
const riotboot_hdr_t *riot_hdr = riotboot_slot_get_hdr(i);
|
||||
if (riotboot_slot_validate(i)) {
|
||||
/* skip slot if metadata broken */
|
||||
continue;
|
||||
}
|
||||
if (riot_hdr->start_addr != riotboot_slot_get_image_startaddr(i)) {
|
||||
continue;
|
||||
}
|
||||
if (slot == -1 || riot_hdr->version > version) {
|
||||
version = riot_hdr->version;
|
||||
slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init ztimer before starting DFU mode */
|
||||
ztimer_init();
|
||||
|
||||
/* Flash the unused slot if magic word is set */
|
||||
riotboot_usb_dfu_init(0);
|
||||
|
||||
if (slot != -1 && !_bootloader_alternative_mode()) {
|
||||
riotboot_slot_jump(slot);
|
||||
}
|
||||
|
||||
/* Nothing to boot, stay in DFU mode to flash a slot */
|
||||
riotboot_usb_dfu_init(1);
|
||||
}
|
||||
|
||||
NORETURN void core_panic(core_panic_t crash_code, const char *message)
|
||||
{
|
||||
(void)crash_code;
|
||||
(void)message;
|
||||
while (1) {}
|
||||
}
|
@ -70,8 +70,8 @@ else
|
||||
endif
|
||||
|
||||
# Configure riotboot bootloader and slot lengths
|
||||
# 4KB are currently enough, set it to 16KB if USB-DFU is used
|
||||
ifneq (,$(filter usbus_dfu,$(USEMODULE)))
|
||||
# 4KB are currently enough, set it to 16KB if USB-DFU or tinyUSB DFU is used
|
||||
ifneq (,$(filter usbus_dfu tinyusb_dfu,$(USEMODULE)))
|
||||
RIOTBOOT_LEN ?= 0x4000
|
||||
else
|
||||
RIOTBOOT_LEN ?= 0x1000
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Slot size is determined by "((total_flash_size - RIOTBOOT_LEN) / 2)".
|
||||
# If RIOTBOOT_LEN uses an uneven number of flashpages, the remainder of the
|
||||
# flash cannot be divided by two slots while staying FLASHPAGE_SIZE aligned.
|
||||
ifneq (,$(filter usbus_dfu,$(USEMODULE)))
|
||||
ifneq (,$(filter usbus_dfu tinyusb_dfu,$(USEMODULE)))
|
||||
RIOTBOOT_LEN ?= 0x4000
|
||||
else
|
||||
RIOTBOOT_LEN ?= 0x2000
|
||||
|
@ -1,6 +1,7 @@
|
||||
ifneq (,$(filter usbus_dfu,$(USEMODULE)))
|
||||
ifeq (,$(filter riotboot_usb_dfu,$(USEMODULE)))
|
||||
# If module usbus_dfu is used but not module riotboot_usb_dfu, the
|
||||
ifneq (,$(filter usbus_dfu tinyusb_dfu,$(USEMODULE)))
|
||||
ifeq (,$(filter riotboot_usb_dfu riotboot_tinyusb_dfu,$(USEMODULE)))
|
||||
# If module usbus_dfu or module tinyusb_dfu is used but neither
|
||||
# module riotboot_usb_dfu nor module riotboot_tinyusb_dfu, the
|
||||
# application uses DFU Runtime and dfu-util as programmer to flash the
|
||||
# application with the bootloader riotboot_dfu which uses the VID/PID pair
|
||||
# allocated for the RIOT bootloader https://pid.codes/1209/7D02/
|
||||
|
@ -17,6 +17,7 @@ config HAS_TINYUSB_HOST
|
||||
|
||||
menuconfig PACKAGE_TINYUSB
|
||||
bool "TinyUSB stack package"
|
||||
depends on TEST_KCONFIG
|
||||
depends on HAS_ARCH_32BIT
|
||||
depends on HAS_TINYUSB_DEVICE || HAS_TINYUSB_HOST
|
||||
select MODULE_FMT
|
||||
@ -90,8 +91,8 @@ if PACKAGE_TINYUSB
|
||||
|
||||
config MODULE_AUTO_INIT_TINYUSB
|
||||
bool "Auto-initialize the tinyUSB package"
|
||||
default y
|
||||
depends on MODULE_AUTO_INIT
|
||||
default y
|
||||
help
|
||||
The tinyUSB stack including the used peripherals are initialized
|
||||
automatically at startup. Additionally, the auto-initialization
|
||||
@ -160,15 +161,8 @@ menu "Device Classes"
|
||||
depends on MODULE_TINYUSB_DEVICE
|
||||
|
||||
rsource "Kconfig.cdc"
|
||||
|
||||
config MODULE_TINYUSB_CLASS_DFU
|
||||
bool "Device Firmware Update (DFU) Runtime"
|
||||
depends on MODULE_TINYUSB_DEVICE
|
||||
|
||||
config MODULE_TINYUSB_CLASS_DFU_RUNTIME
|
||||
bool "Device Firmware Update (DFU)"
|
||||
depends on MODULE_TINYUSB_DEVICE
|
||||
|
||||
rsource "dfu/Kconfig.dfu"
|
||||
rsource "dfu/Kconfig.dfu_rt"
|
||||
rsource "Kconfig.hid"
|
||||
rsource "Kconfig.msc"
|
||||
|
||||
@ -224,6 +218,29 @@ config TUSBD_USE_CUSTOM_DESC
|
||||
interface. In all other cases, custom descriptors must be implemented
|
||||
and handled.
|
||||
|
||||
config MODULE_TINYUSB_DFU
|
||||
bool "tinyUSB DFU driver module"
|
||||
select MODULE_TINYUSB_CLASS_DFU if MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
select MODULE_TINYUSB_CLASS_DFU_RUNTIME if !MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
help
|
||||
Enable tinyUSB Device Firmware Upgrade driver implementation used
|
||||
either in DFU mode by the bootloader or in DFU runtime mode by the
|
||||
application. It is enabled by default, if the tinyUSB DFU variant
|
||||
of the riotboot bootloader is used.
|
||||
|
||||
config MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
# TODO move to sys/riotboot/Kconfig once it is modelled
|
||||
bool "tinyUSB DFU variant of riotboot bootloader"
|
||||
depends on HAS_NO_IDLE_THREAD
|
||||
depends on HAS_PERIPH_PM
|
||||
select MODULE_RIOTBOOT_FLASHWRITE
|
||||
select MODULE_TINYUSB_DFU
|
||||
select MODULE_TINYUSB_CLASS_DFU
|
||||
select MODULE_ZTIMER_SEC
|
||||
help
|
||||
Enable this option to use the tinyUSB DFU variant of the riotboot
|
||||
bootloader.
|
||||
|
||||
endif # MODULE_TINYUSB_DEVICE
|
||||
endif # PACKAGE_TINYUSB
|
||||
|
||||
|
@ -20,6 +20,9 @@ stdio_tinyusb_cdc_acm:
|
||||
tinyusb_contrib:
|
||||
$(QQ)"$(MAKE)" -C $(RIOTPKG)/$(PKG_NAME)/contrib
|
||||
|
||||
tinyusb_dfu:
|
||||
$(QQ)"$(MAKE)" -C $(RIOTPKG)/$(PKG_NAME)/dfu
|
||||
|
||||
tinyusb_hw:
|
||||
$(QQ)"$(MAKE)" -C $(RIOTPKG)/$(PKG_NAME)/hw
|
||||
|
||||
|
@ -8,12 +8,28 @@ USEMODULE += tinyusb_hw
|
||||
|
||||
DEFAULT_MODULE += auto_init_tinyusb
|
||||
|
||||
ifneq (,$(filter riotboot_tinyusb_dfu, $(USEMODULE)))
|
||||
FEATURES_REQUIRED += no_idle_thread
|
||||
FEATURES_REQUIRED += periph_pm
|
||||
USEMODULE += riotboot_flashwrite
|
||||
USEMODULE += tinyusb_dfu
|
||||
USEMODULE += ztimer_sec
|
||||
endif
|
||||
|
||||
ifneq (,$(filter stdio_tinyusb_cdc_acm, $(USEMODULE)))
|
||||
USEMODULE += stdio_available
|
||||
USEMODULE += tinyusb_class_cdc
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinyusb_dfu,$(USEMODULE)))
|
||||
ifneq (,$(filter riotboot_tinyusb_dfu,$(USEMODULE)))
|
||||
USEMODULE += tinyusb_class_dfu
|
||||
else
|
||||
USEMODULE += tinyusb_class_dfu_runtime
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (,$(filter tinyusb_class_%,$(USEMODULE)))
|
||||
$(error At least one tinyusb_class_* module has to be enabled)
|
||||
endif
|
||||
@ -30,31 +46,31 @@ endif
|
||||
|
||||
# Following device classes work only with tinyUSB device stack
|
||||
ifneq (,$(filter tinyusb_class_audio,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_bth,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_dfu,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_dfu_runtime,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_midi,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_net_ecm_rndis,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_net_ncm,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_usbtmc,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
ifneq (,$(filter tinyusb_class_video,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += tinyusb_device
|
||||
USEMODULE += tinyusb_device
|
||||
endif
|
||||
|
||||
# tinyUSB hardware driver selection
|
||||
|
@ -33,3 +33,7 @@ endif
|
||||
ifneq (,$(filter tinyusb_class_net_ecm_rndis,$(USEMODULE)))
|
||||
INCLUDES += -I$(PKGDIRBASE)/tinyusb/lib/networking
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinyusb_dfu,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/dfu/include
|
||||
endif
|
||||
|
@ -41,6 +41,12 @@ enum {
|
||||
TUSBD_ITF_CDC_1, /**< CDC1 Notification interface */
|
||||
TUSBD_ITF_CDC_1_DATA, /**< CDC1 Data interface */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_NUMOF
|
||||
TUSBD_ITF_DFU, /**< DFU interface */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
TUSBD_ITF_DFU_RT, /**< DFU Runtime interface */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
TUSBD_ITF_HID_0, /**< HID0 interface */
|
||||
#endif
|
||||
@ -101,6 +107,13 @@ enum {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
TUSBD_STR_IDX_CDC_1,
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_NUMOF
|
||||
TUSBD_STR_IDX_DFU_SLOT_0,
|
||||
TUSBD_STR_IDX_DFU_SLOT_1,
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
TUSBD_STR_IDX_DFU_RT,
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
TUSBD_STR_IDX_HID_0,
|
||||
#endif
|
||||
@ -117,9 +130,14 @@ enum {
|
||||
};
|
||||
#endif /* !defined(HAVE_TUSBD_STR_IDX_TYPE) */
|
||||
|
||||
/* only two slots are supported */
|
||||
#define CONFIG_TUSBD_DFU_ALT_NUMOF 2
|
||||
|
||||
#if !defined(TUSBD_DESC_TOTAL_LEN)
|
||||
#define TUSBD_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \
|
||||
(CONFIG_TUSBD_CDC_NUMOF * TUD_CDC_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_DFU_NUMOF * TUD_DFU_DESC_LEN(CONFIG_TUSBD_DFU_ALT_NUMOF)) + \
|
||||
(CONFIG_TUSBD_DFU_RT_NUMOF * TUD_DFU_RT_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_HID_NUMOF * TUD_HID_INOUT_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_MSC_NUMOF * TUD_MSC_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN))
|
||||
@ -127,6 +145,8 @@ enum {
|
||||
|
||||
#define TUSBD_DESC_ALT_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \
|
||||
(CONFIG_TUSBD_CDC_NUMOF * TUD_CDC_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_DFU_NUMOF * TUD_DFU_DESC_LEN(CONFIG_TUSBD_DFU_ALT_NUMOF)) + \
|
||||
(CONFIG_TUSBD_DFU_RT_NUMOF * TUD_DFU_RT_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_HID_NUMOF * TUD_HID_INOUT_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_MSC_NUMOF * TUD_MSC_DESC_LEN) + \
|
||||
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN))
|
||||
|
@ -75,7 +75,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_DFU_RT
|
||||
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_DFU_RUNTIME
|
||||
#define CONFIG_TUSBD_DFU_RT_NUMOF 1
|
||||
#else
|
||||
#define CONFIG_TUSBD_DFU_RT_NUMOF 0
|
||||
@ -186,10 +186,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_CDC_NOTIF_EP_SIZE
|
||||
#define CONFIG_TUSBD_CDC_NOTIF_EP_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_EP0_SIZE
|
||||
#define CONFIG_TUSBD_EP0_SIZE 64
|
||||
#endif
|
||||
@ -202,6 +198,10 @@
|
||||
#define CONFIG_TUSBD_HS_EP_SIZE 512
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_CDC_NOTIF_EP_SIZE
|
||||
#define CONFIG_TUSBD_CDC_NOTIF_EP_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_CDC_FS_EP_SIZE
|
||||
#define CONFIG_TUSBD_CDC_FS_EP_SIZE CONFIG_TUSBD_FS_EP_SIZE
|
||||
#endif
|
||||
@ -210,6 +210,48 @@
|
||||
#define CONFIG_TUSBD_CDC_HS_EP_SIZE CONFIG_TUSBD_HS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_ATTR
|
||||
#define CONFIG_TUSBD_DFU_ATTR (DFU_ATTR_CAN_DOWNLOAD | \
|
||||
DFU_ATTR_WILL_DETACH | \
|
||||
DFU_ATTR_MANIFESTATION_TOLERANT)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_DETACH_TIMEOUT
|
||||
#define CONFIG_TUSBD_DFU_DETACH_TIMEOUT 1000
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_POLL_TIMEOUT
|
||||
#define CONFIG_TUSBD_DFU_POLL_TIMEOUT 1
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RESET_DELAY
|
||||
#define CONFIG_TUSBD_DFU_RESET_DELAY 2
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_FS_XFER_SIZE
|
||||
#define CONFIG_TUSBD_DFU_FS_XFER_SIZE CONFIG_TUSBD_FS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_HS_XFER_SIZE
|
||||
#define CONFIG_TUSBD_DFU_HS_XFER_SIZE CONFIG_TUSBD_HS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_HID_EP_SIZE
|
||||
#define CONFIG_TUSBD_HID_EP_SIZE CONFIG_TUSBD_FS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RT_DETACH_TIMEOUT
|
||||
#define CONFIG_TUSBD_DFU_RT_DETACH_TIMEOUT 1000
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RT_FS_XFER_SIZE
|
||||
#define CONFIG_TUSBD_DFU_RT_FS_XFER_SIZE CONFIG_TUSBD_FS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RT_HS_XFER_SIZE
|
||||
#define CONFIG_TUSBD_DFU_RT_HS_XFER_SIZE CONFIG_TUSBD_HS_EP_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_HID_EP_SIZE
|
||||
#define CONFIG_TUSBD_HID_EP_SIZE CONFIG_TUSBD_FS_EP_SIZE
|
||||
#endif
|
||||
@ -263,7 +305,9 @@
|
||||
#define CFG_TUSB_OS OPT_OS_CUSTOM
|
||||
|
||||
/** Debug log level */
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DMA memory section and alignment
|
||||
@ -337,8 +381,8 @@
|
||||
* @name Typical required DFU device class configurations
|
||||
* @{
|
||||
*/
|
||||
#define CFG_TUD_DFU_XFER_BUFSIZE (TUD_OPT_HIGH_SPEED ? CONFIG_TUSBD_HS_EP_SIZE \
|
||||
: CONFIG_TUSBD_FS_EP_SIZE)
|
||||
#define CFG_TUD_DFU_XFER_BUFSIZE (TUD_OPT_HIGH_SPEED ? CONFIG_TUSBD_DFU_HS_XFER_SIZE \
|
||||
: CONFIG_TUSBD_DFU_FS_XFER_SIZE)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -75,7 +75,11 @@ int tinyusb_setup(void)
|
||||
if ((res = thread_create(_tinyusb_thread_stack,
|
||||
sizeof(_tinyusb_thread_stack),
|
||||
TINYUSB_PRIORITY,
|
||||
#if MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
THREAD_CREATE_STACKTEST,
|
||||
#else
|
||||
THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
|
||||
#endif
|
||||
_tinyusb_thread_impl, NULL, "tinyusb")) < 0) {
|
||||
LOG_ERROR("tinyUSB thread couldn't be created, reason %d\n", res);
|
||||
return res;
|
||||
|
@ -30,6 +30,10 @@
|
||||
#include "tusb.h"
|
||||
#include "usb.h"
|
||||
|
||||
#ifdef MODULE_TINYUSB_DFU
|
||||
#include "riotboot/usb_dfu.h"
|
||||
#endif
|
||||
|
||||
#include "tinyusb_descriptors.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
@ -40,16 +44,17 @@
|
||||
|
||||
#if (MODULE_TINYUSB_CLASS_AUDIO || \
|
||||
MODULE_TINYUSB_CLASS_BTH || \
|
||||
MODULE_TINYUSB_CLASS_DFU || \
|
||||
MODULE_TINYUSB_CLASS_DFU_RUNTIME || \
|
||||
MODULE_TINYUSB_CLASS_MIDI || \
|
||||
MODULE_TINYUSB_CLASS_NET_ECM_RNDIS || \
|
||||
MODULE_TINYUSB_CLASS_NET_NCM || \
|
||||
MODULE_TINYUSB_CLASS_USBTMC || \
|
||||
MODULE_TINYUSB_CLASS_VIDEO || \
|
||||
(CONFIG_TUSBD_CDC_NUMOF > 2) || \
|
||||
(CONFIG_TUSBD_DFU_NUMOF > 1) || \
|
||||
(CONFIG_TUSBD_DFU_RT_NUMOF > 1) || \
|
||||
(CONFIG_TUSBD_HID_NUMOF > 2) || \
|
||||
(CONFIG_TUSBD_MSC_NUMOF > 1))
|
||||
(CONFIG_TUSBD_MSC_NUMOF > 1) || \
|
||||
(CONFIG_TUSBD_VENDOR_NUMOF > 1))
|
||||
#error Using generic descriptors is not possible for the selected combination \
|
||||
of device class interfaces. Custom descriptors have to be implemented.
|
||||
#endif
|
||||
@ -226,6 +231,24 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
|
||||
speed ? CONFIG_TUSBD_CDC_HS_EP_SIZE \
|
||||
: CONFIG_TUSBD_CDC_FS_EP_SIZE)
|
||||
|
||||
#define _TUD_DFU_DESC(speed) \
|
||||
/* Interface number, alternate count, starting string index, attributes,
|
||||
* detach timeout, transfer size */ \
|
||||
TUD_DFU_DESCRIPTOR(TUSBD_ITF_DFU, CONFIG_TUSBD_DFU_ALT_NUMOF, \
|
||||
TUSBD_STR_IDX_DFU_SLOT_0, CONFIG_TUSBD_DFU_ATTR, \
|
||||
CONFIG_TUSBD_DFU_DETACH_TIMEOUT, \
|
||||
speed ? CONFIG_TUSBD_DFU_HS_XFER_SIZE \
|
||||
: CONFIG_TUSBD_DFU_FS_XFER_SIZE)
|
||||
|
||||
#define _TUD_DFU_RT_DESC(speed) \
|
||||
/* Interface number, alternate count, starting string index, attributes,
|
||||
* detach timeout, transfer size */ \
|
||||
TUD_DFU_RT_DESCRIPTOR(TUSBD_ITF_DFU_RT, \
|
||||
TUSBD_STR_IDX_DFU_RT, DFU_ATTR_WILL_DETACH, \
|
||||
CONFIG_TUSBD_DFU_RT_DETACH_TIMEOUT, \
|
||||
speed ? CONFIG_TUSBD_DFU_RT_HS_XFER_SIZE \
|
||||
: CONFIG_TUSBD_DFU_RT_FS_XFER_SIZE)
|
||||
|
||||
#define _TUD_HID_INOUT_DESC(speed, n) \
|
||||
/* Interface number, string index, protocol, report descriptor len,
|
||||
* EP Out & EP In address, EP size, polling interval */ \
|
||||
@ -260,6 +283,12 @@ uint8_t const tusb_desc_fs_config[] = {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
_TUD_CDC_DESC(_tusb_speed_fs, 1),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_NUMOF
|
||||
_TUD_DFU_DESC(_tusb_speed_fs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
_TUD_DFU_RT_DESC(_tusb_speed_fs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
_TUD_HID_INOUT_DESC(_tusb_speed_fs, 0),
|
||||
#endif
|
||||
@ -284,6 +313,12 @@ uint8_t const tusb_desc_fs_config_alt[] = {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
_TUD_CDC_DESC(_tusb_speed_fs, 1),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_NUMOF
|
||||
_TUD_DFU_DESC(_tusb_speed_fs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
_TUD_DFU_RT_DESC(_tusb_speed_fs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
_TUD_HID_INOUT_DESC(_tusb_speed_fs, 0),
|
||||
#endif
|
||||
@ -313,6 +348,12 @@ uint8_t const tusb_desc_hs_config[] = {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
_TUD_CDC_DESC(_tusb_speed_hs, 1),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU
|
||||
_TUD_DFU_DESC(_tusb_speed_hs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
_TUD_DFU_RT_DESC(_tusb_speed_hs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
_TUD_HID_INOUT_DESC(_tusb_speed_hs, 0),
|
||||
#endif
|
||||
@ -337,6 +378,12 @@ uint8_t const tusb_desc_hs_config_alt[] = {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
_TUD_CDC_DESC(_tusb_speed_hs, 1),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU
|
||||
_TUD_DFU_DESC(_tusb_speed_hs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
_TUD_DFU_RT_DESC(_tusb_speed_hs),
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
_TUD_HID_INOUT_DESC(_tusb_speed_hs, 0),
|
||||
#endif
|
||||
@ -488,6 +535,18 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
#define CONFIG_TUSBD_CDC_1_STRING "TinyUSB CDC1"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_0_STRING
|
||||
#define CONFIG_TUSBD_DFU_0_STRING USB_DFU_MODE_SLOT0_NAME
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_1_STRING
|
||||
#define CONFIG_TUSBD_DFU_1_STRING USB_DFU_MODE_SLOT1_NAME
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_DFU_RT_STRING
|
||||
#define CONFIG_TUSBD_DFU_RT_STRING USB_APP_MODE_SLOT_NAME
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TUSBD_HID_0_STRING
|
||||
#define CONFIG_TUSBD_HID_0_STRING "TinyUSB HID0 (Generic In/Out)"
|
||||
#endif
|
||||
@ -524,6 +583,13 @@ char const* tusb_string_desc_array[] = {
|
||||
#if CONFIG_TUSBD_CDC_NUMOF > 1
|
||||
CONFIG_TUSBD_CDC_1_STRING, /* CDC Interface 1 */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_NUMOF
|
||||
CONFIG_TUSBD_DFU_0_STRING, /* DFU Firmware Slot 0 */
|
||||
CONFIG_TUSBD_DFU_1_STRING, /* DFU Firmware Slot 1 */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_DFU_RT_NUMOF
|
||||
CONFIG_TUSBD_DFU_RT_STRING, /* APP mode */
|
||||
#endif
|
||||
#if CONFIG_TUSBD_HID_NUMOF > 0
|
||||
CONFIG_TUSBD_HID_0_STRING, /* HID Interface 0 */
|
||||
#endif
|
||||
|
50
pkg/tinyusb/dfu/Kconfig.dfu
Normal file
50
pkg/tinyusb/dfu/Kconfig.dfu
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2022 Gunar Schorcht
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
menuconfig MODULE_TINYUSB_CLASS_DFU
|
||||
bool "Device Firmware Update (DFU)"
|
||||
depends on MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_DFU && MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
|
||||
if MODULE_TINYUSB_CLASS_DFU
|
||||
|
||||
config TUSBD_DFU_NUMOF
|
||||
int
|
||||
default 1
|
||||
|
||||
config TUSBD_DFU_FS_XFER_SIZE
|
||||
int "DFU Full-Speed transfer size [byte]"
|
||||
default 64
|
||||
|
||||
config TUSBD_DFU_HS_XFER_SIZE
|
||||
int "DFU High-Speed transfer size [byte]"
|
||||
default 512
|
||||
|
||||
config TUSBD_DFU_ALT_NUMOF
|
||||
int
|
||||
default 2
|
||||
help
|
||||
Number of alternative DFU firmware slots.
|
||||
|
||||
config TUSBD_DFU_DETACH_TIMEOUT
|
||||
int "DFU detach timeout [ms]"
|
||||
default 1000
|
||||
|
||||
config TUSBD_DFU_POLL_TIMEOUT
|
||||
int "DFU poll timeout [ms]"
|
||||
default 1
|
||||
help
|
||||
DFU Poll Timeout is the time before the host requests the status
|
||||
from the device during a firmware download or manifestation operation.
|
||||
|
||||
config TUSBD_DFU_RESET_DELAY
|
||||
int "DFU reset delay [s]"
|
||||
default 2
|
||||
help
|
||||
DFU reset delay is the time before the device is restarted after
|
||||
a firmware download.
|
||||
|
||||
endif # MODULE_TINYUSB_CLASS_DFU
|
30
pkg/tinyusb/dfu/Kconfig.dfu_rt
Normal file
30
pkg/tinyusb/dfu/Kconfig.dfu_rt
Normal file
@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2022 Gunar Schorcht
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
menuconfig MODULE_TINYUSB_CLASS_DFU_RUNTIME
|
||||
bool "Device Firmware Update Runtime (DFU Runtime)"
|
||||
depends on MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_DFU && !MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
|
||||
if MODULE_TINYUSB_CLASS_DFU_RUNTIME
|
||||
|
||||
config TUSBD_DFU_RT_NUMOF
|
||||
int
|
||||
default 1
|
||||
|
||||
config TUSBD_DFU_RT_FS_XFER_SIZE
|
||||
int "DFU Full-Speed transfer size [byte]"
|
||||
default 64
|
||||
|
||||
config TUSBD_DFU_RT_HS_XFER_SIZE
|
||||
int "DFU High-Speed transfer size [byte]"
|
||||
default 512
|
||||
|
||||
config TUSBD_DFU_RT_DETACH_TIMEOUT
|
||||
int "DFU detach timeout [ms]"
|
||||
default 1000
|
||||
|
||||
endif # MODULE_TINYUSB_CLASS_DFU_RUNTIME
|
3
pkg/tinyusb/dfu/Makefile
Normal file
3
pkg/tinyusb/dfu/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = tinyusb_dfu
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
48
pkg/tinyusb/dfu/include/tinyusb_dfu.h
Normal file
48
pkg/tinyusb/dfu/include/tinyusb_dfu.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_tinyusb_dfu
|
||||
* @{
|
||||
* @file
|
||||
* @brief TinyUSB specific DFU definitions
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
*/
|
||||
|
||||
#ifndef TINYUSB_DFU_H
|
||||
#define TINYUSB_DFU_H
|
||||
|
||||
#include "riotboot/flashwrite.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief tinyUSB DFU device interface context
|
||||
*/
|
||||
typedef struct tinyusb_dfu_device {
|
||||
bool skip_signature; /**< Skip RIOTBOOT signature status */
|
||||
uint8_t slot; /**< Download slot */
|
||||
#ifdef MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
riotboot_flashwrite_t writer; /**< DFU firmware update state structure */
|
||||
#endif
|
||||
} tinyusb_dfu_device_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the tinyUSB DFU device interface context
|
||||
*/
|
||||
void tinyusb_dfu_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TINYUSB_DFU_H */
|
||||
/** @} */
|
153
pkg/tinyusb/dfu/tinyusb_dfu.c
Normal file
153
pkg/tinyusb/dfu/tinyusb_dfu.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_tinyusb_dfu
|
||||
* @{
|
||||
* @file TinyUSB DFU implementation
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "periph/pm.h"
|
||||
#include "riotboot/magic.h"
|
||||
#include "riotboot/slot.h"
|
||||
|
||||
#ifdef MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
#include "ztimer.h"
|
||||
#endif
|
||||
|
||||
#include "device/usbd.h"
|
||||
#include "class/dfu/dfu_device.h"
|
||||
|
||||
#include "tinyusb_dfu.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
static void _reboot(void *arg);
|
||||
static ztimer_t scheduled_reboot = { .callback=_reboot };
|
||||
#endif
|
||||
|
||||
/* there is only one instance of DFU devices */
|
||||
tinyusb_dfu_device_t _tusb_dfu_dev = { .skip_signature = true };
|
||||
|
||||
void tinyusb_dfu_init(void)
|
||||
{
|
||||
_tusb_dfu_dev.skip_signature = true;
|
||||
_tusb_dfu_dev.slot = 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE_RIOTBOOT_TINYUSB_DFU
|
||||
|
||||
uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state)
|
||||
{
|
||||
(void)alt;
|
||||
(void)state;
|
||||
|
||||
/* Invoked before tud_dfu_download_cb() or tud_dfu_manifest_cb() is called
|
||||
* to determine the poll timeout for download and manifest operation */
|
||||
return CONFIG_TUSBD_DFU_POLL_TIMEOUT;
|
||||
}
|
||||
|
||||
void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length)
|
||||
{
|
||||
/* Invoked when a DFU_DNLOAD (wLength > 0) followed by a DFU_GETSTATUS
|
||||
* (state = DFU_DNBUSY) requests was received. */
|
||||
|
||||
(void)block_num;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (_tusb_dfu_dev.skip_signature) {
|
||||
/* Avoid underflow condition */
|
||||
if (length < RIOTBOOT_FLASHWRITE_SKIPLEN) {
|
||||
return;
|
||||
}
|
||||
riotboot_flashwrite_init(&_tusb_dfu_dev.writer, alt);
|
||||
length -= RIOTBOOT_FLASHWRITE_SKIPLEN;
|
||||
DEBUG("[tinyusb_dfu] starting the download with %u bytes for slot %u "
|
||||
"with block %u\n", length, alt, block_num);
|
||||
_tusb_dfu_dev.skip_signature = false;
|
||||
_tusb_dfu_dev.slot = alt;
|
||||
ret = riotboot_flashwrite_putbytes(&_tusb_dfu_dev.writer,
|
||||
&data[RIOTBOOT_FLASHWRITE_SKIPLEN],
|
||||
length, true);
|
||||
}
|
||||
else {
|
||||
assert(alt == _tusb_dfu_dev.slot);
|
||||
|
||||
DEBUG("[tinyusb_dfu] continue the download with %u bytes for slot %u "
|
||||
"with block %u\n", length, alt, block_num);
|
||||
ret = riotboot_flashwrite_putbytes(&_tusb_dfu_dev.writer,
|
||||
data, length, true);
|
||||
}
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("[tinyusb_dfu] error on writing %d bytes for slot %u\n",
|
||||
length, alt);
|
||||
tud_dfu_finish_flashing(DFU_STATUS_ERR_WRITE);
|
||||
}
|
||||
else {
|
||||
tud_dfu_finish_flashing(DFU_STATUS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void tud_dfu_manifest_cb(uint8_t alt)
|
||||
{
|
||||
/* Invoked when the download process is complete and
|
||||
* DFU_DNLOAD (wLength = 0) followed by a DFU_GETSTATUS (state = Manifest)
|
||||
* was received. */
|
||||
|
||||
(void)alt;
|
||||
|
||||
assert(alt == _tusb_dfu_dev.slot);
|
||||
|
||||
DEBUG("[tinyusb_dfu] download for slot %u complete, "
|
||||
"enter manifestation phase\n", alt);
|
||||
|
||||
/* the host indicates that the download process is complete */
|
||||
riotboot_flashwrite_flush(&_tusb_dfu_dev.writer);
|
||||
riotboot_flashwrite_finish(&_tusb_dfu_dev.writer);
|
||||
|
||||
/* indicate that flashing is finished */
|
||||
tud_dfu_finish_flashing(DFU_STATUS_OK);
|
||||
|
||||
/* scheduled reboot after CONFIG_TUSBD_DFU_RESET_DELAY seconds to give
|
||||
* enough time to finish manifestation */
|
||||
ztimer_set(ZTIMER_SEC, &scheduled_reboot, CONFIG_TUSBD_DFU_RESET_DELAY);
|
||||
}
|
||||
|
||||
static void _reboot(void *arg)
|
||||
{
|
||||
DEBUG("[tinyusb_dfu] reboot\n");
|
||||
|
||||
(void)arg;
|
||||
pm_reboot();
|
||||
}
|
||||
#endif /* MODULE_RIOTBOOT_TINYUSB_DFU */
|
||||
|
||||
TU_ATTR_WEAK void tud_dfu_detach_cb(void)
|
||||
{
|
||||
/* the host sent a DFU_DETACH request */
|
||||
|
||||
DEBUG("[tinyusb_dfu] DFU_DETACH request received\n");
|
||||
|
||||
uint32_t *reset_addr = (uint32_t *)RIOTBOOT_MAGIC_ADDR;
|
||||
|
||||
*reset_addr = RIOTBOOT_MAGIC_NUMBER;
|
||||
pm_reboot();
|
||||
}
|
||||
|
||||
void tud_dfu_runtime_reboot_to_dfu_cb(void)
|
||||
{
|
||||
/* the host sent a DFU_DETACH request */
|
||||
tud_dfu_detach_cb();
|
||||
}
|
@ -92,6 +92,7 @@
|
||||
* callbacks for any combination of
|
||||
* - up to two interfaces of the class CDC ACM,
|
||||
* - up to two interfaces of the Generic In/Out HID class,
|
||||
* - up to one DFU interface
|
||||
* - up to one MSC device interface and,
|
||||
* - up to one interface of the Vendor device class.
|
||||
*
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "periph_conf.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/pm.h"
|
||||
#include "pm_layered.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "device/usbd.h"
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "periph_conf.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/pm.h"
|
||||
#include "pm_layered.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "device/usbd.h"
|
||||
|
@ -869,6 +869,10 @@ ifneq (,$(filter riotboot_usb_dfu, $(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_pm
|
||||
endif
|
||||
|
||||
ifneq (,$(filter riotboot_tinyusb_dfu, $(USEMODULE)))
|
||||
USEPKG += tinyusb
|
||||
endif
|
||||
|
||||
ifneq (,$(filter irq_handler,$(USEMODULE)))
|
||||
USEMODULE += event
|
||||
endif
|
||||
|
@ -163,7 +163,7 @@ ifneq (,$(filter prng,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/random/Makefile.include
|
||||
endif
|
||||
|
||||
ifneq (,$(filter usbus_dfu riotboot_reset,$(USEMODULE)))
|
||||
ifneq (,$(filter tinyusb_dfu usbus_dfu riotboot_reset,$(USEMODULE)))
|
||||
CFLAGS += -DCPU_RAM_BASE=$(RAM_START_ADDR)
|
||||
CFLAGS += -DCPU_RAM_SIZE=$(RAM_LEN)
|
||||
endif
|
||||
|
38
sys/riotboot/tinyusb_dfu.c
Normal file
38
sys/riotboot/tinyusb_dfu.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_riotboot_usb_dfu
|
||||
* @ingroup pkg_tinyusb_dfu
|
||||
* @{
|
||||
* @file tinyUSB Device Firmware Upgrade initialization for riotboot
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "riotboot/magic.h"
|
||||
|
||||
#include "tinyusb.h"
|
||||
#include "tinyusb_dfu.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
extern void tinyusb_dfu_init(void);
|
||||
|
||||
void riotboot_usb_dfu_init(unsigned forced)
|
||||
{
|
||||
uint32_t *reset_addr = (uint32_t *)RIOTBOOT_MAGIC_ADDR;
|
||||
|
||||
if (forced == 1 || *reset_addr == RIOTBOOT_MAGIC_NUMBER) {
|
||||
*reset_addr = 0;
|
||||
tinyusb_setup();
|
||||
tinyusb_dfu_init();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user