mirror of https://github.com/rusefi/pcan_pro_x.git
432 lines
13 KiB
C
432 lines
13 KiB
C
#include <assert.h>
|
|
#include "usbd_ctlreq.h"
|
|
#include "usbd_ioreq.h"
|
|
#include "usbd_conf.h"
|
|
#include "usbd_helper.h"
|
|
#include "pcanpro_protocol.h"
|
|
#include "pcanpro_usbd.h"
|
|
#define INCLUDE_LIN_INTERFACE (1)
|
|
|
|
static struct t_class_data pcanpro_data = { 0 };
|
|
|
|
struct t_pcanpro_description
|
|
{
|
|
USB_CONFIGURATION_DESCRIPTOR con0;
|
|
USB_INTERFACE_DESCRIPTOR if0;
|
|
USB_ENDPOINT_DESCRIPTOR ep1_i0;
|
|
USB_ENDPOINT_DESCRIPTOR ep2_i0;
|
|
USB_ENDPOINT_DESCRIPTOR ep3_i0;
|
|
USB_ENDPOINT_DESCRIPTOR ep4_i0;
|
|
USB_ENDPOINT_DESCRIPTOR ep5_i0;
|
|
USB_ENDPOINT_DESCRIPTOR ep6_i0;
|
|
#if INCLUDE_LIN_INTERFACE
|
|
USB_INTERFACE_DESCRIPTOR if1;
|
|
USB_ENDPOINT_DESCRIPTOR ep1_i1;
|
|
USB_ENDPOINT_DESCRIPTOR ep2_i1;
|
|
USB_ENDPOINT_DESCRIPTOR ep3_i1;
|
|
USB_ENDPOINT_DESCRIPTOR ep4_i1;
|
|
USB_ENDPOINT_DESCRIPTOR ep5_i1;
|
|
USB_ENDPOINT_DESCRIPTOR ep6_i1;
|
|
#endif
|
|
};
|
|
|
|
#if defined ( __ICCARM__ )
|
|
#pragma data_alignment=4
|
|
#endif
|
|
__ALIGN_BEGIN static const USB_DEVICE_QUALIFIER_DESCRIPTOR dev_qua __ALIGN_END =
|
|
{
|
|
.bLength = sizeof( USB_DEVICE_QUALIFIER_DESCRIPTOR ),
|
|
.bDescriptorType = USB_QUALIFIER_DESCRIPTOR_TYPE,
|
|
.bcdUSB = 0x0200, /* 2.0 */
|
|
.bDeviceClass = 0,
|
|
.bDeviceSubClass = 0,
|
|
.bDeviceProtocol = 0,
|
|
.bMaxPacketSize0 = 64,
|
|
.bNumConfigurations = 1,
|
|
.bReserved = 0,
|
|
};
|
|
|
|
|
|
#if defined ( __ICCARM__ )
|
|
#pragma data_alignment=4
|
|
#endif
|
|
__ALIGN_BEGIN static struct t_pcanpro_description pcanpro_dev __ALIGN_END =
|
|
{
|
|
.con0 =
|
|
{
|
|
.bLength = sizeof( USB_CONFIGURATION_DESCRIPTOR ),
|
|
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
.wTotalLength = sizeof( struct t_pcanpro_description ),
|
|
#if INCLUDE_LIN_INTERFACE
|
|
.bNumInterfaces = 2,
|
|
#else
|
|
.bNumInterfaces = 1,
|
|
#endif
|
|
.bConfigurationValue = 1,
|
|
.iConfiguration = 4,
|
|
.bmAttributes = USB_CONFIG_BUS_POWERED,
|
|
.MaxPower = 120, /* = 240mA */
|
|
},
|
|
/* CAN INTERFACE */
|
|
.if0 =
|
|
{
|
|
.bLength = sizeof( USB_INTERFACE_DESCRIPTOR ),
|
|
.bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE,
|
|
.bInterfaceNumber = 0,
|
|
.bAlternateSetting = 0,
|
|
.bNumEndpoints = 6,
|
|
.bInterfaceClass = 0,
|
|
.bInterfaceSubClass = 0,
|
|
.bInterfaceProtocol = 0,
|
|
.iInterface = 5,
|
|
},
|
|
.ep1_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_CMDIN,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep2_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_CMDOUT,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep3_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_MSGIN_CH1,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep4_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_MSGOUT_CH1,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep5_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_MSGIN_CH2, /* not used */
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep6_i0 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = PCAN_USB_EP_MSGOUT_CH2,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
#if INCLUDE_LIN_INTERFACE
|
|
/* LIN INTERFACE */
|
|
.if1 =
|
|
{
|
|
.bLength = sizeof( USB_INTERFACE_DESCRIPTOR ),
|
|
.bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE,
|
|
.bInterfaceNumber = 1,
|
|
.bAlternateSetting = 0,
|
|
.bNumEndpoints = 6,
|
|
.bInterfaceClass = 0,
|
|
.bInterfaceSubClass = 0,
|
|
.bInterfaceProtocol = 0,
|
|
.iInterface = 6,
|
|
},
|
|
.ep1_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x84,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep2_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x04,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep3_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x85,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep4_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x05,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep5_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x86,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
},
|
|
.ep6_i1 =
|
|
{
|
|
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
|
|
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
|
|
.bEndpointAddress = 0x06,
|
|
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
|
|
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
|
|
.bInterval = 0,
|
|
}
|
|
#endif
|
|
};
|
|
|
|
static uint8_t device_init( USBD_HandleTypeDef *pdev, uint8_t cfgidx )
|
|
{
|
|
USB_ENDPOINT_DESCRIPTOR *p_ep = &pcanpro_dev.ep1_i0;
|
|
|
|
for( int i = 0; i < pcanpro_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 )
|
|
p_ep[i].wMaxPacketSize = PCAN_FS_MAX_BULK_PACKET_SIZE;
|
|
else if( pdev->dev_speed == USBD_SPEED_HIGH )
|
|
p_ep[i].wMaxPacketSize = PCAN_HS_MAX_BULK_PACKET_SIZE;
|
|
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*)&pcanpro_data;
|
|
|
|
|
|
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_CMDOUT, pcanpro_data.cmd_ep_buffer, sizeof( pcanpro_data.cmd_ep_buffer ) );
|
|
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_MSGOUT_CH1, pcanpro_data.data1_ep_buffer, sizeof( pcanpro_data.data1_ep_buffer ) );
|
|
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_MSGOUT_CH2, pcanpro_data.data2_ep_buffer, sizeof( pcanpro_data.data2_ep_buffer ) );
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
static uint8_t device_deinit( USBD_HandleTypeDef *pdev, uint8_t cfgidx )
|
|
{
|
|
USB_ENDPOINT_DESCRIPTOR const *p_ep = &pcanpro_dev.ep1_i0;
|
|
|
|
for( int i = 0; i < pcanpro_dev.if0.bNumEndpoints; i++ )
|
|
{
|
|
uint8_t ep_addr = p_ep[i].bEndpointAddress;
|
|
USBD_LL_FlushEP( pdev, ep_addr );
|
|
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;
|
|
PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
|
|
USB_DevDisconnect( hpcd->Instance );
|
|
HAL_Delay( 250 );
|
|
USB_DevConnect( hpcd->Instance );
|
|
return USBD_OK;
|
|
}
|
|
|
|
static uint8_t device_setup( USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req )
|
|
{
|
|
switch( req->bmRequest & USB_REQ_TYPE_MASK )
|
|
{
|
|
case USB_REQ_TYPE_VENDOR:
|
|
return pcan_protocol_device_setup( pdev, req );
|
|
case USB_REQ_TYPE_CLASS:
|
|
return USBD_OK;
|
|
case USB_REQ_TYPE_STANDARD:
|
|
return USBD_OK;
|
|
default:
|
|
USBD_CtlError( pdev, req );
|
|
return USBD_FAIL;
|
|
}
|
|
}
|
|
|
|
static uint8_t device_ep0_rx_ready( USBD_HandleTypeDef *pdev )
|
|
{
|
|
pcan_ep0_receive();
|
|
return USBD_OK;
|
|
}
|
|
|
|
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 1
|
|
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 ) == 0U )
|
|
{
|
|
/* update the packet total length */
|
|
pdev->ep_in[epnum].total_length = 0U;
|
|
/* send ZLP */
|
|
USBD_LL_Transmit( pdev, epnum, NULL, 0U );
|
|
}
|
|
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;
|
|
|
|
}
|
|
|
|
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 );
|
|
|
|
if( epnum == PCAN_USB_EP_CMDOUT )
|
|
{
|
|
pcan_protocol_process_data( epnum, pcanpro_data.cmd_ep_buffer, size );
|
|
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.cmd_ep_buffer, sizeof( pcanpro_data.cmd_ep_buffer ) );
|
|
}
|
|
else if( epnum == PCAN_USB_EP_MSGOUT_CH1 )
|
|
{
|
|
pcan_protocol_process_data( epnum, pcanpro_data.data1_ep_buffer, size );
|
|
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.data1_ep_buffer, sizeof( pcanpro_data.data1_ep_buffer ) );
|
|
}
|
|
else if( epnum == PCAN_USB_EP_MSGOUT_CH2 )
|
|
{
|
|
pcan_protocol_process_data( epnum, pcanpro_data.data2_ep_buffer, size );
|
|
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.data2_ep_buffer, sizeof( pcanpro_data.data2_ep_buffer ) );
|
|
}
|
|
else
|
|
{
|
|
return USBD_FAIL;
|
|
}
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
static uint8_t *device_get_hs_cfg( uint16_t *length )
|
|
{
|
|
*length = sizeof( struct t_pcanpro_description );
|
|
return (void*)&pcanpro_dev;
|
|
}
|
|
|
|
static uint8_t *device_get_fs_cfg( uint16_t *length )
|
|
{
|
|
*length = sizeof( struct t_pcanpro_description );
|
|
return (void*)&pcanpro_dev;
|
|
}
|
|
|
|
static uint8_t *device_get_other_speed_cfg( uint16_t *length )
|
|
{
|
|
*length = sizeof( struct t_pcanpro_description );
|
|
return (void*)&pcanpro_dev;
|
|
}
|
|
|
|
uint8_t *device_get_device_qualifier( uint16_t *length )
|
|
{
|
|
*length = sizeof( USB_DEVICE_QUALIFIER_DESCRIPTOR );
|
|
|
|
return (void*)&dev_qua;
|
|
}
|
|
|
|
static uint8_t sof_handler( struct _USBD_HandleTypeDef *pdev )
|
|
{
|
|
uint32_t USBx_BASE = (uint32_t)(((PCD_HandleTypeDef *)pdev->pData)->Instance);
|
|
(void)USBx_BASE;
|
|
|
|
//vn_data_handler_sof( (USBx_DEVICE->DSTS>>8u)&0x3FFFu );
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
static uint8_t *device_get_user_string( USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length )
|
|
{
|
|
__ALIGN_BEGIN static uint8_t USBD_StrDesc[64] __ALIGN_END;
|
|
|
|
UNUSED( pdev );
|
|
|
|
switch( index )
|
|
{
|
|
case 6:
|
|
#if PCAN_FD
|
|
USBD_GetString((uint8_t *)"PCAN-USB Pro FD LIN", USBD_StrDesc, length );
|
|
#else
|
|
USBD_GetString((uint8_t *)"PCAN-USB-PRO LIN Device", USBD_StrDesc, length );
|
|
#endif
|
|
break;
|
|
default:
|
|
USBD_GetString((uint8_t *)"UNHANDLED", USBD_StrDesc, length );
|
|
break;
|
|
}
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
USBD_ClassTypeDef usbd_pcanpro =
|
|
{
|
|
.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 = sof_handler,
|
|
.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
|
|
};
|