13、USBH composite类支持(CDC+MSC)

USBH composite类编写

ST的USBH库支持复合设备,但是需要用户针对复合设备编写自定义符合类处理函数.

1.准备工作

明确复合设备是哪几个类构成,以CDC+MSC为例.

使用CUBEMX生成USBH支持ALL CLASS的工程.

2.修改

2.1.接口修改

打开usbh_conf,h文件,根据支持设备的设备属性(描述符)修改及添加以下内容.

/*修改内容*/

/*----------单个类支持的最大端点数(复合设备取最大值)-----------*/
#define USBH_MAX_NUM_ENDPOINTS      3U

/*----------单个类支持最大接口数(复合设备取最大值)-----------*/
#define USBH_MAX_NUM_INTERFACES      1U

/*----------最大支持类的数量-----------*/
#define USBH_MAX_NUM_SUPPORTED_CLASS      1U

//以上三个参数均需要根据实际支持设备修改

/*根据自己使用库去修改*/
#define USBH_malloc         malloc
#define USBH_free           free
#define USBH_memset         memset
#define USBH_memcpy         memcpy


/*添加内容*/
/*----------   -----------*/
#define USBH_COMPOSITE_CALSS_MAX_NUM      2U

/*----------   -----------*/
#define USBH_CDC_INDEX      0U

/*----------   -----------*/
#define USBH_MSC_INDEX      1U

打开usbh_def.h文件,修改如下内容.

/* USB Host Class structure */
typedef struct
{
  const char          *Name;
  uint8_t              ClassCode;
  USBH_StatusTypeDef(*Init)(struct _USBH_HandleTypeDef *phost);
  USBH_StatusTypeDef(*DeInit)(struct _USBH_HandleTypeDef *phost);
  USBH_StatusTypeDef(*Requests)(struct _USBH_HandleTypeDef *phost);
  USBH_StatusTypeDef(*BgndProcess)(struct _USBH_HandleTypeDef *phost);
  USBH_StatusTypeDef(*SOFProcess)(struct _USBH_HandleTypeDef *phost);
  void                *pData[USBH_COMPOSITE_CALSS_MAX_NUM];
} USBH_ClassTypeDef;

2.2. 类API修改

所有的类修改都遵循如下几步.

  1. 将类管理数据由动态分配变更为静态分配.
  2. 修改类Init函数内类管理结构体部分及寻找接口部分.
  3. 修改Deinit函数内关于类管理接口资源回收部分代码.
  4. 将文件内所有关于获取类结构体的语句同意修正为如下形式.其中索引号即为上述添加的USBH_CDC_INDEX&USBH_MSC_INDEX.
    类管理类型 *Class_Handle = (类管理类型) *) phost->pActiveClass->pData[索引号];
  5. 修改该类的所有文件内的phost->Control.setup.b.wIndex.w赋值语句修改为phost->Control.setup.b.wIndex.w = phost->device.current_interface;.
2.2.1 cdc类修改

打开usbh_cdc.c文件,进行如下修改.

//1. 添加cdc类管理接口及接受缓冲
CDC_HandleTypeDef usbh_cdc_handler;
__align(4) static uint8_t usb_recv_buf[256];

