Fix transfer failure when reconnecting

This commit is contained in:
kkitayam 2021-09-26 21:52:56 +09:00
parent 319db9573c
commit 0c89292a8d
4 changed files with 55 additions and 42 deletions

View File

@ -90,12 +90,6 @@
#define CFG_TUD_ENDPOINT0_SIZE 64 #define CFG_TUD_ENDPOINT0_SIZE 64
#endif #endif
// video streaming endpoint size
#define CFG_TUD_VIDEO_EP_BUFSIZE 256
// The number of video streaming interfaces
#define CFG_TUD_VIDEO_STREAMING 1
//------------- CLASS -------------// //------------- CLASS -------------//
#define CFG_TUD_CDC 0 #define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0 #define CFG_TUD_MSC 0
@ -104,8 +98,12 @@
#define CFG_TUD_AUDIO 0 #define CFG_TUD_AUDIO 0
// The number of video control interfaces // The number of video control interfaces
#define CFG_TUD_VIDEO 1 #define CFG_TUD_VIDEO 1
// The number of video streaming interfaces
#define CFG_TUD_VIDEO_STREAMING 1
#define CFG_TUD_VENDOR 0 #define CFG_TUD_VENDOR 0
// video streaming endpoint size
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// APPLICATION CONFIGURATION // APPLICATION CONFIGURATION

View File

@ -45,7 +45,7 @@ tusb_desc_device_t const desc_device =
.bDescriptorType = TUSB_DESC_DEVICE, .bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) for CDC // Use Interface Association Descriptor (IAD) for Video
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC, .bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON, .bDeviceSubClass = MISC_SUBCLASS_COMMON,
@ -104,7 +104,9 @@ uint8_t const desc_fs_configuration[] =
// Config number, interface count, string index, total length, attribute, power in mA // Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500), TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500),
// IAD for Video Control // IAD for Video Control
TUD_VIDEO_CAPTURE_DESCRIPTOR(4, EPNUM_VIDEO_IN, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, CFG_TUD_VIDEO_EP_BUFSIZE) TUD_VIDEO_CAPTURE_DESCRIPTOR(4, EPNUM_VIDEO_IN,
FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
}; };
// Invoked when received GET CONFIGURATION DESCRIPTOR // Invoked when received GET CONFIGURATION DESCRIPTOR

View File

@ -418,8 +418,6 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
_fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \ _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \
_bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp
// _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15,
/* Uncompressed 3.1.2 Table 3-3 */ /* Uncompressed 3.1.2 Table 3-3 */
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \
TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_UNCOMPRESSED, \ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_UNCOMPRESSED, \

View File

