espressif_tinyusb/src/class/dfu/dfu_rt_device.c

184 lines
6.0 KiB
C
Raw Normal View History

/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Sylvain Munaut <tnt@246tNt.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU_RUNTIME) || (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU_RUNTIME_AND_MODE)
#include "dfu_rt_device.h"
#include "device/usbd_pvt.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
2021-03-26 20:30:43 +01:00
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED
{
2021-04-05 22:32:58 +02:00
dfu_mode_device_status_t status;
dfu_mode_state_t state;
uint8_t attrs;
} dfu_rt_state_ctx_t;
2021-03-26 20:30:43 +01:00
// Only a single dfu state is allowed
2021-04-05 22:32:58 +02:00
CFG_TUSB_MEM_SECTION static dfu_rt_state_ctx_t _dfu_state_ctx;
2021-03-26 20:30:43 +01:00
2021-04-05 22:32:58 +02:00
static void dfu_rt_getstatus_reply(uint8_t rhport, tusb_control_request_t const * request);
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void dfu_rtd_init(void)
{
2021-04-05 22:32:58 +02:00
_dfu_state_ctx.state = APP_IDLE;
2021-03-26 20:30:43 +01:00
_dfu_state_ctx.status = DFU_STATUS_OK;
_dfu_state_ctx.attrs = tud_dfu_runtime_init_attrs_cb();
2021-04-05 22:32:58 +02:00
dfu_debug_print_context();
}
void dfu_rtd_reset(uint8_t rhport)
{
2021-04-05 22:32:58 +02:00
if (((_dfu_state_ctx.attrs & DFU_FUNC_ATTR_WILL_DETACH_BITMASK) == 0)
&& (_dfu_state_ctx.state == DFU_REQUEST_DETACH))
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
tud_dfu_runtime_reboot_to_dfu_cb();
2021-03-26 20:30:43 +01:00
}
2021-04-05 22:32:58 +02:00
_dfu_state_ctx.state = APP_IDLE;
2021-03-26 20:30:43 +01:00
_dfu_state_ctx.status = DFU_STATUS_OK;
_dfu_state_ctx.attrs = tud_dfu_runtime_init_attrs_cb();
2021-04-05 22:32:58 +02:00
dfu_debug_print_context();
}
2020-05-27 19:46:32 +02:00
uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
(void) rhport;
2020-05-27 19:46:32 +02:00
(void) max_len;
2021-04-05 22:32:58 +02:00
// Ensure this is DFU Runtime
TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) &&
(itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0);
uint8_t const * p_desc = tu_desc_next( itf_desc );
2020-05-28 08:57:49 +02:00
uint16_t drv_len = sizeof(tusb_desc_interface_t);
if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) )
{
2020-05-28 08:57:49 +02:00
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
2020-05-28 08:57:49 +02:00
return drv_len;
}
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
2021-04-05 22:32:58 +02:00
// nothing to do with DATA or ACK stage
if ( stage != CONTROL_STAGE_SETUP ) return true;
2019-11-27 06:34:30 +01:00
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
// dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request
if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
TUSB_REQ_SET_INTERFACE == request->bRequest )
{
tud_control_status(rhport, request);
return true;
}
// Handle class request only from here
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
2021-04-05 22:32:58 +02:00
TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest));
2021-03-26 20:30:43 +01:00
switch (request->bRequest)
{
case DFU_REQUEST_DETACH:
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
if (_dfu_state_ctx.state == APP_IDLE)
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
_dfu_state_ctx.state = APP_DETACH;
if ((_dfu_state_ctx.attrs & DFU_FUNC_ATTR_WILL_DETACH_BITMASK) == 1)
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
tud_dfu_runtime_reboot_to_dfu_cb();
} else {
tud_dfu_runtime_detach_start_timer_cb(request->wValue);
2021-03-26 20:30:43 +01:00
}
2021-04-05 22:32:58 +02:00
} else {
TU_LOG2(" DFU Unexpected request during state %s: %u\r\n", tu_lookup_find(&_dfu_mode_state_table, _dfu_state_ctx.state), request->bRequest);
return false;
2021-03-26 20:30:43 +01:00
}
}
break;
2021-04-05 22:32:58 +02:00
case DFU_REQUEST_GETSTATUS:
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
dfu_status_req_payload_t resp;
resp.bStatus = _dfu_state_ctx.status;
memset((uint8_t *)&resp.bwPollTimeout, 0x00, 3); // Value is ignored
resp.bState = _dfu_state_ctx.state;
resp.iString = ( tud_dfu_runtime_get_status_desc_table_index_cb ) ? tud_dfu_runtime_get_status_desc_table_index_cb() : 0;
2021-03-26 20:30:43 +01:00
2021-04-05 22:32:58 +02:00
tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_req_payload_t));
2021-03-26 20:30:43 +01:00
}
break;
2021-04-05 22:32:58 +02:00
case DFU_REQUEST_GETSTATE:
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
tud_control_xfer(rhport, request, &_dfu_state_ctx.state, 1);
2021-03-26 20:30:43 +01:00
}
break;
2021-04-05 22:32:58 +02:00
default:
2021-03-26 20:30:43 +01:00
{
2021-04-05 22:32:58 +02:00
TU_LOG2(" DFU Nonstandard Runtime Request: %u\r\n", request->bRequest);
return ( tud_dfu_runtime_req_nonstandard_cb ) ? tud_dfu_runtime_req_nonstandard_cb(rhport, stage, request) : false;
2021-03-26 20:30:43 +01:00
}
break;
}
return true;
}
2021-04-05 22:32:58 +02:00
void tud_dfu_runtime_set_status(dfu_mode_device_status_t status)
{
_dfu_state_ctx.status = status;
}
void tud_dfu_runtime_detach_timer_elapsed()
{
if (_dfu_state_ctx.state == DFU_REQUEST_DETACH)
{
_dfu_state_ctx.state = APP_IDLE;
}
}
2021-03-26 20:30:43 +01:00
#endif