pcan_cantact_another_one/Src/pcan_usb.c

413 lines
12 KiB
C

#include "pcan_usb.h"
#include "pcan_led.h"
#include "pcan_protocol.h"
#include "usbd_conf.h"
#include "usbd_ctlreq.h"
#include "usbd_helper.h"
#include "usbd_ioreq.h"
#include <assert.h>
#include <stm32f0xx_hal.h>
USBD_HandleTypeDef hUsbDeviceFS;
extern USBD_DescriptorsTypeDef FS_Desc;
static struct t_class_data pcan_data = { 0 };
struct t_pcan_description
{
USB_CONFIGURATION_DESCRIPTOR con0;
USB_INTERFACE_DESCRIPTOR if0;
USB_ENDPOINT_DESCRIPTOR ep1;
USB_ENDPOINT_DESCRIPTOR ep2;
USB_ENDPOINT_DESCRIPTOR ep3;
USB_ENDPOINT_DESCRIPTOR ep4;
};
__ALIGN_BEGIN static const USB_DEVICE_QUALIFIER_DESCRIPTOR dev_qua __ALIGN_END = {
.bLength = sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR),
.bDescriptorType = USB_QUALIFIER_DESCRIPTOR_TYPE,
.bcdUSB = 0x0100, /* 1.0 */
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.bNumConfigurations = 1,
.bReserved = 0,
};
__ALIGN_BEGIN static struct t_pcan_description pcan_usb_dev __ALIGN_END =
{
.con0 =
{
.bLength = sizeof( USB_CONFIGURATION_DESCRIPTOR ),
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE,
.wTotalLength = sizeof( struct t_pcan_description ),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = USB_CONFIG_BUS_POWERED,
.MaxPower = 100, /* = 200mA */
},
.if0 =
{
.bLength = sizeof( USB_INTERFACE_DESCRIPTOR ),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 4,
.bInterfaceClass = 0,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.ep1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_CMDIN, /* PC IN cmd resp */
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 16,
.bInterval = 0,
},
.ep2 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_CMDOUT, /* PC OUT cmd */
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 16,
.bInterval = 0,
},
.ep3 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGIN, /* PC IN frames */
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,
.bInterval = 0,
},
.ep4 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGOUT,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,/* PC OUT frames */
.wMaxPacketSize = 64,
.bInterval = 0,
},
};
static uint8_t device_init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USB_ENDPOINT_DESCRIPTOR *p_ep = &pcan_usb_dev.ep1;
UNUSED(cfgidx);
for (int i = 0; i < pcan_usb_dev.if0.bNumEndpoints; i++)
{
uint8_t ep_addr = p_ep[i].bEndpointAddress;
if (p_ep[i].bmAttributes == USB_ENDPOINT_TYPE_BULK)
{
if (pdev->dev_speed == USBD_SPEED_FULL)
;
else if (pdev->dev_speed == USBD_SPEED_HIGH)
;
else
assert(0);
}
USBD_LL_OpenEP(pdev, ep_addr, p_ep[i].bmAttributes, p_ep[i].wMaxPacketSize);
if ((ep_addr & 0x80) != 0)
pdev->ep_in[ep_addr & EP_ADDR_MSK].is_used = 1;
else
pdev->ep_out[ep_addr & EP_ADDR_MSK].is_used = 1;
}
pdev->pClassData = (void *)&pcan_data;
USBD_LL_PrepareReceive(pdev, PCAN_USB_EP_CMDOUT, pcan_data.buffer_cmd, sizeof(pcan_data.buffer_cmd));
USBD_LL_PrepareReceive(pdev, PCAN_USB_EP_MSGOUT, pcan_data.buffer_data, sizeof(pcan_data.buffer_data));
return USBD_OK;
}
static uint8_t device_deinit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USB_ENDPOINT_DESCRIPTOR const *p_ep = &pcan_usb_dev.ep1;
UNUSED(cfgidx);
for (int i = 0; i < pcan_usb_dev.if0.bNumEndpoints; i++)
{
uint8_t ep_addr = p_ep[i].bEndpointAddress;
USBD_LL_CloseEP(pdev, ep_addr);
if ((ep_addr & 0x80) != 0)
pdev->ep_in[ep_addr & EP_ADDR_MSK].is_used = 0;
else
pdev->ep_out[ep_addr & EP_ADDR_MSK].is_used = 0;
}
pdev->pClassData = (void *)0;
return USBD_OK;
}
uint16_t pcan_usb_send_command_buffer(const void *p, uint16_t size)
{
USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
if (pdev->ep_in[PCAN_USB_EP_CMDIN & 0xFU].total_length)
return 0;
pdev->ep_in[PCAN_USB_EP_CMDIN & 0xFU].total_length = size;
if (USBD_LL_Transmit(pdev, PCAN_USB_EP_CMDIN, (void *)p, size) == USBD_OK)
return size;
return 0;
}
uint16_t pcan_usb_send_data_buffer(const void *p, uint16_t size)
{
USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
if (pdev->ep_in[PCAN_USB_EP_MSGIN & 0xFU].total_length)
return 0;
pdev->ep_in[PCAN_USB_EP_MSGIN & 0xFU].total_length = size;
if (USBD_LL_Transmit(pdev, PCAN_USB_EP_MSGIN, (void *)p, size) == USBD_OK)
return size;
return 0;
}
void pcan_usb_poll(void)
{
HAL_PCD_IRQHandler(&hpcd_USB_FS);
}
static uint8_t device_setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
switch (req->bRequest)
{
/* get info */
case 0:
switch (req->wValue)
{
case 0: /* bootloader info */
{
static const uint8_t bootloader_info[] = { 0x00, 0x00, 0x08, 0x04, 0x00, 0x08, 0x07, 0x00, 0x04, 0x02, 0xe0, 0x07, 0x01, 0x00, 0x00, 0x00 };
USBD_CtlSendData(pdev, (void *)bootloader_info, sizeof(bootloader_info));
pcan_led_set_mode(LED_CH0_RX, LED_MODE_ON, 0);
pcan_led_set_mode(LED_CH0_TX, LED_MODE_ON, 0);
/* reset endpoints */
pcan_flush_ep(PCAN_USB_EP_MSGIN);
pcan_flush_ep(PCAN_USB_EP_CMDIN);
}
break;
}
break;
}
return USBD_OK;
}
static uint8_t device_ep0_rx_ready(USBD_HandleTypeDef *pdev)
{
UNUSED(pdev);
return USBD_OK;
}
/* data was sent to PC */
static uint8_t device_data_in(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
struct t_class_data *p_data = (void *)pdev->pClassData;
if (pdev->pClassData == 0)
return USBD_FAIL;
/* use ZLP */
#if 0
PCD_HandleTypeDef *hpcd = pdev->pData;
uint32_t len = pdev->ep_in[epnum].total_length;
/* packet is multiple of maxpacket, so tell host what all transfer is done */
if( len && ( len % hpcd->IN_ep[epnum].maxpacket ) == 0 )
{
/* update the packet total length */
pdev->ep_in[epnum].total_length = 0;
/* send ZLP */
if( !p_data->ep_tx_data_pending[epnum] )
{
USBD_LL_Transmit( pdev, epnum, NULL, 0 );
}
else
{
p_data->ep_tx_in_use[epnum] = 0;
}
}
else
{
/* tx done, no active transfer */
p_data->ep_tx_in_use[epnum] = 0;
}
#else
pdev->ep_in[epnum].total_length = 0U;
p_data->ep_tx_in_use[epnum] = 0;
#endif
return USBD_OK;
}
/* data was received from PC */
static uint8_t device_data_out(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
int size;
if (pdev->pClassData == 0)
return USBD_FAIL;
size = USBD_LL_GetRxDataSize(pdev, epnum);
(void)size;
if (epnum == PCAN_USB_EP_CMDOUT)
{
pcan_protocol_process_command(pcan_data.buffer_cmd, size);
USBD_LL_PrepareReceive(pdev, PCAN_USB_EP_CMDOUT, pcan_data.buffer_cmd, sizeof(pcan_data.buffer_cmd));
}
else if (epnum == PCAN_USB_EP_MSGOUT)
{
pcan_protocol_process_data(pcan_data.buffer_data, size);
USBD_LL_PrepareReceive(pdev, PCAN_USB_EP_MSGOUT, pcan_data.buffer_data, sizeof(pcan_data.buffer_data));
}
else
{
return USBD_FAIL;
}
return USBD_OK;
}
static uint8_t *device_get_hs_cfg(uint16_t *length)
{
*length = sizeof(struct t_pcan_description);
return (void *)&pcan_usb_dev;
}
static uint8_t *device_get_fs_cfg(uint16_t *length)
{
*length = sizeof(struct t_pcan_description);
return (void *)&pcan_usb_dev;
}
static uint8_t *device_get_other_speed_cfg(uint16_t *length)
{
*length = sizeof(struct t_pcan_description);
return (void *)&pcan_usb_dev;
}
static uint8_t *device_get_device_qualifier(uint16_t *length)
{
*length = sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR);
return (void *)&dev_qua;
}
static uint8_t *device_get_user_string(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
{
UNUSED(pdev);
if (index == 10)
{
__ALIGN_BEGIN static const uint16_t vendor_descriptor[1 + 24] __ALIGN_END = { 0x0332, 'P', 'E', 'A', 'K', '-', 'S', 'y', 's', 't', 'e', 'm', ' ',
'T', 'e', 'c', 'h', 'n', 'i', 'k', ' ', 'G', 'm', 'b', 'H' };
*length = sizeof(vendor_descriptor);
return (uint8_t *)vendor_descriptor;
}
return 0;
}
USBD_ClassTypeDef usbd_pcan = {
.Init = device_init,
.DeInit = device_deinit,
.Setup = device_setup,
.EP0_TxSent = 0,
.EP0_RxReady = device_ep0_rx_ready,
.DataIn = device_data_in,
.DataOut = device_data_out,
.SOF = 0,
.IsoINIncomplete = 0,
.IsoOUTIncomplete = 0,
.GetHSConfigDescriptor = device_get_hs_cfg,
.GetFSConfigDescriptor = device_get_fs_cfg,
.GetOtherSpeedConfigDescriptor = device_get_other_speed_cfg,
.GetDeviceQualifierDescriptor = device_get_device_qualifier,
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
.GetUsrStrDescriptor = device_get_user_string,
#endif
};
void pcan_usb_init(void)
{
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
assert(0);
}
if (USBD_RegisterClass(&hUsbDeviceFS, &usbd_pcan) != USBD_OK)
{
assert(0);
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
assert(0);
}
}
int pcan_flush_ep(uint8_t ep)
{
USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
struct t_class_data *p_data = (void *)pdev->pClassData;
p_data->ep_tx_in_use[ep & 0x0F] = 0;
return USBD_LL_FlushEP(pdev, ep) == USBD_OK;
}
int pcan_flush_data(struct t_m2h_fsm *pfsm, void *src, int size)
{
USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
struct t_class_data *p_data = (void *)pdev->pClassData;
if (!p_data)
return 0;
switch (pfsm->state)
{
case 1:
if (p_data->ep_tx_in_use[pfsm->ep_addr & 0x0F])
{
p_data->ep_tx_data_pending[pfsm->ep_addr & 0x0F] = size;
return 0;
}
pfsm->state = 0;
/* fall through */
case 0:
assert(p_data->ep_tx_in_use[pfsm->ep_addr & 0x0F] == 0);
if (size > pfsm->dbsize)
break;
memcpy(pfsm->pdbuf, src, size);
p_data->ep_tx_in_use[pfsm->ep_addr & 0x0F] = 1;
/* prepare data transmit */
pdev->ep_in[pfsm->ep_addr & EP_ADDR_MSK].total_length = size;
/* no pending data */
p_data->ep_tx_data_pending[pfsm->ep_addr & 0x0F] = 0;
USBD_LL_Transmit(pdev, pfsm->ep_addr, pfsm->pdbuf, size);
pfsm->total_tx += size;
pfsm->state = 1;
return 1;
}
return 0;
}