mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg/tinyusb: add DFU and DFU_RT device class implementation
This commit is contained in:
parent
7fa58f74dd
commit
37b151111f
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
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.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user