//2. 变更 USBH_CDC_InterfaceInit 为如下内容.
static USBH_StatusTypeDef USBH_CDC_InterfaceInit(USBH_HandleTypeDef *phost)
{

    USBH_StatusTypeDef status;
    uint8_t interface;
    CDC_HandleTypeDef *CDC_Handle;
    /*---------------------------------寻找接口部分 修正为如下----------------------------------*/
    interface = USBH_FindInterface(phost, COMMUNICATION_INTERFACE_CLASS_CODE,
                                       ABSTRACT_CONTROL_MODEL, COMMON_AT_COMMAND);

    if((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES))  /* No Valid Interface */
    {
        USBH_DbgLog("Cannot Find the interface for Communication Interface Class.");
        return USBH_FAIL;
    }

    status = USBH_SelectInterface(phost, interface);

    if(status != USBH_OK)
    {
        return USBH_FAIL;
    }
    /*---------------------------------管理结构体部分 修正为如下----------------------------------*/
    phost->pActiveClass->pData[USBH_CDC_INDEX] = &usbh_cdc_handler;
    CDC_Handle = (CDC_HandleTypeDef *) phost->pActiveClass->pData[USBH_CDC_INDEX];

    if(CDC_Handle == NULL)
    {
        USBH_DbgLog("Cannot allocate memory for CDC Handle");
        return USBH_FAIL;
    }

    /* Initialize cdc handler */
    USBH_memset(CDC_Handle, 0, sizeof(CDC_HandleTypeDef));

    /*Collect the notification endpoint address and length*/
    if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U)
    {
        CDC_Handle->CommItf.NotifEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
        CDC_Handle->CommItf.NotifEpSize  = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
    }

    /*Allocate the length for host channel number in*/
    CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost, CDC_Handle->CommItf.NotifEp);

    /* Open pipe for Notification endpoint */
    USBH_OpenPipe(phost, CDC_Handle->CommItf.NotifPipe, CDC_Handle->CommItf.NotifEp,
                  phost->device.address, phost->device.speed, USB_EP_TYPE_INTR,
                  CDC_Handle->CommItf.NotifEpSize);

    USBH_LL_SetToggle(phost, CDC_Handle->CommItf.NotifPipe, 0U);

    interface = USBH_FindInterface(phost, DATA_INTERFACE_CLASS_CODE,
                                       RESERVED, NO_CLASS_SPECIFIC_PROTOCOL_CODE);

    if((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES))  /* No Valid Interface */
    {
        USBH_DbgLog("Cannot Find the interface for Data Interface Class.");
        return USBH_FAIL;
    }

    /*Collect the class specific endpoint address and length*/
    if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U)
    {
        CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
        CDC_Handle->DataItf.InEpSize  = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
    }
    else
    {
        CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
        CDC_Handle->DataItf.OutEpSize  = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
    }

    if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80U)
    {
        CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
        CDC_Handle->DataItf.InEpSize  = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
    }
    else
    {
        CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
        CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
    }

    /*Allocate the length for host channel number out*/
    CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.OutEp);

    /*Allocate the length for host channel number in*/
    CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.InEp);

    /* Open channel for OUT endpoint */
    USBH_OpenPipe(phost, CDC_Handle->DataItf.OutPipe, CDC_Handle->DataItf.OutEp,
                  phost->device.address, phost->device.speed, USB_EP_TYPE_BULK,
                  CDC_Handle->DataItf.OutEpSize);

    /* Open channel for IN endpoint */
    USBH_OpenPipe(phost, CDC_Handle->DataItf.InPipe, CDC_Handle->DataItf.InEp,
                  phost->device.address, phost->device.speed, USB_EP_TYPE_BULK,
                  CDC_Handle->DataItf.InEpSize);

    USBH_LL_SetToggle(phost, CDC_Handle->DataItf.OutPipe, 0U);
    USBH_LL_SetToggle(phost, CDC_Handle->DataItf.InPipe, 0U);

    CDC_Handle->pRxData = usb_recv_buf;
    USBH_memset(CDC_Handle->pRxData,0,256);
    return USBH_OK;
}
//3. 修改USBH_CDC_InterfaceDeInit为如下内容.
static USBH_StatusTypeDef USBH_CDC_InterfaceDeInit(USBH_HandleTypeDef *phost)
{

    CDC_HandleTypeDef *CDC_Handle = (CDC_HandleTypeDef *) phost->pActiveClass->pData[USBH_CDC_INDEX];

    if(CDC_Handle->CommItf.NotifPipe)
    {
        USBH_ClosePipe(phost, CDC_Handle->CommItf.NotifPipe);
        USBH_FreePipe(phost, CDC_Handle->CommItf.NotifPipe);
        CDC_Handle->CommItf.NotifPipe = 0U;     /* Reset the Channel as Free */
    }

    if(CDC_Handle->DataItf.InPipe)
    {
        USBH_ClosePipe(phost, CDC_Handle->DataItf.InPipe);
        USBH_FreePipe(phost, CDC_Handle->DataItf.InPipe);
        CDC_Handle->DataItf.InPipe = 0U;     /* Reset the Channel as Free */
    }

    if(CDC_Handle->DataItf.OutPipe)
    {
        USBH_ClosePipe(phost, CDC_Handle->DataItf.OutPipe);
        USBH_FreePipe(phost, CDC_Handle->DataItf.OutPipe);
        CDC_Handle->DataItf.OutPipe = 0U;    /* Reset the Channel as Free */
    }
    return USBH_OK;
}
//4. 本文件内所有的(CDC_HandleTypeDef *) phost->pActiveClass->pData 替换为 CDC_HandleTypeDef *CDC_Handle = (CDC_HandleTypeDef *) phost->pActiveClass->pData[USBH_CDC_INDEX]; 

//5. 本文件内所有的 phost->Control.setup.b.wIndex.w赋值语句,全部修改为如下内容.

    phost->Control.setup.b.wIndex.w = phost->device.current_interface;

2.2.2 msc类修改

usbh_msc.c文件修改同上,只是部分修改内容要在usbh_msc_bot.c,usbh_msc_scsi.c文件中.

2.3 copmosite类源文件添加

添加usbh_compostie.c文件,如下所示.


#include "usbh_composite.h"