@ -28,7 +28,7 @@
#include "tusb_option.h" #include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VIDEO) #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
#include "device/usbd.h" #include "device/usbd.h"
#include "device/usbd_pvt.h" #include "device/usbd_pvt.h"
@ -66,17 +66,17 @@ typedef struct TU_ATTR_PACKED {
uint8_t index_vs; /* index from the video control interface */ uint8_t index_vs; /* index from the video control interface */
uint8_t error_code;/* error code */ uint8_t error_code;/* error code */
struct { struct {
uint16_t beg; /* Offset of the beggining of video streaming interface descriptor */ uint16_t beg; /* Offset of the begging of video streaming interface descriptor */
uint16_t end; /* Offset of the end of video streaming interface descriptor */ uint16_t end; /* Offset of the end of video streaming interface descriptor */
uint16_t cur; /* Offset of the current settings */ uint16_t cur; /* Offset of the current settings */
uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */ uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */
} desc; } desc;
uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */ uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */
uint32_t bufsize; /* frame buffer size */ uint32_t bufsize; /* frame buffer size */
uint32_t offset; /* offset for the next payload transfer */ uint32_t offset; /* offset for the next payload transfer */
uint32_t max_payload_transfer_size; uint32_t max_payload_transfer_size;
/*------------- From this point, data is not cleared by bus reset -------------*/ /*------------- From this point, data is not cleared by bus reset -------------*/
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_EP_BUFSIZE]; /* EP transfer buffer for streaming */ CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
} videod_streaming_interface_t; } videod_streaming_interface_t;
/* video control interface */ /* video control interface */
@ -89,8 +89,7 @@ typedef struct TU_ATTR_PACKED {
uint8_t power_mode; uint8_t power_mode;
/*------------- From this point, data is not cleared by bus reset -------------*/ /*------------- From this point, data is not cleared by bus reset -------------*/
// // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */
// CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for control */
} videod_interface_t; } videod_interface_t;
@ -115,7 +114,7 @@ static video_probe_and_commit_control_t const def_stm_settings = {
.wCompWindowSize = 1, /* Maybe it is match to GOP size */ .wCompWindowSize = 1, /* Maybe it is match to GOP size */
.wDelay = 240, /* milliseconds */ .wDelay = 240, /* milliseconds */
.dwMaxVideoFrameSize = FRAME_WIDTH * FRAME_HEIGHT * 12 / 8, .dwMaxVideoFrameSize = FRAME_WIDTH * FRAME_HEIGHT * 12 / 8,
.dwMaxPayloadTransferSize = ((FRAME_WIDTH * FRAME_HEIGHT * 12 / 8 * 10) + 999) / 1000 + 2, .dwMaxPayloadTransferSize = ((FRAME_WIDTH * FRAME_HEIGHT * 12 / 8 * FRAME_RATE) + 999) / 1000 + 2,
.dwClockFrequency = 27000000, /* same as MPEG-2 system time clock */ .dwClockFrequency = 27000000, /* same as MPEG-2 system time clock */
.bmFramingInfo = 0x3, .bmFramingInfo = 0x3,
.bPreferedVersion = 1, .bPreferedVersion = 1,
@ -274,7 +273,7 @@ static void const* _find_desc_entity(tusb_desc_vc_itf_t const *vc, uint_fast8_t
/** Close current video control interface. /** Close current video control interface.
* *
* @param[in,out] self The context. * @param[in,out] self Video control interface context.
* @param[in] altnum The target alternate setting number. */ * @param[in] altnum The target alternate setting number. */
static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
{ {
@ -294,9 +293,9 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
return true; return true;
} }
/** Set the specified alternate setting to own video control interface. /** Set the alternate setting to own video control interface.
* *
* @param[in,out] self The context. * @param[in,out] self Video control interface context.
* @param[in] altnum The target alternate setting number. */ * @param[in] altnum The target alternate setting number. */
static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum)
{ {
@ -333,9 +332,9 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
return true; return true;
} }
/** Set the specified alternate setting to own video control interface. /** Set the alternate setting to own video streaming interface.
* *
* @param[in,out] self The context. * @param[in,out] stm Streaming interface context.
* @param[in] altnum The target alternate setting number. */ * @param[in] altnum The target alternate setting number. */
static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum)
{ {
@ -374,6 +373,10 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
hdr->bHeaderLength = sizeof(*hdr); hdr->bHeaderLength = sizeof(*hdr);
hdr->bmHeaderInfo = 0; hdr->bmHeaderInfo = 0;
/* clear transfer management information */
stm->buffer = NULL;
stm->bufsize = 0;
stm->offset = 0;
return true; return true;
} }
@ -398,13 +401,15 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
} }
/** Handle a standard request to the video control interface. */ /** Handle a standard request to the video control interface. */
static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t ctl_idx)
{ {
switch (request->bRequest) { switch (request->bRequest) {
case TUSB_REQ_GET_INTERFACE: case TUSB_REQ_GET_INTERFACE:
if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR; if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR;
TU_VERIFY(1 == request->wLength, VIDEO_UNKNOWN); TU_VERIFY(1 == request->wLength, VIDEO_UNKNOWN);
tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[itf]); tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]);
if (!vc) return VIDEO_UNKNOWN; if (!vc) return VIDEO_UNKNOWN;
if (tud_control_xfer(rhport, request, if (tud_control_xfer(rhport, request,
(void*)&vc->std.bAlternateSetting, (void*)&vc->std.bAlternateSetting,
@ -414,9 +419,9 @@ static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, tusb_control_
case TUSB_REQ_SET_INTERFACE: case TUSB_REQ_SET_INTERFACE:
if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR; if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR;
TU_VERIFY(0 == request->wLength, VIDEO_UNKNOWN); TU_VERIFY(0 == request->wLength, VIDEO_UNKNOWN);
if (!_close_vc_itf(rhport, &_videod_itf[itf])) if (!_close_vc_itf(rhport, &_videod_itf[ctl_idx]))
return VIDEO_UNKNOWN; return VIDEO_UNKNOWN;
if (!_open_vc_itf(rhport, &_videod_itf[itf], request->wValue)) if (!_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue))
return VIDEO_UNKNOWN; return VIDEO_UNKNOWN;
tud_control_status(rhport, request); tud_control_status(rhport, request);
return VIDEO_NO_ERROR; return VIDEO_NO_ERROR;
@ -426,9 +431,11 @@ static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, tusb_control_
} }
} }
static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t ctl_idx)
{ {
videod_interface_t *self = &_videod_itf[itf]; videod_interface_t *self = &_videod_itf[ctl_idx];
/* 4.2.1 Interface Control Request */ /* 4.2.1 Interface Control Request */
switch (TU_U16_HIGH(request->wValue)) { switch (TU_U16_HIGH(request->wValue)) {
case VIDEO_VC_CTL_VIDEO_POWER_MODE: case VIDEO_VC_CTL_VIDEO_POWER_MODE:
@ -440,7 +447,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, tusb_control_r
return VIDEO_UNKNOWN; return VIDEO_UNKNOWN;
} else if (stage == CONTROL_STAGE_ACK) { } else if (stage == CONTROL_STAGE_ACK) {
if (tud_video_power_mode_cb) if (tud_video_power_mode_cb)
return tud_video_power_mode_cb(itf, self->power_mode); return tud_video_power_mode_cb(ctl_idx, self->power_mode);
} }
return VIDEO_NO_ERROR; return VIDEO_NO_ERROR;
case VIDEO_REQUEST_GET_CUR: case VIDEO_REQUEST_GET_CUR:
@ -480,18 +487,20 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, tusb_control_r
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
} }
static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_ctl_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t ctl_idx)
{ {
uint_fast8_t entity_id; uint_fast8_t entity_id;
switch (request->bmRequestType_bit.type) { switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_STANDARD: case TUSB_REQ_TYPE_STANDARD:
return handle_video_ctl_std_req(rhport, stage, request, itf); return handle_video_ctl_std_req(rhport, stage, request, ctl_idx);
case TUSB_REQ_TYPE_CLASS: case TUSB_REQ_TYPE_CLASS:
entity_id = TU_U16_HIGH(request->wIndex); entity_id = TU_U16_HIGH(request->wIndex);
if (!entity_id) { if (!entity_id) {
return handle_video_ctl_cs_req(rhport, stage, request, itf); return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx);
} else { } else {
if (!_find_desc_entity(_get_desc_vc(&_videod_itf[itf]), entity_id)) if (!_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id))
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
} }
@ -500,9 +509,11 @@ static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_requ
} }
} }
static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t stm_idx)
{ {
videod_streaming_interface_t *self = &_videod_streaming_itf[itf]; videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
switch (request->bRequest) { switch (request->bRequest) {
case TUSB_REQ_GET_INTERFACE: case TUSB_REQ_GET_INTERFACE:
if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR; if (stage != CONTROL_STAGE_SETUP) return VIDEO_NO_ERROR;
@ -526,10 +537,12 @@ static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, tusb_control_
} }
} }
static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t stm_idx)
{ {
(void)rhport; (void)rhport;
videod_streaming_interface_t *self = &_videod_streaming_itf[itf]; videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
/* 4.2.1 Interface Control Request */ /* 4.2.1 Interface Control Request */
switch (TU_U16_HIGH(request->wValue)) { switch (TU_U16_HIGH(request->wValue)) {
case VIDEO_VS_CTL_STREAM_ERROR_CODE: case VIDEO_VS_CTL_STREAM_ERROR_CODE:
@ -641,15 +654,17 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, tusb_control_r
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
} }
static int handle_video_stm_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t itf) static int handle_video_stm_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t stm_idx)
{ {
switch (request->bmRequestType_bit.type) { switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_STANDARD: case TUSB_REQ_TYPE_STANDARD:
return handle_video_stm_std_req(rhport, stage, request, itf); return handle_video_stm_std_req(rhport, stage, request, stm_idx);
case TUSB_REQ_TYPE_CLASS: case TUSB_REQ_TYPE_CLASS:
if (TU_U16_HIGH(request->wIndex)) if (TU_U16_HIGH(request->wIndex))
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
return handle_video_stm_cs_req(rhport, stage, request, itf); return handle_video_stm_cs_req(rhport, stage, request, stm_idx);
default: default:
return VIDEO_INVALID_REQUEST; return VIDEO_INVALID_REQUEST;
} }