This module provides a USB Host Video Device Class Driver (HUVC). It implements the USB HUVC Interface.
The r_usb_huvc module combines with the r_usb_basic module to provide USB Host Video Device Class (HUVC) driver.
The user sets the data communication related items of the UVC device using the following class request.
For details about each device class, please refer to Video Class specification.
#define OPTION_KEEP_RECEIVING_WHILE_DEVICE_IS_CONNECTED
#define OPTION_WAIT_BEFORE_ISO_IN_TRANSFER_START
#if defined(OPTION_WAIT_BEFORE_ISO_IN_TRANSFER_START)
#define APP_DELAY_TIME_MS 50
#endif
#define CLASS_REQ_BUFFER_SIZE (256)
#define VIDEO_BUFFER_SIZE (40 * 1024)
#define TEMP_BUFFER_SIZE (1024)
#define BMREQUESTTYPETYPE (0x0060U)
#define ALT_NUM_0 (0)
#define STREAM_HEADER_BFH_ERR (0x40)
#define PROBE_CONTROL_REQUEST_SIZE (0x0022)
#define HIBANDWIDTH_MAX_PAYLOAD_SIZE (3 * 2024)
#define NON_HIBANDWIDTH_MAX_PAYLOAD_SIZE (1024)
#define STREAM_HEADER_LENGTH (12)
#define MAX_PAYLOAD_SIZE_192 (192)
#define MAX_PAYLOAD_SIZE_384 (384)
#define MAX_PAYLOAD_SIZE_512 (512)
#define MAX_PAYLOAD_SIZE_640 (640)
#define MAX_PAYLOAD_SIZE_800 (800)
#define APP_STREAMING_FORMAT USB_HUVC_VS_FORMAT_MJPEG
#define APP_STREAMING_FRAME_WIDTH 640
#define APP_STREAMING_FRAME_HEIGHT 480
#define APP_TREAMING_FRAME_INTERVAL 333333
void usb_huvc_example(void);
#if (BSP_CFG_RTOS == 2)
void usb_apl_callback(usb_event_info_t * p_event_info, usb_hdl_t cur_task,
usb_onoff_t usb_state);
#endif
#if (BSP_CFG_RTOS == 2)
static volatile usb_event_info_t * p_usb_event = NULL;
extern QueueHandle_t g_usb_queue;
#else
static usb_event_info_t event_info = {0};
static volatile usb_event_info_t * p_usb_event = &event_info;
#endif
static uint8_t g_class_req_buf[CLASS_REQ_BUFFER_SIZE] BSP_ALIGN_VARIABLE(4) = {RESET_VALUE};
static uint8_t g_recv_buffer[VIDEO_BUFFER_SIZE] BSP_ALIGN_VARIABLE(4);
static uint8_t g_recv_frame_data[VIDEO_BUFFER_SIZE] BSP_ALIGN_VARIABLE(4);
#if (USB_CFG_DMA == USB_CFG_ENABLE)
static uint8_t g_temp_buffer[TEMP_BUFFER_SIZE] BSP_ALIGN_VARIABLE(4);
#endif
static uint8_t * g_p_buffer = &g_recv_buffer[0];
static uint8_t g_usb_dummy = RESET_VALUE;
static volatile bool g_err_flag = false;
static usb_huvc_streaming_info_t g_streaming_info;
static uint32_t g_alt_get_retry_values[] =
{
MAX_PAYLOAD_SIZE_800,
MAX_PAYLOAD_SIZE_640,
MAX_PAYLOAD_SIZE_512,
MAX_PAYLOAD_SIZE_384,
MAX_PAYLOAD_SIZE_192
};
static uint8_t g_device_address = 0;
static uint32_t g_completed_read_transfer_length_total = 0;
static uint32_t g_completed_frame_data_length_total = 0;
static void huvc_app_standard_request_complete(void);
static void huvc_app_video_class_request_complete(void);
static fsp_err_t huvc_app_interface_set(uint32_t value, uint32_t index);
static fsp_err_t huvc_app_probe_set(usb_huvc_streaming_info_t * p_info);
static fsp_err_t huvc_app_probe_get(usb_huvc_streaming_info_t * p_info);
static fsp_err_t huvc_app_commit_set(usb_huvc_streaming_info_t * p_info);
static void handle_error(
fsp_err_t err,
char * err_str);
void usb_huvc_example (void)
{
uint8_t * p_header;
#if (BSP_CFG_RTOS == 2)
BaseType_t err_queue = USB_FALSE;
#endif
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
while (true)
{
if (true == g_err_flag)
{
}
#if (BSP_CFG_RTOS == 2)
err_queue = xQueueReceive(g_usb_queue, &p_usb_event, (portMAX_DELAY));
if (USB_TRUE != err_queue)
{
handle_error(
FSP_ERR_ABORTED,
"Error in receiving USB event message through queue");
}
#else
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
#endif
switch (p_usb_event->event)
{
{
g_device_address = p_usb_event->device_address;
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
g_streaming_info.format = APP_STREAMING_FORMAT;
g_streaming_info.width = APP_STREAMING_FRAME_WIDTH;
g_streaming_info.height = APP_STREAMING_FRAME_HEIGHT;
g_streaming_info.interval = APP_TREAMING_FRAME_INTERVAL;
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
err = huvc_app_probe_set(&g_streaming_info);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
break;
}
{
if ((FSP_SUCCESS == p_usb_event->status) || (FSP_ERR_USB_SIZE_SHORT == p_usb_event->status))
{
#if (USB_CFG_DMA == USB_CFG_ENABLE)
if (g_p_buffer == &g_temp_buffer[0])
{
memcpy(g_recv_buffer + g_completed_read_transfer_length_total,
g_p_buffer,
p_usb_event->data_size);
}
#endif
p_header = g_recv_buffer + g_completed_read_transfer_length_total;
if (0 == (STREAM_HEADER_BFH_ERR & p_header[1]))
{
if (STREAM_HEADER_LENGTH < p_usb_event->data_size)
{
memcpy(g_recv_frame_data + g_completed_frame_data_length_total,
g_p_buffer,
p_usb_event->data_size);
g_completed_frame_data_length_total += p_usb_event->data_size;
}
}
else
{
}
g_completed_read_transfer_length_total += p_usb_event->data_size;
#if (USB_CFG_DMA == USB_CFG_ENABLE)
if (0 != g_completed_read_transfer_length_total % sizeof(uint32_t))
{
g_p_buffer = &g_temp_buffer[0];
}
else
{
g_p_buffer = g_recv_buffer + g_completed_read_transfer_length_total;
}
#else
g_p_buffer = g_recv_buffer + g_completed_read_transfer_length_total;
#endif
if (VIDEO_BUFFER_SIZE >= g_completed_read_transfer_length_total + g_streaming_info.max_payload_size)
{
err =
R_USB_Read(&g_basic0_ctrl, g_p_buffer, g_streaming_info.max_payload_size, g_device_address);
if (FSP_SUCCESS != err)
{
huvc_app_interface_set(ALT_NUM_0, g_streaming_info.interface_number);
break;
}
}
else
{
#if defined OPTION_KEEP_RECEIVING_WHILE_DEVICE_IS_CONNECTED
g_completed_frame_data_length_total = 0;
g_completed_read_transfer_length_total = 0;
g_recv_buffer,
g_streaming_info.max_payload_size,
g_device_address);
if (FSP_SUCCESS != err)
{
huvc_app_interface_set(ALT_NUM_0, g_streaming_info.interface_number);
break;
}
#else
err = huvc_app_interface_set(ALT_NUM_0, g_streaming_info.interface_number);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
#endif
}
}
else
{
huvc_app_interface_set(ALT_NUM_0, g_streaming_info.interface_number);
break;
}
break;
}
{
switch (BMREQUESTTYPETYPE & p_usb_event->setup.request_type)
{
{
huvc_app_standard_request_complete();
break;
}
{
huvc_app_video_class_request_complete();
break;
}
}
break;
}
{
memset(&g_streaming_info, 0, sizeof(g_streaming_info));
g_device_address = 0;
g_completed_read_transfer_length_total = 0;
g_completed_frame_data_length_total = 0;
break;
}
default:
{
break;
}
}
}
}
static void huvc_app_standard_request_complete (void)
{
{
if ((g_streaming_info.interface_number == p_usb_event->setup.request_index) &&
(g_streaming_info.alternate_number == p_usb_event->setup.request_value))
{
g_streaming_info.interface_number,
g_streaming_info.alternate_number,
g_device_address);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
#if defined(OPTION_WAIT_BEFORE_ISO_IN_TRANSFER_START)
#endif
err =
R_USB_Read(&g_basic0_ctrl, g_recv_buffer, g_streaming_info.max_payload_size, g_device_address);
if (FSP_SUCCESS != err)
{
huvc_app_interface_set(ALT_NUM_0, g_streaming_info.interface_number);
}
}
else if ((g_streaming_info.interface_number == p_usb_event->setup.request_index) &&
(ALT_NUM_0 == p_usb_event->setup.request_value))
{
}
else
{
APP_ERR_TRAP
}
}
}
static void huvc_app_video_class_request_complete (void)
{
uint32_t max_payload_size;
uint32_t i;
if ((USB_HUVC_SET_CUR == (p_usb_event->setup.request_type &
USB_BREQUEST)) &&
(USB_HUVC_VS_PROBE_CONTROL == (p_usb_event->setup.request_value & VALUE_FF00H) >> 8))
{
err = huvc_app_probe_get(&g_streaming_info);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
}
else if ((USB_HUVC_GET_CUR == (p_usb_event->setup.request_type &
USB_BREQUEST)) &&
(USB_HUVC_VS_PROBE_CONTROL == (p_usb_event->setup.request_value & VALUE_FF00H) >> 8))
{
err = huvc_app_commit_set(&g_streaming_info);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
}
else if ((USB_HUVC_SET_CUR == (p_usb_event->setup.request_type &
USB_BREQUEST)) &&
(USB_HUVC_VS_COMMIT_CONTROL == (p_usb_event->setup.request_value & VALUE_FF00H) >> 8))
{
max_payload_size = (uint32_t) g_class_req_buf[USB_HUVC_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE];
max_payload_size |= (uint32_t) g_class_req_buf[USB_HUVC_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE + 1] << 8;
max_payload_size |= (uint32_t) g_class_req_buf[USB_HUVC_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE + 2] << 16;
max_payload_size |= (uint32_t) g_class_req_buf[USB_HUVC_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE + 3] << 24;
if (HIBANDWIDTH_MAX_PAYLOAD_SIZE < max_payload_size)
{
APP_ERR_TRAP
}
else if (NON_HIBANDWIDTH_MAX_PAYLOAD_SIZE < max_payload_size)
{
g_streaming_info.max_payload_size = NON_HIBANDWIDTH_MAX_PAYLOAD_SIZE;
}
else
{
g_streaming_info.max_payload_size = max_payload_size;
}
if (FSP_SUCCESS != err)
{
if (FSP_ERR_USB_FAILED == err)
{
max_payload_size = g_streaming_info.max_payload_size;
for (i = 0; i < (sizeof(g_alt_get_retry_values) / sizeof(uint32_t)); i++)
{
if (max_payload_size != g_alt_get_retry_values[i])
{
g_streaming_info.max_payload_size = g_alt_get_retry_values[i];
if (FSP_SUCCESS == err)
{
break;
}
}
}
if (i >= (sizeof(g_alt_get_retry_values) / sizeof(uint32_t)))
{
APP_ERR_TRAP
}
}
else
{
APP_ERR_TRAP
}
}
err = huvc_app_interface_set(g_streaming_info.alternate_number, g_streaming_info.interface_number);
if (FSP_SUCCESS != err)
{
APP_ERR_TRAP
}
}
else
{
}
}
static fsp_err_t huvc_app_interface_set (uint32_t value, uint32_t index)
{
usb_setup_t setup;
setup.request_value = (uint16_t) value;
setup.request_index = (uint16_t) index;
setup.request_length = 0;
return err;
}
static fsp_err_t huvc_app_probe_set (usb_huvc_streaming_info_t * p_info)
{
usb_setup_t setup;
if (NULL == p_info)
{
return FSP_ERR_USB_PARAMETER;
}
if (0 == p_info->interface_number)
{
return FSP_ERR_USB_PARAMETER;
}
setup.request_value = USB_HUVC_VS_PROBE_CONTROL << 8;
setup.request_index = (uint16_t) p_info->interface_number;
setup.request_length = PROBE_CONTROL_REQUEST_SIZE;
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FORMAT_INDEX] = (uint8_t) p_info->current_format;
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FRAME_INDEX] = (uint8_t) p_info->current_frame;
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FRAME_INTERVAL] = (uint8_t) p_info->current_frame_interval;
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FRAME_INTERVAL + 1] = (uint8_t) (p_info->current_frame_interval >> 8);
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FRAME_INTERVAL + 2] = (uint8_t) (p_info->current_frame_interval >> 16);
g_class_req_buf[USB_HUVC_PROBE_COMMIT_FRAME_INTERVAL + 3] = (uint8_t) (p_info->current_frame_interval >> 24);
return err;
}
static fsp_err_t huvc_app_probe_get (usb_huvc_streaming_info_t * p_info)
{
usb_setup_t setup;
if (NULL == p_info)
{
return FSP_ERR_USB_PARAMETER;
}
if (0 == p_info->interface_number)
{
return FSP_ERR_USB_PARAMETER;
}
setup.request_value = USB_HUVC_VS_PROBE_CONTROL << 8;
setup.request_index = (uint16_t) p_info->interface_number;
setup.request_length = PROBE_CONTROL_REQUEST_SIZE;
return err;
}
static fsp_err_t huvc_app_commit_set (usb_huvc_streaming_info_t * p_info)
{
usb_setup_t setup;
if (NULL == p_info)
{
return FSP_ERR_USB_PARAMETER;
}
if (0 == p_info->interface_number)
{
return FSP_ERR_USB_PARAMETER;
}
setup.request_value = USB_HUVC_VS_COMMIT_CONTROL << 8;
setup.request_index = (uint16_t) p_info->interface_number;
setup.request_length = PROBE_CONTROL_REQUEST_SIZE;
return err;
}
static void handle_error (
fsp_err_t err,
char * err_str)
{
if (FSP_SUCCESS != error)
{
APP_ERR_TRAP
}
}
#if (BSP_CFG_RTOS == 2)
void usb_apl_callback (usb_event_info_t * p_event_info, usb_hdl_t handler,
usb_onoff_t usb_state)
{
if (USB_TRUE != (xQueueSend(g_usb_queue, (const void *) &p_event_info, (TickType_t) (NO_WAIT_TIME))))
{
g_err_flag = true;
}
}
#endif