static USBH_StatusTypeDef USBH_CUSTOM_InterfaceInit(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_CUSTOM_InterfaceDeInit(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_CUSTOM_ClassRequest(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_CUSTOM_SOFProcess(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_CUSTOM_Process(USBH_HandleTypeDef *phost);

static void change_interface(USBH_HandleTypeDef *phost,uint8_t class_code);

static uint8_t cdc_init = 0;

USBH_ClassTypeDef  Composite_Class =
{
    "CUSTOM",
    USB_CUSTOM_COMPOSITE_CLASS,
    USBH_CUSTOM_InterfaceInit,
    USBH_CUSTOM_InterfaceDeInit,
    USBH_CUSTOM_ClassRequest,
    USBH_CUSTOM_Process,
    USBH_CUSTOM_SOFProcess,
    NULL,
};
static USBH_ClassTypeDef *p_cdc_class_handler = USBH_CDC_CLASS;
static USBH_ClassTypeDef *p_msc_class_handler = USBH_MSC_CLASS;

static USBH_StatusTypeDef USBH_CUSTOM_InterfaceInit(USBH_HandleTypeDef *phost)
{
    USBH_StatusTypeDef status;
status = p_cdc_class_handler->Init(phost);
cdc_init = 0;
if(status != USBH_OK)
USBH_UsrLog("cdc init err\n");

if(phost->device.CfgDesc.bNumInterfaces == 3)
{
status = p_msc_class_handler->Init(phost);
if(status != USBH_OK)
USBH_UsrLog("msc init err\n");
}
    return status;
}

static USBH_StatusTypeDef USBH_CUSTOM_InterfaceDeInit(USBH_HandleTypeDef *phost)
{
p_cdc_class_handler->DeInit(phost);

if(phost->device.CfgDesc.bNumInterfaces == 3)
p_msc_class_handler->DeInit(phost);
cdc_init = 0;
    return USBH_OK;
}

static USBH_StatusTypeDef USBH_CUSTOM_ClassRequest(USBH_HandleTypeDef *phost)
{
    USBH_StatusTypeDef status;
    if(!cdc_init)
    {
        change_interface(phost,0);
        status = p_cdc_class_handler->Requests(phost);
        if(status != USBH_OK)
        {
//           USBH_UsrLog("cdc Requests err statu = %d\n",status);
        }
        else
            cdc_init =1;
    }

    if((phost->device.CfgDesc.bNumInterfaces == 3) && (cdc_init == 1))
    {
        change_interface(phost,1);
        status = p_msc_class_handler->Requests(phost);
//        if(status != USBH_OK)
//        USBH_UsrLog("msc Requests err statu = %d\n",status);
    }
    return status;
}


static USBH_StatusTypeDef USBH_CUSTOM_Process(USBH_HandleTypeDef *phost)
{
    USBH_StatusTypeDef status;
    if(phost->device.CfgDesc.bNumInterfaces == 3)
    {
        phost->device.current_interface = 2;
        change_interface(phost,1);
        status = p_msc_class_handler->BgndProcess(phost);
        //if((status != USBH_OK) && (status != USBH_BUSY))
        //USBH_UsrLog("msc BgndProcess err status = %d\n",status);
    }
    phost->device.current_interface = 0;
    change_interface(phost,0);
    status = p_cdc_class_handler->BgndProcess(phost);
    //if((status != USBH_OK) && (status != USBH_BUSY))
    //USBH_UsrLog("cdc BgndProcess err status = %d\n",status);
    return status;
}

static USBH_StatusTypeDef USBH_CUSTOM_SOFProcess(USBH_HandleTypeDef *phost)
{
    UNUSED(phost);

    return USBH_OK;
}

static void change_interface(USBH_HandleTypeDef *phost,uint8_t class_code)
{
    uint8_t interface;
    if(class_code == 0)
        interface = USBH_FindInterface(phost, COMMUNICATION_INTERFACE_CLASS_CODE,ABSTRACT_CONTROL_MODEL, COMMON_AT_COMMAND);
    else
        interface = USBH_FindInterface(phost, USB_MSC_CLASS, MSC_TRANSPARENT, MSC_BOT);

    if((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES))  /* Not Valid Interface */
        USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
    else
    {
        if(USBH_SelectInterface(phost, interface) != USBH_OK)
        {
            USBH_DbgLog("interface num err\r\n");
        }
    }
}

添加usbh_composite.h文件,内容如下所示.

#ifndef __USBD_COMPOSITE_H
#define __USBD_COMPOSITE_H

#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "usbh_cdc.h"
#include "usbh_msc.h"

#define USB_CUSTOM_COMPOSITE_CLASS 0x02U

extern USBH_ClassTypeDef        Composite_Class;
#define USBH_COMPOSITE_CLASS    &Composite_Class



#ifdef __cplusplus
}
#endif

#endif  /* __USBD_MSC_H */

2.3 修改应用接口、

#include "usbh_composite.h"

void MX_USB_HOST_Init()
{
    if(USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS) != USBH_OK)
    {
        Error_Handler();
    }

    if(USBH_RegisterClass(&hUsbHostHS, USBH_COMPOSITE_CLASS) != USBH_OK)
    {
        Error_Handler();
    }

    if(USBH_Start(&hUsbHostHS) != USBH_OK)
    {
        Error_Handler();
    }
}

static void USBH_UserProcess(USBH_HandleTypeDef * phost, uint8_t id)
{
  switch (id)
  {
  case HOST_USER_SELECT_CONFIGURATION:
    break;

  case HOST_USER_DISCONNECTION:

    break;

  case HOST_USER_CLASS_ACTIVE:
    break;

  case HOST_USER_CONNECTION:

    break;

  default:
    break;
  }
}

备注

到这仅支持CDC+MSC类设备枚举,如果要正式使用还需要进行其余修改配合.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值