1625 lines
68 KiB
C
1625 lines
68 KiB
C
/*
|
|
* Copyright (c) 2022, sakumisu
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <rtthread.h>
|
|
|
|
#ifdef RT_USB_DEVICE_VIDEO
|
|
|
|
#include "include/usb_device.h"
|
|
#include "usbd_video.h"
|
|
#include "include/usb_video.h"
|
|
#include "jpgdef.h"
|
|
#include "lib/video/dvp/jpeg/jpg.h"
|
|
#include "lib/video/dvp/cmos_sensor/csi.h"
|
|
#include "lib/lcd/lcd.h"
|
|
#include "hal/vpp.h"
|
|
#include "hal/scale.h"
|
|
#include "custom_mem/custom_mem.h"
|
|
#include "video_app.h"
|
|
|
|
#define VS_HEADER_SIZ (unsigned int)(VIDEO_SIZEOF_VS_INPUT_HEADER_DESC(1,1) + VIDEO_SIZEOF_VS_FORMAT_MJPEG_DESC + VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(1))
|
|
#define CONFIG_USB_HS
|
|
|
|
#ifdef CONFIG_USB_HS
|
|
#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
|
|
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
|
|
|
|
// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
|
|
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
|
|
|
|
// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
|
|
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
|
|
|
|
#else
|
|
#define MAX_PAYLOAD_SIZE 1020
|
|
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
|
|
#endif
|
|
|
|
#define VIDEO_IN_EP 0x81
|
|
#define VIDEO_INT_EP 0x83
|
|
|
|
#define WIDTH (unsigned int)(640)
|
|
#define HEIGHT (unsigned int)(480)
|
|
|
|
#define CAM_FPS (30)
|
|
#define INTERVAL (unsigned long)(10000000 / CAM_FPS)
|
|
#define MIN_BIT_RATE(width, height) (unsigned long)(width * height * 16 * CAM_FPS) //16 bit
|
|
#define MAX_BIT_RATE(width, height) (unsigned long)(width * height * 16 * CAM_FPS)
|
|
#define MAX_FRAME_SIZE(width, height) (unsigned long)(width * height * 2)
|
|
|
|
#define UVC_MAX_PACKET_SIZE 64
|
|
#define VIDEO_BUFFER_SZ 1024
|
|
#define UVC_INTF_STR_INDEX 0x02
|
|
|
|
#define EVENT_VIDEO_START (1 << 0)
|
|
#define EVENT_VIDEO_STOP (1 << 1)
|
|
#define EVENT_VIDEO_DATA (1 << 2)
|
|
|
|
enum usbd_video_mode
|
|
{
|
|
USBD_VIDEO_CLOSE = 0,
|
|
USBD_VIDEO_OPEN,
|
|
};
|
|
|
|
struct video_entity_info {
|
|
rt_uint8_t bDescriptorSubtype;
|
|
rt_uint8_t bEntityId;
|
|
rt_uint16_t wTerminalType;
|
|
};
|
|
|
|
#define CONFIG_USBDEV_MAX_BUS 1
|
|
|
|
typedef void (*uvc_set_resolution)(uint32_t in_weight, uint32_t in_height, uint32_t out_weight, uint32_t out_height, uint32_t en);
|
|
|
|
struct usbd_video_ops
|
|
{
|
|
uvc_set_resolution set_resolution;
|
|
};
|
|
|
|
struct usbd_video_priv {
|
|
struct video_probe_and_commit_controls probe;
|
|
struct video_probe_and_commit_controls commit;
|
|
rt_uint8_t power_mode;
|
|
rt_uint8_t error_code;
|
|
struct video_entity_info info[3];
|
|
struct usbd_video_ops ops;
|
|
} g_usbd_video[CONFIG_USBDEV_MAX_BUS];
|
|
|
|
struct uvc_vc_noep_descriptor
|
|
{
|
|
#ifdef RT_USB_DEVICE_COMPOSITE
|
|
struct uiad_descriptor iad_desc;
|
|
#endif
|
|
struct uinterface_descriptor intf_desc;
|
|
struct video_cs_if_vc_header_descriptor hdr_desc;
|
|
struct video_cs_if_vc_input_terminal_descriptor it_desc;
|
|
struct video_cs_if_vc_processing_unit_descriptor pu_desc;
|
|
struct video_cs_if_vc_output_terminal_descriptor ot_desc;
|
|
};
|
|
|
|
struct uvc_vs_noep_descriptor
|
|
{
|
|
struct uinterface_descriptor intf_desc;
|
|
struct video_cs_if_vs_input_header_descriptor it_desc;
|
|
struct video_cs_if_vs_format_uncompressed_descriptor fmt_desc;
|
|
struct video_cs_if_vs_frame_uncompressed_descriptor frame_desc;
|
|
struct video_cs_if_vs_frame_uncompressed_descriptor frame2_desc;
|
|
};
|
|
|
|
struct uvc_vs_ep_descriptor
|
|
{
|
|
struct uinterface_descriptor intf_desc;
|
|
struct uendpoint_descriptor ep_desc;
|
|
};
|
|
|
|
/*
|
|
* uvc class device type
|
|
*/
|
|
|
|
struct uvc_class_device
|
|
{
|
|
rt_device_t dev;
|
|
rt_event_t event;
|
|
rt_uint8_t open_count;
|
|
|
|
rt_uint8_t *buffer;
|
|
rt_uint32_t buffer_index;
|
|
|
|
uep_t ep;
|
|
rt_thread_t thread;
|
|
};
|
|
struct uvc_class_device usbd_uvc;
|
|
|
|
rt_align(4)
|
|
static struct udevice_descriptor dev_desc =
|
|
{
|
|
USB_DESC_LENGTH_DEVICE, //bLength;
|
|
USB_DESC_TYPE_DEVICE, //type;
|
|
USB_BCD_VERSION, //bcdUSB;
|
|
USB_CLASS_MISC, //bDeviceClass;
|
|
0x02, //bDeviceSubClass;
|
|
0x01, //bDeviceProtocol;
|
|
UVC_MAX_PACKET_SIZE, //bMaxPacketSize0;
|
|
_VENDOR_ID, //idVendor;
|
|
_PRODUCT_ID, //idProduct;
|
|
USB_BCD_DEVICE, //bcdDevice;
|
|
USB_STRING_MANU_INDEX, //iManufacturer;
|
|
USB_STRING_PRODUCT_INDEX, //iProduct;
|
|
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
|
|
0x00, //bNumConfigurations;
|
|
};
|
|
|
|
//FS and HS needed
|
|
rt_align(4)
|
|
static struct usb_qualifier_descriptor dev_qualifier =
|
|
{
|
|
sizeof(dev_qualifier), //bLength
|
|
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
|
|
0x0200, //bcdUSB
|
|
USB_CLASS_VIDEO, //bDeviceClass
|
|
0x00, //bDeviceSubClass
|
|
0x00, //bDeviceProtocol
|
|
64, //bMaxPacketSize0
|
|
0x01, //bNumConfigurations
|
|
0,
|
|
};
|
|
|
|
rt_align(4)
|
|
const static char *_ustring[] =
|
|
{
|
|
"Language",
|
|
"USBZH", //"Cherry USB",
|
|
"USB2.0 Camera", //"USB Composite Device",
|
|
"20240411",
|
|
};
|
|
|
|
rt_align(4)
|
|
static struct uvc_vc_noep_descriptor vc_desc =
|
|
{
|
|
#ifdef RT_USB_DEVICE_COMPOSITE
|
|
{
|
|
USB_DESC_LENGTH_IAD,
|
|
USB_DESC_TYPE_IAD,
|
|
USB_DYNAMIC,
|
|
0x02,
|
|
USB_CLASS_VIDEO,
|
|
VIDEO_SC_VIDEO_INTERFACE_COLLECTION,
|
|
0x00,
|
|
0x00,
|
|
},
|
|
#endif
|
|
/* Interface Descriptor */
|
|
{
|
|
USB_DESC_LENGTH_INTERFACE,
|
|
USB_DESC_TYPE_INTERFACE,
|
|
USB_DYNAMIC,
|
|
0x00,
|
|
0x00,
|
|
USB_CLASS_VIDEO,
|
|
VIDEO_SC_VIDEOCONTROL,
|
|
VIDEO_PC_PROTOCOL_UNDEFINED,
|
|
#ifdef RT_USB_DEVICE_COMPOSITE
|
|
UVC_INTF_STR_INDEX,
|
|
#else
|
|
0x00,
|
|
#endif
|
|
},
|
|
/* Header Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vc_header_descriptor), //0x0d,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE,
|
|
0x0100,
|
|
VIDEO_VC_TERMINAL_LEN,
|
|
48000000,
|
|
0x01,
|
|
{0x01},
|
|
},
|
|
/* Input Terminal Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vc_input_terminal_descriptor), //0x12,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE,
|
|
0x01,
|
|
VIDEO_ITT_CAMERA,
|
|
0x00,
|
|
0x00,
|
|
0x0000,
|
|
0x0000,
|
|
0x0000,
|
|
0x03,
|
|
{0x00, 0x00, 0x00},
|
|
},
|
|
/* Processing Unit Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vc_processing_unit_descriptor), //0x0c,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE,
|
|
0x02,
|
|
0x01,
|
|
0x0000,
|
|
0x02,
|
|
{0x00,0x00},
|
|
0x00,
|
|
0x00,
|
|
},
|
|
/* Output Terminal Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vc_output_terminal_descriptor), //0x09,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE,
|
|
0x03,
|
|
VIDEO_TT_STREAMING,
|
|
0x00,
|
|
0x02,
|
|
0x00,
|
|
},
|
|
};
|
|
|
|
rt_align(4)
|
|
static struct uvc_vs_noep_descriptor vs_noep_desc =
|
|
{
|
|
/* Interface Descriptor */
|
|
{
|
|
USB_DESC_LENGTH_INTERFACE,
|
|
USB_DESC_TYPE_INTERFACE,
|
|
0x01,
|
|
0x00,
|
|
0x00,
|
|
USB_CLASS_VIDEO,
|
|
VIDEO_SC_VIDEOSTREAMING,
|
|
0x00,
|
|
0x00,
|
|
},
|
|
/* Header Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vs_input_header_descriptor), //0x0d,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE,
|
|
0x01,
|
|
VS_HEADER_SIZ,
|
|
VIDEO_IN_EP,
|
|
0x00,
|
|
0x03,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x02,
|
|
{0x00,0x00},/* bmaControls : No VideoStreaming specific controls are supported.*/
|
|
},
|
|
/* VS Format Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vs_format_uncompressed_descriptor), //0x0b,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_SUBTYPE,
|
|
0x01,
|
|
0x02,
|
|
0x00,
|
|
0x01,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
},
|
|
/* VS Frame 640x480 Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vs_frame_uncompressed_descriptor), //0x1a,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE,
|
|
0x01,
|
|
0x00,
|
|
WIDTH,
|
|
HEIGHT,
|
|
MIN_BIT_RATE(WIDTH,HEIGHT),
|
|
MAX_BIT_RATE(WIDTH,HEIGHT),
|
|
MAX_FRAME_SIZE(WIDTH,HEIGHT),
|
|
INTERVAL,
|
|
0x01,
|
|
{INTERVAL},
|
|
},
|
|
/* VS Frame 1280x720 Descriptor */
|
|
{
|
|
sizeof(struct video_cs_if_vs_frame_uncompressed_descriptor), //0x1a,
|
|
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
|
|
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE,
|
|
0x02,
|
|
0x00,
|
|
1280,
|
|
720,
|
|
MIN_BIT_RATE(1280,720),
|
|
MAX_BIT_RATE(1280,720),
|
|
MAX_FRAME_SIZE(1280,720),
|
|
INTERVAL,
|
|
0x01,
|
|
{INTERVAL},
|
|
},
|
|
};
|
|
|
|
rt_align(4)
|
|
static struct uvc_vs_ep_descriptor vs_ep_desc =
|
|
{
|
|
/* Interface Descriptor */
|
|
{
|
|
USB_DESC_LENGTH_INTERFACE,
|
|
USB_DESC_TYPE_INTERFACE,
|
|
0x01,
|
|
0x01,
|
|
0x01,
|
|
USB_CLASS_VIDEO,
|
|
VIDEO_SC_VIDEOSTREAMING,
|
|
0x00,
|
|
0x00,
|
|
},
|
|
/* Endpoint Descriptor */
|
|
{
|
|
USB_DESC_LENGTH_ENDPOINT,
|
|
USB_DESC_TYPE_ENDPOINT,
|
|
VIDEO_IN_EP | USB_DIR_OUT,
|
|
0x05,
|
|
VIDEO_PACKET_SIZE,
|
|
0x01,
|
|
},
|
|
};
|
|
|
|
|
|
static rt_bool_t usbd_video_control_request_handler(rt_uint8_t busid, ufunction_t func, ureq_t setup)
|
|
{
|
|
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
|
|
rt_uint8_t buf[26];
|
|
os_printf("%s %d\n",__FUNCTION__,__LINE__);
|
|
switch (control_selector) {
|
|
case VIDEO_VC_VIDEO_POWER_MODE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_SET_CUR:
|
|
break;
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
case VIDEO_VC_REQUEST_ERROR_CODE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
buf[0] = 0x06;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static rt_bool_t usbd_video_control_unit_terminal_request_handler(rt_uint8_t busid, ufunction_t func, ureq_t setup)
|
|
{
|
|
rt_uint8_t entity_id = (rt_uint8_t)(setup->wIndex >> 8);
|
|
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
|
|
rt_uint8_t data[26];
|
|
os_printf("%s %d\n",__FUNCTION__,__LINE__);
|
|
for (rt_uint8_t i = 0; i < 3; i++) {
|
|
struct video_entity_info *entity_info = &g_usbd_video[busid].info[i];
|
|
if (entity_info->bEntityId == entity_id) {
|
|
switch (entity_info->bDescriptorSubtype) {
|
|
case VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE:
|
|
break;
|
|
case VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
|
|
if (entity_info->wTerminalType == VIDEO_ITT_CAMERA) {
|
|
switch (control_selector) {
|
|
case VIDEO_CT_AE_MODE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
data[0] = 0x08;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint32_t dwExposureTimeAbsolute = 2500;
|
|
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
|
|
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
|
|
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
|
|
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
|
|
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_CT_FOCUS_ABSOLUTE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wFocusAbsolute = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wFocusAbsolute = 0;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wFocusAbsolute = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wFocusAbsolute = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wFocusAbsolute = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_CT_ZOOM_ABSOLUTE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wObjectiveFocalLength = 0x0064;
|
|
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wObjectiveFocalLength = 0x0064;
|
|
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wObjectiveFocalLength = 0x00c8;
|
|
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wObjectiveFocalLength = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wObjectiveFocalLength = 0x0064;
|
|
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_CT_ROLL_ABSOLUTE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wRollAbsolute = 0x0000;
|
|
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wRollAbsolute = 0x0000;
|
|
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wRollAbsolute = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wRollAbsolute = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wRollAbsolute = 0x0000;
|
|
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_CT_FOCUS_AUTO_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wFocusAuto = 0x0000;
|
|
memcpy(data, (rt_uint8_t *)&wFocusAuto, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_D("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
|
return -1;
|
|
}
|
|
} else {
|
|
LOG_D("Unhandled Video Class wTerminalType 0x%02x\r\n", entity_info->wTerminalType);
|
|
return -2;
|
|
}
|
|
break;
|
|
case VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
|
|
break;
|
|
case VIDEO_VC_SELECTOR_UNIT_DESCRIPTOR_SUBTYPE:
|
|
break;
|
|
case VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE:
|
|
switch (control_selector) {
|
|
case VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wBacklightCompensation = 0x0004;
|
|
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wBacklightCompensation = 0;
|
|
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wBacklightCompensation = 8;
|
|
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wBacklightCompensation = 1;
|
|
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wBacklightCompensation = 4;
|
|
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_BRIGHTNESS_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_SET_CUR: {
|
|
//rt_uint16_t wBrightness = (rt_uint16_t)(*data)[1] << 8 | (rt_uint16_t)(*data)[0];
|
|
} break;
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wBrightness = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wBrightness = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wBrightness = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wBrightness = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wBrightness = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_CONTRAST_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wContrast = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wContrast, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wContrast = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wContrast, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wContrast = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wContrast, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wContrast = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wContrast, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wContrast = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wContrast, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_HUE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wHue = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wHue, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wHue = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wHue, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wHue = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wHue, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wHue = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wHue, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wHue = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wHue, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_SATURATION_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wSaturation = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wSaturation = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wSaturation = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wSaturation = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_SHARPNESS_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wSharpness = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wSharpness = 0x00ff;
|
|
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wSharpness = 0x0001;
|
|
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wSharpness = 0x0080;
|
|
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_GAIN_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wGain = 0;
|
|
memcpy(data, (rt_uint8_t *)&wGain, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wGain = 255;
|
|
memcpy(data, (rt_uint8_t *)&wGain, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wGain = 1;
|
|
memcpy(data, (rt_uint8_t *)&wGain, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wGain = 255;
|
|
memcpy(data, (rt_uint8_t *)&wGain, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wWhiteBalance_Temprature = 417;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MIN: {
|
|
rt_uint16_t wWhiteBalance_Temprature = 300;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_MAX: {
|
|
rt_uint16_t wWhiteBalance_Temprature = 600;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_RES: {
|
|
rt_uint16_t wWhiteBalance_Temprature = 1;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
data[0] = 0x03; //struct video_camera_capabilities
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
break;
|
|
case VIDEO_REQUEST_GET_DEF: {
|
|
rt_uint16_t wWhiteBalance_Temprature = 417;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR: {
|
|
rt_uint16_t wWhiteBalance_Temprature_Auto = 1;
|
|
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature_Auto, 1);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
|
|
} break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
g_usbd_video[busid].error_code = 0x06;
|
|
LOG_D("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_VC_EXTENSION_UNIT_DESCRIPTOR_SUBTYPE:
|
|
break;
|
|
case VIDEO_VC_ENCODING_UNIT_DESCRIPTOR_SUBTYPE:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
rt_uint32_t usbd_video_mjpeg_payload_fill(rt_uint8_t busid, rt_uint8_t *input, rt_uint32_t input_len, rt_uint8_t *output, rt_uint32_t *out_len)
|
|
{
|
|
rt_uint32_t packets;
|
|
rt_uint32_t last_packet_size;
|
|
rt_uint32_t picture_pos = 0;
|
|
static rt_uint8_t uvc_header[2] = { 0x02, 0x80 };
|
|
|
|
packets = (input_len + (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
|
|
|
|
//os_printf("packets:%d input len:%d dwMaxPayloadSize:%d \n",packets,input_len,g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
|
|
|
|
last_packet_size = input_len - ((packets - 1) * (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2));
|
|
|
|
for (rt_size_t i = 0; i < packets; i++) {
|
|
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i] = uvc_header[0];
|
|
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1];
|
|
if (i == (packets - 1)) {
|
|
hw_memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size);
|
|
output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1);
|
|
} else {
|
|
hw_memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
|
|
picture_pos += g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2;
|
|
}
|
|
}
|
|
uvc_header[1] ^= 1;
|
|
*out_len = (input_len + 2 * packets);
|
|
return packets;
|
|
}
|
|
|
|
rt_uint32_t usbd_video_mjpeg_payload_header_fill(rt_uint8_t *input, rt_uint32_t input_len, rt_uint8_t *output, rt_uint8_t *uvc_header, rt_uint8_t uvc_header_len)
|
|
{
|
|
|
|
//os_printf("uvc header len:%d\n",uvc_header_len);
|
|
|
|
if(input_len < VIDEO_PACKET_SIZE - uvc_header_len) //2为header的长度
|
|
{
|
|
|
|
|
|
output[0] = uvc_header[0];
|
|
output[1] = uvc_header[1];
|
|
output[1] |= (1 << 1);
|
|
|
|
os_memcpy(&output[2], input, input_len);
|
|
|
|
uvc_header[1] ^= 1;
|
|
}
|
|
else
|
|
{
|
|
output[0] = uvc_header[0];
|
|
output[1] = uvc_header[1];
|
|
|
|
os_memcpy(&output[2], input, input_len);
|
|
}
|
|
|
|
return input_len + uvc_header_len;
|
|
}
|
|
|
|
static rt_err_t usbd_video_open(rt_uint8_t busid, ufunction_t func)
|
|
{
|
|
os_printf("usbd video open\r\n");
|
|
|
|
os_printf("g_usbd_video[busid].probe.bFormatIndex:%d\n",g_usbd_video[busid].probe.bFormatIndex);
|
|
|
|
if((g_usbd_video[busid].probe.bFormatIndex == 1))
|
|
{
|
|
switch(g_usbd_video[busid].probe.bFrameIndex){
|
|
case 1:
|
|
os_printf("set interface VGA\r\n");
|
|
g_usbd_video[busid].ops.set_resolution(640, 480, WIDTH, HEIGHT, USBD_VIDEO_OPEN);
|
|
break;
|
|
|
|
case 2:
|
|
os_printf("set interface 720P\r\n");
|
|
g_usbd_video[busid].ops.set_resolution(640, 480, 1280, 720, USBD_VIDEO_OPEN);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
usbd_uvc.ep->request.buffer = usbd_uvc.buffer;
|
|
usbd_uvc.ep->request.size = VIDEO_PACKET_SIZE;
|
|
usbd_uvc.ep->request.req_type = UIO_REQUEST_WRITE;
|
|
rt_usbd_io_request(func->device, usbd_uvc.ep, &usbd_uvc.ep->request);
|
|
usbd_uvc.open_count = 0;
|
|
usbd_uvc.open_count++;
|
|
rt_event_send(usbd_uvc.event, EVENT_VIDEO_START);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static rt_err_t usbd_video_close(rt_uint8_t busid, ufunction_t func)
|
|
{
|
|
os_printf("usbd video close\r\n");
|
|
|
|
struct scale_device *scale_dev;
|
|
struct scale_device *scale3_dev;
|
|
struct vpp_device *vpp_dev;
|
|
vpp_dev = (struct vpp_device *)dev_get(HG_VPP_DEVID);
|
|
scale_dev = (struct scale_device *)dev_get(HG_SCALE1_DEVID);
|
|
scale3_dev= (struct scale_device *)dev_get(HG_SCALE3_DEVID);
|
|
|
|
g_usbd_video[busid].ops.set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, USBD_VIDEO_CLOSE);
|
|
|
|
usbd_uvc.open_count--;
|
|
rt_event_send(usbd_uvc.event, EVENT_VIDEO_STOP);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void usbd_video_probe_and_commit_controls_init(rt_uint8_t busid, rt_uint32_t dwFrameInterval, rt_uint32_t dwMaxVideoFrameSize, rt_uint32_t dwMaxPayloadTransferSize)
|
|
{
|
|
g_usbd_video[busid].probe.hintUnion.bmHint = 0x01;
|
|
g_usbd_video[busid].probe.hintUnion1.bmHint = 0;
|
|
g_usbd_video[busid].probe.bFormatIndex = 1;
|
|
g_usbd_video[busid].probe.bFrameIndex = 1;
|
|
g_usbd_video[busid].probe.dwFrameInterval = dwFrameInterval;
|
|
g_usbd_video[busid].probe.wKeyFrameRate = 0;
|
|
g_usbd_video[busid].probe.wPFrameRate = 0;
|
|
g_usbd_video[busid].probe.wCompQuality = 0;
|
|
g_usbd_video[busid].probe.wCompWindowSize = 0;
|
|
g_usbd_video[busid].probe.wDelay = 0;
|
|
g_usbd_video[busid].probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
|
|
g_usbd_video[busid].probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
|
|
g_usbd_video[busid].probe.dwClockFrequency = 0;
|
|
g_usbd_video[busid].probe.bmFramingInfo = 0;
|
|
g_usbd_video[busid].probe.bPreferedVersion = 0;
|
|
g_usbd_video[busid].probe.bMinVersion = 0;
|
|
g_usbd_video[busid].probe.bMaxVersion = 0;
|
|
|
|
g_usbd_video[busid].commit.hintUnion.bmHint = 0x01;
|
|
g_usbd_video[busid].commit.hintUnion1.bmHint = 0;
|
|
g_usbd_video[busid].commit.bFormatIndex = 1;
|
|
g_usbd_video[busid].commit.bFrameIndex = 1;
|
|
g_usbd_video[busid].commit.dwFrameInterval = dwFrameInterval;
|
|
g_usbd_video[busid].commit.wKeyFrameRate = 0;
|
|
g_usbd_video[busid].commit.wPFrameRate = 0;
|
|
g_usbd_video[busid].commit.wCompQuality = 0;
|
|
g_usbd_video[busid].commit.wCompWindowSize = 0;
|
|
g_usbd_video[busid].commit.wDelay = 0;
|
|
g_usbd_video[busid].commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
|
|
g_usbd_video[busid].commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
|
|
g_usbd_video[busid].commit.dwClockFrequency = 0;
|
|
g_usbd_video[busid].commit.bmFramingInfo = 0;
|
|
g_usbd_video[busid].commit.bPreferedVersion = 0;
|
|
g_usbd_video[busid].commit.bMinVersion = 0;
|
|
g_usbd_video[busid].commit.bMaxVersion = 0;
|
|
}
|
|
|
|
void usbd_video_init_intf(rt_uint8_t busid, rt_uint32_t dwFrameInterval, rt_uint32_t dwMaxVideoFrameSize, rt_uint32_t dwMaxPayloadTransferSize)
|
|
{
|
|
|
|
g_usbd_video[busid].info[0].bDescriptorSubtype = VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
|
|
g_usbd_video[busid].info[0].bEntityId = 0x01;
|
|
g_usbd_video[busid].info[0].wTerminalType = VIDEO_ITT_CAMERA;
|
|
g_usbd_video[busid].info[1].bDescriptorSubtype = VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
|
|
g_usbd_video[busid].info[1].bEntityId = 0x03;
|
|
g_usbd_video[busid].info[1].wTerminalType = 0x00;
|
|
g_usbd_video[busid].info[2].bDescriptorSubtype = VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE;
|
|
g_usbd_video[busid].info[2].bEntityId = 0x02;
|
|
g_usbd_video[busid].info[2].wTerminalType = 0x00;
|
|
|
|
usbd_video_probe_and_commit_controls_init(busid, dwFrameInterval, dwMaxVideoFrameSize, dwMaxPayloadTransferSize);
|
|
}
|
|
|
|
static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
|
|
{
|
|
LOG_D("_ep0_cmd_handler");
|
|
|
|
dcd_ep0_send_status(device->dcd);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _vc_interface_as_handler(ufunction_t func, ureq_t setup)
|
|
{
|
|
RT_ASSERT(func != RT_NULL);
|
|
RT_ASSERT(func->device != RT_NULL);
|
|
RT_ASSERT(setup != RT_NULL);
|
|
|
|
os_printf("_vc_interface_as_handler\n");
|
|
|
|
rt_uint8_t entity_id = (rt_uint8_t)(setup->wIndex >> 8);
|
|
rt_uint8_t busid = 0;
|
|
|
|
if (entity_id == 0) {
|
|
return usbd_video_control_request_handler(busid, func, setup); /* Interface Control Requests */
|
|
} else {
|
|
return usbd_video_control_unit_terminal_request_handler(busid, func, setup); /* Unit and Terminal Requests */
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
|
|
|
|
static rt_err_t _vs_interface_as_handler(ufunction_t func, ureq_t setup)
|
|
{
|
|
RT_ASSERT(func != RT_NULL);
|
|
RT_ASSERT(func->device != RT_NULL);
|
|
RT_ASSERT(setup != RT_NULL);
|
|
|
|
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
|
|
rt_uint8_t busid = 0;
|
|
rt_uint8_t buf[26];
|
|
|
|
memset(buf, 0, 26);
|
|
|
|
os_printf("_vs_interface_as_handler\n");
|
|
os_printf("request_type:%x bRequest:%d control_selector:%d\n",(setup->request_type & USB_REQ_TYPE_MASK), setup->bRequest,control_selector);
|
|
|
|
#if 1
|
|
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
|
|
{
|
|
switch (setup->bRequest)
|
|
{
|
|
case USB_REQ_GET_INTERFACE:
|
|
break;
|
|
case USB_REQ_SET_INTERFACE:
|
|
LOG_D("set interface handler");
|
|
if (setup->wValue == 1)
|
|
{
|
|
usbd_video_open(busid, func);
|
|
}
|
|
else if (setup->wValue == 0)
|
|
{
|
|
usbd_video_close(busid, func);
|
|
}
|
|
break;
|
|
default:
|
|
LOG_D("unknown uac request 0x%x", setup->bRequest);
|
|
return -RT_ERROR;
|
|
}
|
|
}else{
|
|
switch (control_selector) {
|
|
case VIDEO_VS_PROBE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_SET_CUR:
|
|
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&buf, setup->wLength, _ep0_cmd_handler);
|
|
os_sleep_ms(5); //等待DMA读取完毕的延时
|
|
memcpy(&g_usbd_video[busid].probe, (rt_uint8_t *)&buf, 22);
|
|
os_printf("SET CUR FormatIndex:%x FrameIndex:%x buf[2]:%x %x\n",g_usbd_video[busid].probe.bFormatIndex,g_usbd_video[busid].probe.bFrameIndex,buf[2],buf[3]);
|
|
break;
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
|
|
//os_printf("GET CUR payloadsize:%d\n",g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
|
|
break;
|
|
|
|
case VIDEO_REQUEST_GET_MIN:
|
|
case VIDEO_REQUEST_GET_MAX:
|
|
case VIDEO_REQUEST_GET_RES:
|
|
case VIDEO_REQUEST_GET_DEF:
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
|
|
//os_printf("GET = payloadsize:%d\n",g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
|
|
break;
|
|
case VIDEO_REQUEST_GET_LEN:
|
|
buf[0] = sizeof(struct video_probe_and_commit_controls);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
|
|
case VIDEO_REQUEST_GET_INFO:;
|
|
buf[0] = 0x03;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_VS_COMMIT_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_SET_CUR:
|
|
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength, _ep0_cmd_handler);
|
|
os_sleep_ms(5); //等待DMA读取完毕的延时
|
|
break;
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
|
|
break;
|
|
case VIDEO_REQUEST_GET_MIN:
|
|
case VIDEO_REQUEST_GET_MAX:
|
|
case VIDEO_REQUEST_GET_RES:
|
|
case VIDEO_REQUEST_GET_DEF:
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
|
|
break;
|
|
|
|
case VIDEO_REQUEST_GET_LEN:
|
|
buf[0] = sizeof(struct video_probe_and_commit_controls);
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
|
|
case VIDEO_REQUEST_GET_INFO:;
|
|
buf[0] = 0x03;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
case VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
|
|
switch (setup->bRequest) {
|
|
case VIDEO_REQUEST_GET_CUR:
|
|
buf[0] = g_usbd_video[busid].error_code;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
case VIDEO_REQUEST_GET_INFO:
|
|
buf[0] = 0x01;
|
|
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
|
|
break;
|
|
default:
|
|
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _ep_data_handler(ufunction_t func, rt_size_t size)
|
|
{
|
|
RT_ASSERT(func != RT_NULL);
|
|
|
|
rt_event_send(usbd_uvc.event, EVENT_VIDEO_DATA);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _function_enable(ufunction_t func)
|
|
{
|
|
RT_ASSERT(func != RT_NULL);
|
|
|
|
os_printf("uvc function enable");
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _function_disable(ufunction_t func)
|
|
{
|
|
RT_ASSERT(func != RT_NULL);
|
|
|
|
os_printf("uvc function disable");
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static struct ufunction_ops ops =
|
|
{
|
|
_function_enable,
|
|
_function_disable,
|
|
RT_NULL,
|
|
};
|
|
|
|
/**
|
|
* This function will configure uvc descriptor.
|
|
*
|
|
* @param comm the communication interface number.
|
|
* @param data the data interface number.
|
|
*
|
|
* @return RT_EOK on successful.
|
|
*/
|
|
static rt_err_t _uvc_descriptor_config(struct uvc_vc_noep_descriptor *vc,
|
|
rt_uint8_t cintf_nr, struct uvc_vs_noep_descriptor *vs, rt_uint8_t sintf_nr)
|
|
{
|
|
vc->hdr_desc.baInterfaceNr[0] = sintf_nr;
|
|
#ifdef RT_USB_DEVICE_COMPOSITE
|
|
vc->iad_desc.bFirstInterface = cintf_nr;
|
|
#endif
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_bool_t opcode_func(stream *s,void *priv,rt_bool_t opcode)
|
|
{
|
|
rt_bool_t res = 0;
|
|
|
|
switch(opcode)
|
|
{
|
|
case STREAM_OPEN_ENTER:
|
|
break;
|
|
case STREAM_OPEN_EXIT:
|
|
{
|
|
enable_stream(s,1);
|
|
}
|
|
break;
|
|
case STREAM_OPEN_FAIL:
|
|
break;
|
|
default:
|
|
//默认都返回成功
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void usbd_uvc_entry(void *parameter)
|
|
{
|
|
rt_uint32_t e;
|
|
stream *s = NULL;
|
|
rt_uint32_t flen = 0;
|
|
rt_uint32_t node_len = 0;
|
|
rt_uint32_t out_len;
|
|
rt_uint32_t packets;
|
|
rt_uint32_t timeout = 0;
|
|
rt_uint32_t index = 0;
|
|
rt_uint8_t *jpeg_buf_addr = NULL;
|
|
struct data_structure *get_f = NULL;
|
|
struct ufunction *func = (struct ufunction *)parameter;
|
|
static rt_uint8_t uvc_header[2] = { 0x02, 0x80 };
|
|
|
|
usbd_uvc.buffer = os_malloc(VIDEO_BUFFER_SZ);
|
|
|
|
if (usbd_uvc.buffer == RT_NULL)
|
|
{
|
|
LOG_E("malloc failed\r\n");
|
|
goto __exit;
|
|
}
|
|
|
|
s = open_stream_available(R_RTP_JPEG, 0, 8, opcode_func, NULL);
|
|
if(s == RT_NULL)
|
|
{
|
|
LOG_D("open stream failed\n");
|
|
goto __exit;
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
if (rt_event_recv(usbd_uvc.event, EVENT_VIDEO_START | EVENT_VIDEO_STOP,
|
|
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
|
1000, &e) != RT_EOK)
|
|
{
|
|
printf("usbd video wait evevnt\r\n");
|
|
continue;
|
|
}
|
|
|
|
if (e & EVENT_VIDEO_START)
|
|
{
|
|
|
|
}else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
LOG_D("video display start\r\n");
|
|
|
|
#if 1
|
|
while(1){
|
|
get_f = recv_real_data(s);
|
|
flen = 0;
|
|
if(get_f)
|
|
{
|
|
printf("U");
|
|
flen = get_stream_real_data_len(get_f);
|
|
node_len = GET_NODE_LEN(get_f);
|
|
jpeg_buf_addr = (rt_uint8_t *)GET_JPG_BUF(get_f);
|
|
packets = 0;
|
|
out_len = 0;
|
|
memset(usbd_uvc.buffer,0,VIDEO_BUFFER_SZ);
|
|
|
|
while(flen)
|
|
{
|
|
if (rt_event_recv(usbd_uvc.event, EVENT_VIDEO_DATA | EVENT_VIDEO_STOP,
|
|
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
|
1000, &e) != RT_EOK)
|
|
{
|
|
os_printf("uvc_video_thread: recv event timeout\n");
|
|
}
|
|
|
|
if (e & EVENT_VIDEO_DATA)
|
|
{
|
|
//printf("D");
|
|
if(flen > (VIDEO_PACKET_SIZE-sizeof(uvc_header)))
|
|
{
|
|
out_len = usbd_video_mjpeg_payload_header_fill((rt_uint8_t *)(jpeg_buf_addr + index), (VIDEO_PACKET_SIZE-sizeof(uvc_header)), usbd_uvc.buffer, (rt_uint8_t*)&uvc_header,sizeof(uvc_header));
|
|
//os_printf("1 out len:%d buffer:%x [0]:%x [1]:%x [2]:%x [3]:%x\n",out_len,jpeg_buf_addr + index, usbd_uvc.buffer[0], usbd_uvc.buffer[1],usbd_uvc.buffer[2],usbd_uvc.buffer[3]);
|
|
usbd_uvc.ep->request.buffer = usbd_uvc.buffer;
|
|
usbd_uvc.ep->request.size = VIDEO_PACKET_SIZE;
|
|
usbd_uvc.ep->request.req_type = UIO_REQUEST_WRITE;
|
|
|
|
rt_usbd_io_request(func->device, usbd_uvc.ep, &usbd_uvc.ep->request);
|
|
flen -= (VIDEO_PACKET_SIZE-sizeof(uvc_header));
|
|
index += (VIDEO_PACKET_SIZE-sizeof(uvc_header));
|
|
}else{
|
|
|
|
out_len = usbd_video_mjpeg_payload_header_fill((rt_uint8_t *)(jpeg_buf_addr + index), flen, usbd_uvc.buffer, (rt_uint8_t*)&uvc_header,sizeof(uvc_header));
|
|
// os_printf("2 out len:%d buffer:%x [0]:%x [1]:%x [2]:%x [3]:%x\n",out_len,jpeg_buf_addr + index, usbd_uvc.buffer[0], usbd_uvc.buffer[1],usbd_uvc.buffer[2],usbd_uvc.buffer[3]);
|
|
usbd_uvc.ep->request.buffer = usbd_uvc.buffer;
|
|
usbd_uvc.ep->request.size = out_len;
|
|
usbd_uvc.ep->request.req_type = UIO_REQUEST_WRITE;
|
|
|
|
rt_usbd_io_request(func->device, usbd_uvc.ep, &usbd_uvc.ep->request);
|
|
flen = 0;
|
|
index = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (e & EVENT_VIDEO_STOP)
|
|
{
|
|
printf("P");
|
|
flen = 0;
|
|
index = 0;
|
|
timeout = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if(get_f)
|
|
{
|
|
free_data(get_f);
|
|
get_f = NULL;
|
|
}
|
|
timeout = 0;
|
|
}
|
|
else
|
|
{
|
|
timeout++;
|
|
printf("n");
|
|
os_sleep_ms(5);
|
|
if(timeout > 100)
|
|
{
|
|
timeout = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
__exit:
|
|
if (usbd_uvc.buffer)
|
|
os_free(usbd_uvc.buffer);
|
|
if (s)
|
|
close_stream(s);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* This function will create a uvc function instance.
|
|
*
|
|
* @param device the usb device object.
|
|
*
|
|
* @return RT_EOK on successful.
|
|
*/
|
|
ufunction_t rt_usbd_function_uvc_device_create(udevice_t device)
|
|
{
|
|
ufunction_t func;
|
|
uintf_t intf_vc, intf_vs;
|
|
ualtsetting_t setting_vs_noep;
|
|
ualtsetting_t setting_vc, setting_vs_ep;
|
|
struct uvc_vs_ep_descriptor *vs_ep_desc_t;
|
|
|
|
/* parameter check */
|
|
RT_ASSERT(device != RT_NULL);
|
|
#ifdef RT_USB_DEVICE_COMPOSITE
|
|
rt_usbd_device_set_interface_string(device, UVC_INTF_STR_INDEX, _ustring[2]);
|
|
#else
|
|
/* set usb device string description */
|
|
rt_usbd_device_set_string(device, _ustring);
|
|
#endif
|
|
|
|
/* create a uac function */
|
|
func = rt_usbd_function_new(device, &dev_desc, &ops);
|
|
//not support HS
|
|
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
|
|
|
|
usbd_uvc_init(func);
|
|
|
|
/* create interface */
|
|
intf_vc = rt_usbd_interface_new(device, _vc_interface_as_handler); //配置接口handler
|
|
intf_vs = rt_usbd_interface_new(device, _vs_interface_as_handler); //配置接口handler
|
|
|
|
os_printf("===sizeof:%d %d %d\n",sizeof(struct uvc_vc_noep_descriptor),sizeof(struct uvc_vs_noep_descriptor),sizeof(struct uvc_vs_ep_descriptor));
|
|
|
|
/* create alternate setting */
|
|
setting_vc = rt_usbd_altsetting_new(sizeof(struct uvc_vc_noep_descriptor));
|
|
setting_vs_noep = rt_usbd_altsetting_new(sizeof(struct uvc_vs_noep_descriptor));
|
|
setting_vs_ep = rt_usbd_altsetting_new(sizeof(struct uvc_vs_ep_descriptor));
|
|
/* config desc in alternate setting */
|
|
rt_usbd_altsetting_config_descriptor(setting_vc, &vc_desc,
|
|
(rt_off_t) & ((struct uvc_vc_noep_descriptor *)0)->intf_desc);
|
|
os_printf("intf_desc[0]:%x\n",&(vc_desc.intf_desc));
|
|
rt_usbd_altsetting_config_descriptor(setting_vs_noep, &vs_noep_desc,
|
|
(rt_off_t) & ((struct uvc_vs_noep_descriptor *)0)->intf_desc);
|
|
rt_usbd_altsetting_config_descriptor(setting_vs_ep, &vs_ep_desc,
|
|
(rt_off_t) & ((struct uvc_vs_ep_descriptor *)0)->intf_desc);
|
|
/* configure the uac interface descriptor */
|
|
_uvc_descriptor_config(setting_vc->desc, intf_vc->intf_num, setting_vs_noep->desc, intf_vs->intf_num);
|
|
//_uac_samplerate_config(setting_vs_ep->desc, AUDIO_SAMPLERATE);
|
|
|
|
/* create endpoint */
|
|
vs_ep_desc_t = (struct uvc_vs_ep_descriptor *)setting_vs_ep->desc;
|
|
usbd_uvc.ep = rt_usbd_endpoint_new(&vs_ep_desc_t->ep_desc, _ep_data_handler); //配置端点handler
|
|
|
|
/* add the endpoint to the alternate setting */
|
|
rt_usbd_altsetting_add_endpoint(setting_vs_ep, usbd_uvc.ep);
|
|
|
|
/* add the alternate setting to the interface, then set default setting of the interface */
|
|
rt_usbd_interface_add_altsetting(intf_vc, setting_vc);
|
|
rt_usbd_set_altsetting(intf_vc, 0);
|
|
rt_usbd_interface_add_altsetting(intf_vs, setting_vs_noep);
|
|
rt_usbd_interface_add_altsetting(intf_vs, setting_vs_ep);
|
|
rt_usbd_set_altsetting(intf_vs, 0);
|
|
|
|
/* add the interface to the uac function */
|
|
rt_usbd_function_add_interface(func, intf_vc);
|
|
rt_usbd_function_add_interface(func, intf_vs);
|
|
|
|
return func;
|
|
}
|
|
|
|
static void usbd_video_set_resolution(uint32_t in_weight, uint32_t in_height, uint32_t out_weight, uint32_t out_height, uint32_t en)
|
|
{
|
|
struct vpp_device *vpp_dev;
|
|
struct scale_device *scale_dev;
|
|
struct scale_device *scale3_dev;
|
|
|
|
extern uint8 *yuvbuf;
|
|
|
|
vpp_dev = (struct vpp_device *)dev_get(HG_VPP_DEVID);
|
|
scale_dev = (struct scale_device *)dev_get(HG_SCALE1_DEVID);
|
|
scale3_dev= (struct scale_device *)dev_get(HG_SCALE3_DEVID);
|
|
|
|
if(en)
|
|
{
|
|
photo_msg.out0_h = out_height;
|
|
photo_msg.out0_w = out_weight;
|
|
|
|
if((in_weight != out_weight) || (in_height != out_height))
|
|
{
|
|
os_printf("---------SCALE TO MJPEG---------\n");
|
|
scale_from_vpp_to_jpg(scale_dev,(uint32)yuvbuf,in_weight,in_height,out_weight,out_height);
|
|
jpg_cfg(HG_JPG0_DEVID,SCALER_DATA);
|
|
}
|
|
else
|
|
{
|
|
os_printf("---------VPP TO MJPEG---------\n");
|
|
jpg_cfg(HG_JPG0_DEVID,VPP_DATA0);
|
|
}
|
|
start_jpeg();
|
|
scale_close(scale3_dev);
|
|
vpp_open(vpp_dev);
|
|
}
|
|
else
|
|
{
|
|
vpp_close(vpp_dev);
|
|
scale_close(scale_dev);
|
|
scale_open(scale3_dev);
|
|
stop_jpeg();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
extern void usb_uvc_thread();
|
|
rt_bool_t usbd_uvc_init(struct ufunction *func)
|
|
{
|
|
rt_uint8_t busid = 0;
|
|
rt_thread_t usbd_uvc_thread;
|
|
|
|
g_usbd_video[busid].ops.set_resolution = usbd_video_set_resolution;
|
|
|
|
usbd_uvc.event = rt_event_create("usbd_uvc_event", RT_IPC_FLAG_FIFO);
|
|
|
|
|
|
usbd_uvc_thread = rt_thread_create("usbd_uvc_thread",
|
|
usbd_uvc_entry, func,
|
|
1024,
|
|
OS_TASK_PRIORITY_NORMAL, 10);
|
|
|
|
if(usbd_uvc_thread != RT_NULL)
|
|
rt_thread_startup(usbd_uvc_thread);
|
|
|
|
usbd_uvc.thread = usbd_uvc_thread;
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
|
|
void rt_usbd_function_uvc_device_delete()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* register uvc class
|
|
*/
|
|
static struct udclass uvc_device_class =
|
|
{
|
|
.rt_usbd_function_create = rt_usbd_function_uvc_device_create,
|
|
.rt_usbd_function_delete = rt_usbd_function_uvc_device_delete,
|
|
};
|
|
|
|
int rt_usbd_uvc_device_class_register(void)
|
|
{
|
|
rt_usbd_class_register(&uvc_device_class);
|
|
usbd_video_init_intf(0, INTERVAL, MAX_FRAME_SIZE(WIDTH,HEIGHT), MAX_PAYLOAD_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif |