respond to config requests

This commit is contained in:
Hubert Denkmair 2016-04-08 10:52:40 +02:00
parent e3a2a26851
commit 5d44a5e026
4 changed files with 260 additions and 114 deletions

View File

@ -2,5 +2,6 @@
#include "usbd_def.h"
extern USBD_ClassTypeDef USBD_CAN;
uint8_t USBD_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len);
extern USBD_ClassTypeDef USBD_GS_CAN;
uint8_t USBD_GS_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len);

View File

@ -85,7 +85,7 @@ int main(void)
MX_CAN_Init();
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CAN);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_GS_CAN);
USBD_Start(&hUsbDeviceFS);
/* USER CODE BEGIN 2 */

View File

@ -56,14 +56,14 @@
/** @defgroup USBD_DESC_Private_Defines
* @{
*/
#define USBD_VID 1155
#define USBD_LANGID_STRING 1033
#define USBD_VID 0x1d50
#define USBD_PID_FS 0x606f
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "bytewerk"
#define USBD_PID_FS 22336
#define USBD_PRODUCT_STRING_FS "candleLight gs_usb"
#define USBD_SERIALNUMBER_STRING_FS "000000000001"
#define USBD_CONFIGURATION_STRING_FS "gs_usb config"
#define USBD_PRODUCT_STRING_FS "candleLight gs_usb"
#define USBD_CONFIGURATION_STRING_FS "gs_usb config"
#define USBD_INTERFACE_STRING_FS "gs_usb interface"
#define USBD_SERIALNUMBER_STRING_FS "000000000001"
/* USER CODE BEGIN 0 */

View File

@ -3,11 +3,132 @@
#include "usbd_ctlreq.h"
#include "usbd_ioreq.h"
#define u32 uint32_t
#define u8 uint8_t
enum gs_usb_breq {
GS_USB_BREQ_HOST_FORMAT = 0,
GS_USB_BREQ_BITTIMING,
GS_USB_BREQ_MODE,
GS_USB_BREQ_BERR,
GS_USB_BREQ_BT_CONST,
GS_USB_BREQ_DEVICE_CONFIG
};
enum gs_can_mode {
/* reset a channel. turns it off */
GS_CAN_MODE_RESET = 0,
/* starts a channel */
GS_CAN_MODE_START
};
enum gs_can_state {
GS_CAN_STATE_ERROR_ACTIVE = 0,
GS_CAN_STATE_ERROR_WARNING,
GS_CAN_STATE_ERROR_PASSIVE,
GS_CAN_STATE_BUS_OFF,
GS_CAN_STATE_STOPPED,
GS_CAN_STATE_SLEEPING
};
/* data types passed between host and device */
struct gs_host_config {
u32 byte_order;
} __packed;
/* All data exchanged between host and device is exchanged in host byte order,
* thanks to the struct gs_host_config byte_order member, which is sent first
* to indicate the desired byte order.
*/
struct gs_device_config {
u8 reserved1;
u8 reserved2;
u8 reserved3;
u8 icount;
u32 sw_version;
u32 hw_version;
} __packed;
#define GS_CAN_MODE_NORMAL 0
#define GS_CAN_MODE_LISTEN_ONLY (1<<0)
#define GS_CAN_MODE_LOOP_BACK (1<<1)
#define GS_CAN_MODE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_MODE_ONE_SHOT (1<<3)
struct gs_device_mode {
u32 mode;
u32 flags;
} __packed;
struct gs_device_state {
u32 state;
u32 rxerr;
u32 txerr;
} __packed;
struct gs_device_bittiming {
u32 prop_seg;
u32 phase_seg1;
u32 phase_seg2;
u32 sjw;
u32 brp;
} __packed;
#define GS_CAN_FEATURE_LISTEN_ONLY (1<<0)
#define GS_CAN_FEATURE_LOOP_BACK (1<<1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_FEATURE_ONE_SHOT (1<<3)
struct gs_device_bt_const {
u32 feature;
u32 fclk_can;
u32 tseg1_min;
u32 tseg1_max;
u32 tseg2_min;
u32 tseg2_max;
u32 sjw_max;
u32 brp_min;
u32 brp_max;
u32 brp_inc;
} __packed;
#define GS_CAN_FLAG_OVERFLOW 1
struct gs_host_frame {
u32 echo_id;
u32 can_id;
u8 can_dlc;
u8 channel;
u8 flags;
u8 reserved;
u8 data[8];
} __packed;
/* The GS USB devices make use of the same flags and masks as in
* linux/can.h and linux/can/error.h, and no additional mapping is necessary.
*/
/* Only send a max of GS_MAX_TX_URBS frames per channel at a time. */
#define GS_MAX_TX_URBS 10
/* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */
#define GS_MAX_RX_URBS 30
/* Maximum number of interfaces the driver supports per device.
* Current hardware only supports 2 interfaces. The future may vary.
*/
#define GS_MAX_INTF 2
struct gs_tx_context {
struct gs_can *dev;
unsigned int echo_id;
};
#define SLCAN_IN_EP 0x81 /* EP1 for data IN */
#define SLCAN_OUT_EP 0x01 /* EP1 for data OUT */
#define CAN_CMD_EP 0x82 /* EP2 for CDC commands */
#define CAN_DATA_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
#define CAN_CMD_PACKET_SIZE 8 /* Control Endpoint Packet size */
#define CAN_CMD_PACKET_SIZE 64 /* Control Endpoint Packet size */
#define USB_CAN_CONFIG_DESC_SIZ 67
#define CDC_GET_LINE_CODING 0x21
@ -18,8 +139,8 @@ typedef struct {
__IO uint32_t TxState;
__IO uint32_t RxState;
uint8_t CmdOpCode;
uint8_t CmdLength;
uint8_t req_bRequest;
uint8_t req_wLength;
uint8_t slcan_str_index;
uint8_t _dummy;
@ -27,41 +148,45 @@ typedef struct {
uint8_t cmd_buf[CAN_CMD_PACKET_SIZE];
uint8_t rx_buf[CAN_DATA_MAX_PACKET_SIZE];
uint8_t tx_buf[CAN_DATA_MAX_PACKET_SIZE];
} USBD_CAN_HandleTypeDef;
static uint8_t USBD_CAN_ReceivePacket(USBD_HandleTypeDef *pdev);
struct gs_host_config host_config;
struct gs_device_mode device_mode;
static uint8_t USBD_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_CAN_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static uint8_t USBD_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev);
static uint8_t *USBD_CAN_GetCfgDesc(uint16_t *len);
static uint8_t *USBD_CAN_GetDeviceQualifierDescriptor(uint16_t *length);
} USBD_GS_CAN_HandleTypeDef;
static uint8_t USBD_GS_CAN_ReceivePacket(USBD_HandleTypeDef *pdev);
static uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_GS_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_GS_CAN_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static uint8_t USBD_GS_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_GS_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev);
static uint8_t *USBD_GS_CAN_GetCfgDesc(uint16_t *len);
static uint8_t *USBD_GS_CAN_GetDeviceQualifierDescriptor(uint16_t *length);
/* CAN interface class callbacks structure */
USBD_ClassTypeDef USBD_CAN = {
USBD_CAN_Init,
USBD_CAN_DeInit,
USBD_CAN_Setup,
USBD_ClassTypeDef USBD_GS_CAN = {
USBD_GS_CAN_Init,
USBD_GS_CAN_DeInit,
USBD_GS_CAN_Setup,
NULL, /* EP0_TxSent, */
USBD_CAN_EP0_RxReady,
USBD_CAN_DataIn,
USBD_CAN_DataOut,
USBD_GS_CAN_EP0_RxReady,
USBD_GS_CAN_DataIn,
USBD_GS_CAN_DataOut,
NULL,
NULL,
NULL,
USBD_CAN_GetCfgDesc,
USBD_CAN_GetCfgDesc,
USBD_CAN_GetCfgDesc,
USBD_CAN_GetDeviceQualifierDescriptor,
USBD_GS_CAN_GetCfgDesc,
USBD_GS_CAN_GetCfgDesc,
USBD_GS_CAN_GetCfgDesc,
USBD_GS_CAN_GetDeviceQualifierDescriptor,
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_CAN_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
__ALIGN_BEGIN static uint8_t USBD_GS_CAN_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
@ -76,8 +201,8 @@ __ALIGN_BEGIN static uint8_t USBD_CAN_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_
};
/* USB CDC device Configuration Descriptor */
__ALIGN_BEGIN uint8_t USBD_CAN_CfgDesc[USB_CAN_CONFIG_DESC_SIZ] __ALIGN_END =
/* GS_USB device Configuration Descriptor */
__ALIGN_BEGIN uint8_t USBD_GS_CAN_CfgDesc[USB_CAN_CONFIG_DESC_SIZ] __ALIGN_END =
{
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
@ -99,9 +224,9 @@ __ALIGN_BEGIN uint8_t USBD_CAN_CfgDesc[USB_CAN_CONFIG_DESC_SIZ] __ALIGN_END =
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0xFF, /* bInterfaceClass: Vendor Specific*/
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
@ -171,29 +296,7 @@ __ALIGN_BEGIN uint8_t USBD_CAN_CfgDesc[USB_CAN_CONFIG_DESC_SIZ] __ALIGN_END =
0x00 /* bInterval: ignore for Bulk transfer */
};
static int8_t USBD_CAN_ControlReq(uint8_t cmd, uint8_t *pbuf, uint16_t len)
{
(void) len;
switch (cmd) {
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(115200);
pbuf[1] = (uint8_t)(115200 >> 8);
pbuf[2] = (uint8_t)(115200 >> 16);
pbuf[3] = (uint8_t)(115200 >> 24);
pbuf[4] = 0; // stop bits (1)
pbuf[5] = 0; // parity (none)
pbuf[6] = 8; // number of bits (8)
break;
default:
break;
}
return (USBD_OK);
}
static uint8_t USBD_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
static uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
(void) cfgidx;
uint8_t ret = 0;
@ -202,19 +305,19 @@ static uint8_t USBD_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
USBD_LL_OpenEP(pdev, SLCAN_OUT_EP, USBD_EP_TYPE_BULK, CAN_DATA_MAX_PACKET_SIZE);
USBD_LL_OpenEP(pdev, CAN_CMD_EP, USBD_EP_TYPE_INTR, CAN_CMD_PACKET_SIZE);
USBD_CAN_HandleTypeDef *hcan = USBD_malloc(sizeof(USBD_CAN_HandleTypeDef));
USBD_GS_CAN_HandleTypeDef *hcan = USBD_malloc(sizeof(USBD_GS_CAN_HandleTypeDef));
if(hcan == 0) {
ret = 1;
} else {
USBD_memset(hcan, 0, sizeof(USBD_CAN_HandleTypeDef));
USBD_memset(hcan, 0, sizeof(USBD_GS_CAN_HandleTypeDef));
pdev->pClassData = hcan;
USBD_LL_PrepareReceive(pdev, SLCAN_OUT_EP, hcan->rx_buf, CAN_DATA_MAX_PACKET_SIZE);
}
return ret;
}
static uint8_t USBD_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
static uint8_t USBD_GS_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
(void) cfgidx;
uint8_t ret = 0;
@ -232,30 +335,88 @@ static uint8_t USBD_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
return ret;
}
static uint8_t USBD_CAN_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) {
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*) pdev->pClassData;
switch (hcan->req_bRequest) {
case GS_USB_BREQ_HOST_FORMAT:
// host data format received (expect 0x0000beef in byte_order)
memcpy(&hcan->host_config, hcan->cmd_buf, sizeof(hcan->host_config));
break;
case GS_USB_BREQ_MODE:
// set device mode (flags, start/reset...)
memcpy(&hcan->device_mode, hcan->cmd_buf, sizeof(hcan->device_mode));
break;
default:
break;
}
hcan->req_bRequest = 0xFF;
return USBD_OK;
}
static uint8_t USBD_GS_CAN_Vendor_Request(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*) pdev->pClassData;
struct gs_device_config dconf;
memset(&dconf, 0, sizeof(dconf));
dconf.icount = 0;
dconf.hw_version = 1;
dconf.sw_version = 1;
struct gs_device_bt_const btconst;
memset(&btconst, 0, sizeof(btconst));
btconst.fclk_can = 48000000;
btconst.tseg1_min = 1;
btconst.tseg1_max = 16;
btconst.tseg2_min = 1;
btconst.tseg2_max = 8;
btconst.sjw_max = 4;
btconst.brp_min = 1;
btconst.brp_max = 1024;
btconst.brp_inc = 1;
btconst.feature = GS_CAN_FEATURE_LISTEN_ONLY | GS_CAN_FEATURE_LOOP_BACK;
switch (req->bRequest) {
case GS_USB_BREQ_HOST_FORMAT:
case GS_USB_BREQ_MODE:
hcan->req_bRequest = req->bRequest;
hcan->req_wLength = (uint8_t)req->wLength;
USBD_CtlPrepareRx(pdev, hcan->cmd_buf, req->wLength);
break;
case GS_USB_BREQ_DEVICE_CONFIG:
memcpy(hcan->cmd_buf, &dconf, sizeof(dconf));
USBD_CtlSendData(pdev, hcan->cmd_buf, req->wLength);
break;
case GS_USB_BREQ_BT_CONST:
memcpy(hcan->cmd_buf, &btconst, sizeof(btconst));
USBD_CtlSendData(pdev, hcan->cmd_buf, req->wLength);
break;
}
return USBD_OK;
}
static uint8_t USBD_GS_CAN_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*) pdev->pClassData;
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*) pdev->pClassData;
static uint8_t ifalt = 0;
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
case USB_REQ_TYPE_CLASS:
if (req->wLength) {
if (req->bmRequest & 0x80) {
USBD_CAN_ControlReq(req->bRequest, hcan->cmd_buf, req->wLength);
USBD_CtlSendData(pdev, hcan->cmd_buf, req->wLength);
} else {
hcan->CmdOpCode = req->bRequest;
hcan->CmdLength = (uint8_t)req->wLength;
USBD_CtlPrepareRx(pdev, hcan->cmd_buf, req->wLength);
}
} else {
USBD_CAN_ControlReq(req->bRequest, (uint8_t*)req, 0);
}
break;
case USB_REQ_TYPE_VENDOR:
return USBD_GS_CAN_Vendor_Request(pdev, req);
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest) {
@ -275,11 +436,11 @@ static uint8_t USBD_CAN_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *re
return USBD_OK;
}
static uint8_t USBD_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
static uint8_t USBD_GS_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
(void) epnum;
if(pdev->pClassData != NULL) {
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*)pdev->pClassData;
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
hcan->TxState = 0;
return USBD_OK;
} else {
@ -287,11 +448,11 @@ static uint8_t USBD_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
}
}
static uint8_t USBD_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
static uint8_t USBD_GS_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
if (pdev->pClassData != NULL) {
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*)pdev->pClassData;
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
hcan->RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
/* USB data will be immediately processed, this allow next USB traffic being
@ -307,7 +468,7 @@ static uint8_t USBD_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
}
// prepare for next read
USBD_CAN_ReceivePacket(pdev);
USBD_GS_CAN_ReceivePacket(pdev);
return USBD_OK;
} else {
@ -315,38 +476,22 @@ static uint8_t USBD_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
}
}
static uint8_t USBD_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) {
if (pdev->pClassData != NULL) {
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*) pdev->pClassData;
if (hcan->CmdOpCode != 0xFF) {
USBD_CAN_ControlReq(hcan->CmdOpCode, hcan->cmd_buf, (uint16_t)hcan->RxLength);
hcan->CmdOpCode = 0xFF;
}
}
return USBD_OK;
}
static uint8_t *USBD_CAN_GetCfgDesc(uint16_t *len)
static uint8_t *USBD_GS_CAN_GetCfgDesc(uint16_t *len)
{
*len = sizeof(USBD_CAN_CfgDesc);
return USBD_CAN_CfgDesc;
*len = sizeof(USBD_GS_CAN_CfgDesc);
return USBD_GS_CAN_CfgDesc;
}
uint8_t *USBD_CAN_GetDeviceQualifierDescriptor(uint16_t *length)
uint8_t *USBD_GS_CAN_GetDeviceQualifierDescriptor(uint16_t *length)
{
*length = sizeof(USBD_CAN_DeviceQualifierDesc);
return USBD_CAN_DeviceQualifierDesc;
*length = sizeof(USBD_GS_CAN_DeviceQualifierDesc);
return USBD_GS_CAN_DeviceQualifierDesc;
}
static uint8_t USBD_CAN_ReceivePacket(USBD_HandleTypeDef *pdev)
static uint8_t USBD_GS_CAN_ReceivePacket(USBD_HandleTypeDef *pdev)
{
/* Suspend or Resume USB Out process */
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*)pdev->pClassData;
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
if (hcan == 0) {
return USBD_FAIL;
} else {
@ -354,9 +499,9 @@ static uint8_t USBD_CAN_ReceivePacket(USBD_HandleTypeDef *pdev)
}
}
uint8_t USBD_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len)
uint8_t USBD_GS_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len)
{
USBD_CAN_HandleTypeDef *hcan = (USBD_CAN_HandleTypeDef*)pdev->pClassData;
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
if (hcan->TxState == 0) {
hcan->TxState = 1;