mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-31 05:52:55 +08:00
TUD_EPBUF_TYPE_DEF video_device.c
This commit is contained in:
parent
7831af3ccf
commit
1eb72af433
@ -116,34 +116,32 @@ typedef struct TU_ATTR_PACKED {
|
|||||||
uint8_t state; /* 0:probing 1:committed 2:streaming */
|
uint8_t state; /* 0:probing 1:committed 2:streaming */
|
||||||
|
|
||||||
video_probe_and_commit_control_t probe_commit_payload; /* Probe and Commit control */
|
video_probe_and_commit_control_t probe_commit_payload; /* Probe and Commit control */
|
||||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
|
||||||
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;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TUD_EPBUF_DEF(buf, CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE);
|
||||||
|
} videod_streaming_epbuf_t;
|
||||||
|
|
||||||
/* video control interface */
|
/* video control interface */
|
||||||
typedef struct TU_ATTR_PACKED {
|
typedef struct TU_ATTR_PACKED {
|
||||||
uint8_t const *beg; /* The head of the first video control interface descriptor */
|
const uint8_t*beg; /* The head of the first video control interface descriptor */
|
||||||
uint16_t len; /* Byte length of the descriptors */
|
uint16_t len; /* Byte length of the descriptors */
|
||||||
uint16_t cur; /* offset for current video control interface */
|
uint16_t cur; /* offset for current video control interface */
|
||||||
uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
|
uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
|
||||||
uint8_t error_code; /* error code */
|
uint8_t error_code; /* error code */
|
||||||
uint8_t power_mode;
|
uint8_t power_mode;
|
||||||
|
|
||||||
/*------------- 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 */
|
|
||||||
|
|
||||||
} videod_interface_t;
|
} videod_interface_t;
|
||||||
|
|
||||||
#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf)
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
||||||
CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
|
||||||
|
|
||||||
tu_static uint8_t const _cap_get = 0x1u; /* support for GET */
|
static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
||||||
tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
|
CFG_TUD_MEM_SECTION static videod_streaming_epbuf_t _videod_streaming_epbuf[CFG_TUD_VIDEO_STREAMING];
|
||||||
|
|
||||||
|
static uint8_t const _cap_get = 0x1u; /* support for GET */
|
||||||
|
static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Debug
|
// Debug
|
||||||
@ -816,21 +814,20 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Prepare the next packet payload. */
|
/** Prepare the next packet payload. */
|
||||||
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
|
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint8_t* ep_buf) {
|
||||||
{
|
|
||||||
uint_fast16_t remaining = stm->bufsize - stm->offset;
|
uint_fast16_t remaining = stm->bufsize - stm->offset;
|
||||||
uint_fast16_t hdr_len = stm->ep_buf[0];
|
uint_fast16_t hdr_len = ep_buf[0];
|
||||||
uint_fast16_t pkt_len = stm->max_payload_transfer_size;
|
uint_fast16_t pkt_len = stm->max_payload_transfer_size;
|
||||||
if (hdr_len + remaining < pkt_len) {
|
if (hdr_len + remaining < pkt_len) {
|
||||||
pkt_len = hdr_len + remaining;
|
pkt_len = hdr_len + remaining;
|
||||||
}
|
}
|
||||||
TU_ASSERT(pkt_len >= hdr_len);
|
TU_ASSERT(pkt_len >= hdr_len);
|
||||||
uint_fast16_t data_len = pkt_len - hdr_len;
|
uint_fast16_t data_len = pkt_len - hdr_len;
|
||||||
memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
|
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
|
||||||
stm->offset += data_len;
|
stm->offset += data_len;
|
||||||
remaining -= data_len;
|
remaining -= data_len;
|
||||||
if (!remaining) {
|
if (!remaining) {
|
||||||
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*) ep_buf;
|
||||||
hdr->EndOfFrame = 1;
|
hdr->EndOfFrame = 1;
|
||||||
}
|
}
|
||||||
return hdr_len + data_len;
|
return hdr_len + data_len;
|
||||||
@ -1001,7 +998,8 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
tusb_control_request_t const *request,
|
tusb_control_request_t const *request,
|
||||||
uint_fast8_t stm_idx) {
|
uint_fast8_t stm_idx) {
|
||||||
(void)rhport;
|
(void)rhport;
|
||||||
videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
|
videod_streaming_interface_t *stm = &_videod_streaming_itf[stm_idx];
|
||||||
|
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[stm_idx];
|
||||||
|
|
||||||
uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
|
uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
|
||||||
TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vs_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
|
TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vs_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
|
||||||
@ -1013,7 +1011,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
case VIDEO_REQUEST_GET_CUR:
|
case VIDEO_REQUEST_GET_CUR:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(tud_control_xfer(rhport, request, &stm->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
return VIDEO_ERROR_NONE;
|
return VIDEO_ERROR_NONE;
|
||||||
|
|
||||||
@ -1028,17 +1026,17 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIDEO_VS_CTL_PROBE:
|
case VIDEO_VS_CTL_PROBE:
|
||||||
if (self->state != VS_STATE_PROBING) {
|
if (stm->state != VS_STATE_PROBING) {
|
||||||
self->state = VS_STATE_PROBING;
|
stm->state = VS_STATE_PROBING;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (request->bRequest) {
|
switch (request->bRequest) {
|
||||||
case VIDEO_REQUEST_SET_CUR:
|
case VIDEO_REQUEST_SET_CUR:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)),
|
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)),
|
||||||
VIDEO_ERROR_UNKNOWN);
|
VIDEO_ERROR_UNKNOWN);
|
||||||
} else if (stage == CONTROL_STAGE_DATA) {
|
} else if (stage == CONTROL_STAGE_DATA) {
|
||||||
TU_VERIFY(_update_streaming_parameters(self, &self->probe_commit_payload),
|
TU_VERIFY(_update_streaming_parameters(stm, &stm->probe_commit_payload),
|
||||||
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||||
}
|
}
|
||||||
return VIDEO_ERROR_NONE;
|
return VIDEO_ERROR_NONE;
|
||||||
@ -1046,7 +1044,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
case VIDEO_REQUEST_GET_CUR:
|
case VIDEO_REQUEST_GET_CUR:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
return VIDEO_ERROR_NONE;
|
return VIDEO_ERROR_NONE;
|
||||||
|
|
||||||
@ -1056,8 +1054,8 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
case VIDEO_REQUEST_GET_DEF:
|
case VIDEO_REQUEST_GET_DEF:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||||
video_probe_and_commit_control_t tmp = self->probe_commit_payload;
|
video_probe_and_commit_control_t tmp = stm->probe_commit_payload;
|
||||||
TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
TU_VERIFY(_negotiate_streaming_parameters(stm, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
return VIDEO_ERROR_NONE;
|
return VIDEO_ERROR_NONE;
|
||||||
@ -1085,23 +1083,23 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
switch (request->bRequest) {
|
switch (request->bRequest) {
|
||||||
case VIDEO_REQUEST_SET_CUR:
|
case VIDEO_REQUEST_SET_CUR:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||||
} else if (stage == CONTROL_STAGE_DATA) {
|
} else if (stage == CONTROL_STAGE_DATA) {
|
||||||
video_probe_and_commit_control_t *param = &self->probe_commit_payload;
|
video_probe_and_commit_control_t *param = &stm->probe_commit_payload;
|
||||||
TU_VERIFY(_update_streaming_parameters(self, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
TU_VERIFY(_update_streaming_parameters(stm, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||||
/* Set the negotiated value */
|
/* Set the negotiated value */
|
||||||
self->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
|
stm->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
|
||||||
int ret = VIDEO_ERROR_NONE;
|
int ret = VIDEO_ERROR_NONE;
|
||||||
if (tud_video_commit_cb) {
|
if (tud_video_commit_cb) {
|
||||||
ret = tud_video_commit_cb(self->index_vc, self->index_vs, param);
|
ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param);
|
||||||
}
|
}
|
||||||
if (VIDEO_ERROR_NONE == ret) {
|
if (VIDEO_ERROR_NONE == ret) {
|
||||||
self->state = VS_STATE_COMMITTED;
|
stm->state = VS_STATE_COMMITTED;
|
||||||
self->buffer = NULL;
|
stm->buffer = NULL;
|
||||||
self->bufsize = 0;
|
stm->bufsize = 0;
|
||||||
self->offset = 0;
|
stm->offset = 0;
|
||||||
/* initialize payload header */
|
/* initialize payload header */
|
||||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)self->ep_buf;
|
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm_epbuf->buf;
|
||||||
hdr->bHeaderLength = sizeof(*hdr);
|
hdr->bHeaderLength = sizeof(*hdr);
|
||||||
hdr->bmHeaderInfo = 0;
|
hdr->bmHeaderInfo = 0;
|
||||||
}
|
}
|
||||||
@ -1111,7 +1109,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||||||
case VIDEO_REQUEST_GET_CUR:
|
case VIDEO_REQUEST_GET_CUR:
|
||||||
if (stage == CONTROL_STAGE_SETUP) {
|
if (stage == CONTROL_STAGE_SETUP) {
|
||||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
return VIDEO_ERROR_NONE;
|
return VIDEO_ERROR_NONE;
|
||||||
|
|
||||||
@ -1199,12 +1197,14 @@ bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
|
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) {
|
||||||
{
|
|
||||||
TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
|
TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
|
||||||
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
|
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
|
||||||
|
|
||||||
if (!buffer || !bufsize) return false;
|
if (!buffer || !bufsize) return false;
|
||||||
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
|
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
|
||||||
|
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[ctl_idx];
|
||||||
|
|
||||||
if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
|
if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
|
||||||
if (stm->state == VS_STATE_PROBING) return false;
|
if (stm->state == VS_STATE_PROBING) return false;
|
||||||
|
|
||||||
@ -1221,14 +1221,14 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
|
|||||||
|
|
||||||
TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
|
TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
|
||||||
/* update the packet header */
|
/* update the packet header */
|
||||||
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_epbuf->buf;
|
||||||
hdr->FrameID ^= 1;
|
hdr->FrameID ^= 1;
|
||||||
hdr->EndOfFrame = 0;
|
hdr->EndOfFrame = 0;
|
||||||
/* update the packet data */
|
/* update the packet data */
|
||||||
stm->buffer = (uint8_t*)buffer;
|
stm->buffer = (uint8_t*)buffer;
|
||||||
stm->bufsize = bufsize;
|
stm->bufsize = bufsize;
|
||||||
uint_fast16_t pkt_len = _prepare_in_payload(stm);
|
uint_fast16_t pkt_len = _prepare_in_payload(stm, stm_epbuf->buf);
|
||||||
TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
|
TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm_epbuf->buf, (uint16_t) pkt_len), 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1242,7 +1242,7 @@ void videod_init(void) {
|
|||||||
}
|
}
|
||||||
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
||||||
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
||||||
tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
|
tu_memclr(stm, sizeof(videod_streaming_interface_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,7 +1258,7 @@ void videod_reset(uint8_t rhport) {
|
|||||||
}
|
}
|
||||||
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
||||||
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
||||||
tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
|
tu_memclr(stm, sizeof(videod_streaming_interface_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1392,13 +1392,14 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
|||||||
uint8_t const *desc = ctl->beg;
|
uint8_t const *desc = ctl->beg;
|
||||||
if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break;
|
if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
|
TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
|
||||||
|
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[itf];
|
||||||
|
|
||||||
if (stm->offset < stm->bufsize) {
|
if (stm->offset < stm->bufsize) {
|
||||||
/* Claim the endpoint */
|
/* Claim the endpoint */
|
||||||
TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
|
TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
|
||||||
uint_fast16_t pkt_len = _prepare_in_payload(stm);
|
uint_fast16_t pkt_len = _prepare_in_payload(stm, stm_epbuf->buf);
|
||||||
TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
|
TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm_epbuf->buf, (uint16_t) pkt_len), 0);
|
||||||
} else {
|
} else {
|
||||||
stm->buffer = NULL;
|
stm->buffer = NULL;
|
||||||
stm->bufsize = 0;
|
stm->bufsize = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user