From 5d44a5e026cc6ca2b0a8b0934be0a1750ac64faa Mon Sep 17 00:00:00 2001 From: Hubert Denkmair Date: Fri, 8 Apr 2016 10:52:40 +0200 Subject: [PATCH] respond to config requests --- include/usbd_gs_can.h | 5 +- src/main.c | 2 +- src/usbd_desc.c | 12 +- src/usbd_gs_can.c | 355 +++++++++++++++++++++++++++++------------- 4 files changed, 260 insertions(+), 114 deletions(-) diff --git a/include/usbd_gs_can.h b/include/usbd_gs_can.h index f23c72c..963eb57 100644 --- a/include/usbd_gs_can.h +++ b/include/usbd_gs_can.h @@ -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); diff --git a/src/main.c b/src/main.c index 76f3634..6c45f2a 100644 --- a/src/main.c +++ b/src/main.c @@ -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 */ diff --git a/src/usbd_desc.c b/src/usbd_desc.c index d3bdd3b..e8574e8 100644 --- a/src/usbd_desc.c +++ b/src/usbd_desc.c @@ -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 */ diff --git a/src/usbd_gs_can.c b/src/usbd_gs_can.c index 14a7097..6528e62 100644 --- a/src/usbd_gs_can.c +++ b/src/usbd_gs_can.c @@ -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;