文章目录
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修改
所有的类修改都遵循如下几步.
- 将类管理数据由动态分配变更为静态分配.
- 修改类Init函数内类管理结构体部分及寻找接口部分.
- 修改Deinit函数内关于类管理接口资源回收部分代码.
- 将文件内所有关于获取类结构体的语句同意修正为如下形式.其中索引号即为上述添加的
USBH_CDC_INDEX
&USBH_MSC_INDEX
.
类管理类型 *Class_Handle = (类管理类型) *) phost->pActiveClass->pData[索引号];
- 修改该类的所有文件内的
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类设备枚举,如果要正式使用还需要进行其余修改配合.