たとえば送受信の場合に何が呼び出されるか? というと、10回目に示したUSBD_CDC_cbの定義の方が使われるようだ。だから、受信時にはusbd_cdc_DataIn()が、送信時にはusbd_cdc_DataOut()がそれぞれ呼び出される形となる。これらの関数を定義しているusbd_cdc_core.cはUSBのCDC ClassのDriverなのでここに手を入れることはできないが、冒頭のコメントに、
@note
For the Abstract Control Model, this core allows only transmitting the
requests to lower layer dispatcher (ie. usbd_cdc_vcp.c/.h) which should
manage each request and perform relative actions.
といった記載がある(改行位置をちょっといじってます)。調べてみると、
extern CDC_IF_Prop_TypeDef APP_FOPS;
という宣言があり、たとえば初期化のusbd_cdc_Init()の中には、
APP_FOPS.pIf_Init();
といった形でこのAPP_FOPSの中の関数を呼び出している。usbd_cdc_DataIn()そのものはこのAPP_FOPS内の関数を呼び出していないが、読み込みなら全データを読み込んだあとに呼び出されるusbd_cdc_EP0_RxReady()は、
/**
* @brief usbd_cdc_EP0_RxReady
* Data received on control endpoint
* @param pdev: device device instance
* @retval status
*/
static uint8_t usbd_cdc_EP0_RxReady (void *pdev)
{
if (cdcCmd != NO_CMD)
{
/* Process the data */
APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen);
/* Reset the command variable to default value */
cdcCmd = NO_CMD;
}
return USBD_OK;
}
といった具合に、APP_FOPS.pIF_Ctrl()という関数を呼んでいるし、usbd_cdc_DataOut()の方は、
/**
* @brief usbd_cdc_DataOut
* Data received on non-control Out endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
static uint8_t usbd_cdc_DataOut (void *pdev, uint8_t epnum)
{
uint16_t USB_Rx_Cnt;
/* Get the received data buffer and update the counter */
USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
/* USB data will be immediately processed, this allow next USB traffic being
NAKed till the end of the application Xfer */
APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt);
/* Prepare Out endpoint to receive next packet */
DCD_EP_PrepareRx(pdev,
CDC_OUT_EP,
(uint8_t*)(USB_Rx_Buffer),
CDC_DATA_OUT_PACKET_SIZE);
return USBD_OK;
}
てな具合でAPP_FOPS.pIf_DataRx()を呼び出している。
このusbd_cdc_core.cでextern宣言で参照しているAPP_FOPSの実体は? というと、usbd_conf.hで宣言している、
#define APP_FOPS VCP_fops
である。このVCP_fopsは? というと、usb_cdc_vcp.cの中で、
CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,
VCP_DeInit,
VCP_Ctrl,
VCP_DataTx,
VCP_DataRx
};
という宣言がある。やっとここでVCP Driverにたどりついたわけだ。
ではこのVCP Driverは何をやっているか? たとえばVCP_DataRx()は
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
uint32_t i;
for (i = 0; i < Len; i++)
{
USART_SendData(EVAL_COM1, *(Buf + i) );
while(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
}
return USBD_OK;
}
となっていて、なにやらUSARTと絡んでいる。で、ここでマニュアルを見てみることにする。STM32F105xx, STM32F107xx, STM32F2xx and STM32F4xx USB On-The-Go host and device library User manual(UM1021)には、こんな図が掲載されている(Photo01)。要するにVCP Driverの中でUSARTとUSBの間でデータのやり取りをしているわけだ。今回の目的では別にUSARTとデータ交換する必要はないので、ここに手をいれればPC側とUSBで通信ができそうだ。
(続く)