#include "app_cfg.h"
#include "app_type.h"
#include "interfaces.h"
#include "tool/buffer/buffer.h"
#include "stack/usb/core/vsfusbh.h"
#include "stack/usb/class/host/UVC/vsfusbh_UVC.h"
#define UVC_PROBE_CRTL_DATA_SIZE 36
enum uav_evt_t
{
UAV_RESET_STREAM_PARAM = VSFSM_EVT_USER_LOCAL + 1,
UAV_ISO_ENABLE,
UAV_ISO_DISABLE,
};
enum uav_request_t
{
RC_UNDEFINED = 0x00,
SET_CUR = 0x01,
GET_CUR = 0x81,
GET_MIN = 0x82,
GET_MAX = 0x83,
GET_RES = 0x84,
GET_LEN = 0x85,
GET_INFO = 0x86,
GET_DEF = 0x87,
};
struct vsfusbh_uvc_t
{
struct vsfusbh_t *usbh;
struct vsfusbh_device_t *dev;
struct vsfsm_t init_sm;
struct vsfsm_pt_t init_pt;
struct vsfsm_t ctrl_sm;
struct vsfsm_pt_t ctrl_pt;
struct vsfsm_t video_sm;
//struct vsfsm_t audio_sm;
struct vsfusbh_urb_t ctrl_urb;
struct vsfusbh_urb_t video_urb;
//struct vsfusbh_urb_t audio_urb;
uint8_t *ctrl_urb_buf;
uint8_t *video_urb_buf;
//uint8_t *audio_urb_buf;
struct vsfusbh_uvc_payload_t video_payload;
//struct vsfusbh_uvc_payload_t audio_payload;
struct vsfusbh_uvc_param_t set_param;
struct vsfusbh_uvc_param_t cur_param;
uint16_t video_iso_packet_len;
//uint16_t audio_iso_packet_len;
uint8_t video_iso_ep;
//uint8_t audio_iso_ep;
};
void (*vsfusbh_uvc_report)(void *dev_data, struct vsfusbh_uvc_param_t *param,
struct vsfusbh_uvc_payload_t *payload) = NULL;
static vsf_err_t uvc_init_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
{
vsf_err_t err;
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)pt->user_data;
struct vsfusbh_urb_t *vsfurb = &hdata->ctrl_urb;
vsfsm_pt_begin(pt);
// reset interfaces 1 (video)
vsfurb->transfer_buffer = NULL;
vsfurb->transfer_length = 0;
err = vsfusbh_set_interface(hdata->usbh, vsfurb, 1, 0);
if (err != VSFERR_NONE)
return err;
vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE);
if (vsfurb->status != URB_OK)
return VSFERR_FAIL;
vsfsm_pt_end(pt);
return VSFERR_NONE;
}
static struct vsfsm_state_t *uvc_evt_handler_init(struct vsfsm_t *sm,
vsfsm_evt_t evt)
{
vsf_err_t err;
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)sm->user_data;
switch (evt)
{
case VSFSM_EVT_INIT:
case VSFSM_EVT_URB_COMPLETE:
case VSFSM_EVT_DELAY_DONE:
err = hdata->init_pt.thread(&hdata->init_pt, evt);
if (err < 0)
{
// TODO
}
else if (err == 0)
{
hdata->ctrl_urb.sm = &hdata->ctrl_sm;
if (vsfusbh_uvc_report)
vsfusbh_uvc_report(hdata, &hdata->cur_param, NULL);
}
break;
default:
break;
}
return NULL;
}
const uint8_t negotiate_temp[26] =
{
0x00, 0x00, 0x01, 0x03, 0x15, 0x16, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
static vsf_err_t uvc_ctrl_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
{
vsf_err_t err;
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)pt->user_data;
struct vsfusbh_urb_t *vsfurb = &hdata->ctrl_urb;
vsfsm_pt_begin(pt);
if (hdata->set_param.video_enable)
{
// negotiate
hdata->video_iso_packet_len = 1024;
hdata->video_iso_ep = 1;
// commit param
vsfurb->transfer_buffer = hdata->ctrl_urb_buf;
memcpy(vsfurb->transfer_buffer, negotiate_temp, 26);
vsfurb->transfer_length = 26;
vsfurb->pipe = usb_sndctrlpipe(vsfurb->vsfdev, 0);
err = vsfusbh_control_msg(hdata->usbh, vsfurb,
USB_TYPE_CLASS |USB_RECIP_INTERFACE | USB_DIR_OUT, SET_CUR,
0x0200, 0x0001);
if (err != VSFERR_NONE)
return err;
vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE);
if (vsfurb->status != URB_OK)
return VSFERR_FAIL;
// set interfaces
vsfurb->transfer_buffer = NULL;
vsfurb->transfer_length = 0;
err = vsfusbh_set_interface(hdata->usbh, vsfurb, 1, 4);
if (err != VSFERR_NONE)
return err;
vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE);
if (vsfurb->status != URB_OK)
return VSFERR_FAIL;
// enable video
vsfsm_post_evt_pending(&hdata->video_sm, UAV_ISO_ENABLE);
}
else
{
vsfurb->transfer_buffer = NULL;
vsfurb->transfer_length = 0;
err = vsfusbh_set_interface(hdata->usbh, vsfurb, 1, 0);
if (err != VSFERR_NONE)
return err;
vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE);
if (vsfurb->status != URB_OK)
return VSFERR_FAIL;
}
vsf_bufmgr_free(hdata->ctrl_urb_buf);
hdata->ctrl_urb_buf = NULL;
memcpy(&hdata->cur_param, &hdata->set_param,
sizeof(struct vsfusbh_uvc_param_t));
vsfusbh_uvc_report(hdata, &hdata->cur_param, NULL);
vsfsm_pt_end(pt);
return VSFERR_NONE;
}
static struct vsfsm_state_t *uvc_evt_handler_ctrl(struct vsfsm_t *sm,
vsfsm_evt_t evt)
{
vsf_err_t err;
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)sm->user_data;
switch (evt)
{
case VSFSM_EVT_INIT:
break;
case UAV_RESET_STREAM_PARAM:
hdata->ctrl_pt.state = 0;
if (hdata->ctrl_urb_buf == NULL)
{
hdata->ctrl_urb_buf = vsf_bufmgr_malloc(UVC_PROBE_CRTL_DATA_SIZE);
if (hdata->ctrl_urb_buf == NULL)
return NULL;
}
case VSFSM_EVT_URB_COMPLETE:
case VSFSM_EVT_DELAY_DONE:
err = hdata->ctrl_pt.thread(&hdata->ctrl_pt, evt);
if (err < 0)
{
// TODO
vsf_bufmgr_free(hdata->ctrl_urb_buf);
hdata->ctrl_urb_buf = NULL;
}
else if (err == 0)
{
vsf_bufmgr_free(hdata->ctrl_urb_buf);
hdata->ctrl_urb_buf = NULL;
}
break;
default:
break;
}
return NULL;
}
static struct vsfsm_state_t *uvc_evt_handler_video(struct vsfsm_t *sm,
vsfsm_evt_t evt)
{
vsf_err_t err;
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)sm->user_data;
struct vsfusbh_t *usbh = hdata->usbh;
struct vsfusbh_urb_t *vsfurb = &hdata->video_urb;
switch (evt)
{
case VSFSM_EVT_INIT:
break;
case UAV_ISO_ENABLE:
if (hdata->video_urb_buf == NULL)
{
vsfurb->vsfdev->epmaxpacketin[hdata->video_iso_ep] = hdata->video_iso_packet_len;
hdata->video_urb_buf = vsf_bufmgr_malloc(hdata->video_iso_packet_len);
if (hdata->video_urb_buf == NULL)
return NULL;
vsfurb->transfer_buffer = hdata->video_urb_buf;
vsfurb->transfer_length = hdata->video_iso_packet_len;
vsfurb->pipe = usb_rcvisocpipe(vsfurb->vsfdev, hdata->video_iso_ep);
vsfurb->transfer_flags |= USB_ISO_ASAP;
vsfurb->number_of_packets = 1;
vsfurb->iso_frame_desc[0].offset = 0;
vsfurb->iso_frame_desc[0].length = hdata->video_iso_packet_len;
err = vsfusbh_submit_urb(usbh, vsfurb);
if (err != VSFERR_NONE)
goto error;
}
break;
case UAV_ISO_DISABLE:
// TODO
break;
case VSFSM_EVT_URB_COMPLETE:
if (vsfurb->status == URB_OK)
{
hdata->video_payload.len = vsfurb->actual_length;
vsfusbh_uvc_report(hdata, &hdata->cur_param, &hdata->video_payload);
}
else
{
goto error;
}
err = vsfusbh_relink_urb(usbh, vsfurb);
if (err != VSFERR_NONE)
goto error;
break;
default:
break;
}
return NULL;
error:
vsf_bufmgr_free(hdata->video_urb_buf);
hdata->video_urb_buf = NULL;
return NULL;
}
static void *vsfusbh_uvc_init(struct vsfusbh_t *usbh, struct vsfusbh_device_t *dev)
{
struct vsfusbh_class_data_t *cdata;
struct vsfusbh_uvc_t *hdata;
cdata = vsf_bufmgr_malloc(sizeof(struct vsfusbh_class_data_t));
if (NULL == cdata)
return NULL;
hdata = vsf_bufmgr_malloc(sizeof(struct vsfusbh_uvc_t));
if (NULL == hdata)
{
vsf_bufmgr_free(cdata);
return NULL;
}
memset(cdata, 0, sizeof(struct vsfusbh_class_data_t));
memset(hdata, 0, sizeof(struct vsfusbh_uvc_t));
cdata->dev = dev;
hdata->dev = dev;
hdata->usbh = usbh;
cdata->param = hdata;
hdata->video_payload.type = VSFUSBH_UVC_PAYLOAD_VIDEO;
hdata->video_payload.buf = hdata->video_urb_buf;
hdata->init_sm.init_state.evt_handler = uvc_evt_handler_init;
hdata->init_sm.user_data = (void*)hdata;
hdata->init_pt.thread = uvc_init_thread;
hdata->init_pt.user_data = hdata;
hdata->init_pt.sm = &hdata->init_sm;
hdata->init_pt.state = 0;
hdata->ctrl_sm.init_state.evt_handler = uvc_evt_handler_ctrl;
hdata->ctrl_sm.user_data = (void*)hdata;
hdata->ctrl_pt.thread = uvc_ctrl_thread;
hdata->ctrl_pt.user_data = hdata;
hdata->ctrl_pt.sm = &hdata->ctrl_sm;
hdata->ctrl_pt.state = 0;
hdata->ctrl_urb.vsfdev = dev;
hdata->ctrl_urb.timeout = 200;
hdata->ctrl_urb.sm = &hdata->init_sm;
hdata->video_sm.init_state.evt_handler = uvc_evt_handler_video;
hdata->video_sm.user_data = (void*)hdata;
hdata->video_urb.vsfdev = dev;
hdata->video_urb.timeout = 200;
hdata->video_urb.sm = &hdata->video_sm;
vsfsm_init(&hdata->init_sm);
vsfsm_init(&hdata->ctrl_sm);
vsfsm_init(&hdata->video_sm);
return cdata;
}
static vsf_err_t vsfusbh_uvc_match(struct vsfusbh_device_t *dev)
{
if ((dev->descriptor.idVendor == 0x04f2) &&
(dev->descriptor.idProduct == 0xb130))
{
return VSFERR_NONE;
}
return VSFERR_FAIL;
}
static void vsfusbh_uvc_free(struct vsfusbh_device_t *dev)
{
struct vsfusbh_class_data_t *cdata = (struct vsfusbh_class_data_t *)(dev->priv);
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)cdata->param;
// TODO
// free urb
vsf_bufmgr_free(hdata);
vsf_bufmgr_free(cdata);
}
const struct vsfusbh_class_drv_t vsfusbh_uvc_drv = {
vsfusbh_uvc_init,
vsfusbh_uvc_free,
vsfusbh_uvc_match,
};
vsf_err_t vsfusbh_uvc_set(void *dev_data, struct vsfusbh_uvc_param_t *param)
{
struct vsfusbh_uvc_t *hdata = (struct vsfusbh_uvc_t *)dev_data;
hdata->set_param = *param;
vsfsm_post_evt_pending(&hdata->ctrl_sm, UAV_RESET_STREAM_PARAM);
return VSFERR_NONE;
}