[FL-1857] New USB stack (#735)
* libusb_stm32 USB stack test * USB: Add dual CDC mode * USB HID demo, added libusb_stm32 as submodule * Target F6/F7: remomve unused ll_usb Co-authored-by: n.minaylov <n.minaylov@flipperdevices.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
555
firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
Normal file
555
firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
Normal file
@@ -0,0 +1,555 @@
|
||||
#include "furi-hal-version.h"
|
||||
#include "furi-hal-usb_i.h"
|
||||
#include "furi-hal-vcp_i.h"
|
||||
#include "furi-hal-usb-cdc_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#define CDC0_RXD_EP 0x01
|
||||
#define CDC0_TXD_EP 0x82
|
||||
#define CDC0_NTF_EP 0x83
|
||||
|
||||
#define CDC1_RXD_EP 0x04
|
||||
#define CDC1_TXD_EP 0x85
|
||||
#define CDC1_NTF_EP 0x86
|
||||
|
||||
#define CDC_NTF_SZ 0x08
|
||||
|
||||
struct CdcIadDescriptor {
|
||||
struct usb_iad_descriptor comm_iad;
|
||||
struct usb_interface_descriptor comm;
|
||||
struct usb_cdc_header_desc cdc_hdr;
|
||||
struct usb_cdc_call_mgmt_desc cdc_mgmt;
|
||||
struct usb_cdc_acm_desc cdc_acm;
|
||||
struct usb_cdc_union_desc cdc_union;
|
||||
struct usb_endpoint_descriptor comm_ep;
|
||||
struct usb_interface_descriptor data;
|
||||
struct usb_endpoint_descriptor data_eprx;
|
||||
struct usb_endpoint_descriptor data_eptx;
|
||||
};
|
||||
|
||||
struct CdcConfigDescriptorSingle {
|
||||
struct usb_config_descriptor config;
|
||||
struct CdcIadDescriptor iad_0;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CdcConfigDescriptorDual {
|
||||
struct usb_config_descriptor config;
|
||||
struct CdcIadDescriptor iad_0;
|
||||
struct CdcIadDescriptor iad_1;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc.");
|
||||
|
||||
/* Device descriptor */
|
||||
static const struct usb_device_descriptor cdc_device_desc = {
|
||||
.bLength = sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_DEVICE,
|
||||
.bcdUSB = VERSION_BCD(2,0,0),
|
||||
.bDeviceClass = USB_CLASS_IAD,
|
||||
.bDeviceSubClass = USB_SUBCLASS_IAD,
|
||||
.bDeviceProtocol = USB_PROTO_IAD,
|
||||
.bMaxPacketSize0 = USB_EP0_SIZE,
|
||||
.idVendor = 0x0483,
|
||||
.idProduct = 0x5740,
|
||||
.bcdDevice = VERSION_BCD(1,0,0),
|
||||
.iManufacturer = UsbDevManuf,
|
||||
.iProduct = UsbDevProduct,
|
||||
.iSerialNumber = UsbDevSerial,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
/* Device configuration descriptor - single mode*/
|
||||
static const struct CdcConfigDescriptorSingle cdc_cfg_desc_single = {
|
||||
.config = {
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_CONFIGURATION,
|
||||
.wTotalLength = sizeof(struct CdcConfigDescriptorSingle),
|
||||
.bNumInterfaces = 2,
|
||||
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = NO_DESCRIPTOR,
|
||||
.bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
|
||||
.bMaxPower = USB_CFG_POWER_MA(100),
|
||||
},
|
||||
.iad_0 = {
|
||||
.comm_iad = {
|
||||
.bLength = sizeof(struct usb_iad_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
||||
.bFirstInterface = 0,
|
||||
.bInterfaceCount = 2,
|
||||
.bFunctionClass = USB_CLASS_CDC,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bFunctionProtocol = USB_PROTO_NONE,
|
||||
.iFunction = NO_DESCRIPTOR,
|
||||
},
|
||||
.comm = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.cdc_hdr = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_header_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_HEADER,
|
||||
.bcdCDC = VERSION_BCD(1,1,0),
|
||||
},
|
||||
.cdc_mgmt = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
|
||||
.bmCapabilities = 0,
|
||||
.bDataInterface = 1,
|
||||
},
|
||||
.cdc_acm = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_acm_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_ACM,
|
||||
.bmCapabilities = 0,
|
||||
},
|
||||
.cdc_union = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_union_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_UNION,
|
||||
.bMasterInterface0 = 0,
|
||||
.bSlaveInterface0 = 1,
|
||||
},
|
||||
.comm_ep = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_NTF_EP,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = CDC_NTF_SZ,
|
||||
.bInterval = 0xFF,
|
||||
},
|
||||
.data = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 1,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_NONE,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.data_eprx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_RXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
.data_eptx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_TXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/* Device configuration descriptor - dual mode*/
|
||||
static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = {
|
||||
.config = {
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_CONFIGURATION,
|
||||
.wTotalLength = sizeof(struct CdcConfigDescriptorDual),
|
||||
.bNumInterfaces = 4,
|
||||
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = NO_DESCRIPTOR,
|
||||
.bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
|
||||
.bMaxPower = USB_CFG_POWER_MA(100),
|
||||
},
|
||||
.iad_0 = {
|
||||
.comm_iad = {
|
||||
.bLength = sizeof(struct usb_iad_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
||||
.bFirstInterface = 0,
|
||||
.bInterfaceCount = 2,
|
||||
.bFunctionClass = USB_CLASS_CDC,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bFunctionProtocol = USB_PROTO_NONE,
|
||||
.iFunction = NO_DESCRIPTOR,
|
||||
},
|
||||
.comm = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.cdc_hdr = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_header_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_HEADER,
|
||||
.bcdCDC = VERSION_BCD(1,1,0),
|
||||
},
|
||||
.cdc_mgmt = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
|
||||
.bmCapabilities = 0,
|
||||
.bDataInterface = 1,
|
||||
},
|
||||
.cdc_acm = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_acm_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_ACM,
|
||||
.bmCapabilities = 0,
|
||||
},
|
||||
.cdc_union = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_union_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_UNION,
|
||||
.bMasterInterface0 = 0,
|
||||
.bSlaveInterface0 = 1,
|
||||
},
|
||||
.comm_ep = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_NTF_EP,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = CDC_NTF_SZ,
|
||||
.bInterval = 0xFF,
|
||||
},
|
||||
.data = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 1,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_NONE,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.data_eprx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_RXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
.data_eptx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC0_TXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
},
|
||||
.iad_1 = {
|
||||
.comm_iad = {
|
||||
.bLength = sizeof(struct usb_iad_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
||||
.bFirstInterface = 2,
|
||||
.bInterfaceCount = 2,
|
||||
.bFunctionClass = USB_CLASS_CDC,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bFunctionProtocol = USB_PROTO_NONE,
|
||||
.iFunction = NO_DESCRIPTOR,
|
||||
},
|
||||
.comm = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 2+0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_CDC,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.cdc_hdr = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_header_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_HEADER,
|
||||
.bcdCDC = VERSION_BCD(1,1,0),
|
||||
},
|
||||
.cdc_mgmt = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
|
||||
.bmCapabilities = 0,
|
||||
.bDataInterface = 2+1,
|
||||
},
|
||||
.cdc_acm = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_acm_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_ACM,
|
||||
.bmCapabilities = 0,
|
||||
},
|
||||
.cdc_union = {
|
||||
.bFunctionLength = sizeof(struct usb_cdc_union_desc),
|
||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_DTYPE_CDC_UNION,
|
||||
.bMasterInterface0 = 2+0,
|
||||
.bSlaveInterface0 = 2+1,
|
||||
},
|
||||
.comm_ep = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC1_NTF_EP,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = CDC_NTF_SZ,
|
||||
.bInterval = 0xFF,
|
||||
},
|
||||
.data = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 2+1,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_NONE,
|
||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.data_eprx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC1_RXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
.data_eptx = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = CDC1_TXD_EP,
|
||||
.bmAttributes = USB_EPTYPE_BULK,
|
||||
.wMaxPacketSize = CDC_DATA_SZ,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct usb_cdc_line_coding cdc_line = {
|
||||
.dwDTERate = 38400,
|
||||
.bCharFormat = USB_CDC_1_STOP_BITS,
|
||||
.bParityType = USB_CDC_NO_PARITY,
|
||||
.bDataBits = 8,
|
||||
};
|
||||
static void cdc_init(usbd_device* dev, struct UsbInterface* intf);
|
||||
static void cdc_deinit(usbd_device *dev);
|
||||
static void cdc_on_wakeup(usbd_device *dev);
|
||||
static void cdc_on_suspend(usbd_device *dev);
|
||||
|
||||
static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg);
|
||||
static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback);
|
||||
static usbd_device* usb_dev;
|
||||
static struct UsbInterface* cdc_if_cur = NULL;
|
||||
|
||||
struct UsbInterface usb_cdc_single = {
|
||||
.init = cdc_init,
|
||||
.deinit = cdc_deinit,
|
||||
.wakeup = cdc_on_wakeup,
|
||||
.suspend = cdc_on_suspend,
|
||||
|
||||
.dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,
|
||||
|
||||
.str_manuf_descr = (void*)&dev_manuf_desc,
|
||||
.str_prod_descr = NULL,
|
||||
.str_serial_descr = NULL,
|
||||
|
||||
.cfg_descr = (void*)&cdc_cfg_desc_single,
|
||||
};
|
||||
|
||||
struct UsbInterface usb_cdc_dual = {
|
||||
.init = cdc_init,
|
||||
.deinit = cdc_deinit,
|
||||
.wakeup = cdc_on_wakeup,
|
||||
.suspend = cdc_on_suspend,
|
||||
|
||||
.dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,
|
||||
|
||||
.str_manuf_descr = (void*)&dev_manuf_desc,
|
||||
.str_prod_descr = NULL,
|
||||
.str_serial_descr = NULL,
|
||||
|
||||
.cfg_descr = (void*)&cdc_cfg_desc_dual,
|
||||
};
|
||||
|
||||
static void cdc_init(usbd_device* dev, struct UsbInterface* intf) {
|
||||
usb_dev = dev;
|
||||
cdc_if_cur = intf;
|
||||
|
||||
char* name = (char*)furi_hal_version_get_device_name_ptr();
|
||||
uint8_t len = (name == NULL) ? (0) : (strlen(name));
|
||||
struct usb_string_descriptor* dev_prod_desc = furi_alloc(len * 2 + 2);
|
||||
dev_prod_desc->bLength = len * 2 + 2;
|
||||
dev_prod_desc->bDescriptorType = USB_DTYPE_STRING;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
dev_prod_desc->wString[i] = name[i];
|
||||
|
||||
name = (char*)furi_hal_version_get_name_ptr();
|
||||
len = (name == NULL) ? (0) : (strlen(name));
|
||||
struct usb_string_descriptor* dev_serial_desc = furi_alloc((len + 5) * 2 + 2);
|
||||
dev_serial_desc->bLength = (len + 5) * 2 + 2;
|
||||
dev_serial_desc->bDescriptorType = USB_DTYPE_STRING;
|
||||
memcpy(dev_serial_desc->wString, "f\0l\0i\0p\0_\0", 5*2);
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
dev_serial_desc->wString[i+5] = name[i];
|
||||
|
||||
cdc_if_cur->str_prod_descr = dev_prod_desc;
|
||||
cdc_if_cur->str_serial_descr = dev_serial_desc;
|
||||
|
||||
usbd_reg_config(dev, cdc_ep_config);
|
||||
usbd_reg_control(dev, cdc_control);
|
||||
|
||||
usbd_connect(dev, true);
|
||||
}
|
||||
|
||||
static void cdc_deinit(usbd_device *dev) {
|
||||
usbd_reg_config(dev, NULL);
|
||||
usbd_reg_control(dev, NULL);
|
||||
|
||||
free(cdc_if_cur->str_prod_descr);
|
||||
free(cdc_if_cur->str_serial_descr);
|
||||
|
||||
cdc_if_cur = NULL;
|
||||
}
|
||||
|
||||
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) {
|
||||
if (if_num == 0)
|
||||
usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len);
|
||||
else
|
||||
usbd_ep_write(usb_dev, CDC1_TXD_EP, buf, len);
|
||||
}
|
||||
|
||||
int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) {
|
||||
if (if_num == 0)
|
||||
return usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len);
|
||||
else
|
||||
return usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len);
|
||||
}
|
||||
|
||||
static void cdc_on_wakeup(usbd_device *dev) {
|
||||
furi_hal_vcp_on_usb_resume();
|
||||
}
|
||||
|
||||
static void cdc_on_suspend(usbd_device *dev) {
|
||||
furi_hal_vcp_on_usb_suspend();
|
||||
}
|
||||
|
||||
static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
if (ep == CDC0_RXD_EP)
|
||||
furi_hal_vcp_on_cdc_rx(0);
|
||||
else
|
||||
furi_hal_vcp_on_cdc_rx(1);
|
||||
}
|
||||
|
||||
static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
if (ep == CDC0_TXD_EP)
|
||||
furi_hal_vcp_on_cdc_tx_complete(0);
|
||||
else
|
||||
furi_hal_vcp_on_cdc_tx_complete(1);
|
||||
}
|
||||
|
||||
static void cdc_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
if (event == usbd_evt_eptx) {
|
||||
cdc_tx_ep_callback(dev, event, ep);
|
||||
} else {
|
||||
cdc_rx_ep_callback(dev, event, ep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure endpoints */
|
||||
static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) {
|
||||
uint8_t if_cnt = ((struct usb_config_descriptor*)(cdc_if_cur->cfg_descr))->bNumInterfaces;
|
||||
switch (cfg) {
|
||||
case 0:
|
||||
/* deconfiguring device */
|
||||
usbd_ep_deconfig(dev, CDC0_NTF_EP);
|
||||
usbd_ep_deconfig(dev, CDC0_TXD_EP);
|
||||
usbd_ep_deconfig(dev, CDC0_RXD_EP);
|
||||
usbd_reg_endpoint(dev, CDC0_RXD_EP, 0);
|
||||
usbd_reg_endpoint(dev, CDC0_TXD_EP, 0);
|
||||
if (if_cnt == 4) {
|
||||
usbd_ep_deconfig(dev, CDC1_NTF_EP);
|
||||
usbd_ep_deconfig(dev, CDC1_TXD_EP);
|
||||
usbd_ep_deconfig(dev, CDC1_RXD_EP);
|
||||
usbd_reg_endpoint(dev, CDC1_RXD_EP, 0);
|
||||
usbd_reg_endpoint(dev, CDC1_TXD_EP, 0);
|
||||
}
|
||||
return usbd_ack;
|
||||
case 1:
|
||||
/* configuring device */
|
||||
if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) {
|
||||
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
|
||||
usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_rx_ep_callback);
|
||||
usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_tx_ep_callback);
|
||||
} else {
|
||||
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
|
||||
usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_txrx_ep_callback);
|
||||
usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_txrx_ep_callback);
|
||||
}
|
||||
usbd_ep_write(dev, CDC0_TXD_EP, 0, 0);
|
||||
|
||||
if (if_cnt == 4) {
|
||||
if ((CDC1_TXD_EP & 0x7F) != (CDC1_RXD_EP & 0x7F)) {
|
||||
usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
|
||||
usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_rx_ep_callback);
|
||||
usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_tx_ep_callback);
|
||||
} else {
|
||||
usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
|
||||
usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
|
||||
usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_txrx_ep_callback);
|
||||
usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_txrx_ep_callback);
|
||||
}
|
||||
usbd_ep_write(dev, CDC1_TXD_EP, 0, 0);
|
||||
}
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Control requests handler */
|
||||
static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) {
|
||||
/* CDC control requests */
|
||||
if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
|
||||
&& req->wIndex == 0 ) {
|
||||
switch (req->bRequest) {
|
||||
case USB_CDC_SET_CONTROL_LINE_STATE:
|
||||
furi_hal_vcp_on_cdc_control_line(req->wValue);
|
||||
return usbd_ack;
|
||||
case USB_CDC_SET_LINE_CODING:
|
||||
memcpy(&cdc_line, req->data, sizeof(cdc_line));
|
||||
return usbd_ack;
|
||||
case USB_CDC_GET_LINE_CODING:
|
||||
dev->status.data_ptr = &cdc_line;
|
||||
dev->status.data_count = sizeof(cdc_line);
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
return usbd_fail;
|
||||
}
|
7
firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
Normal file
7
firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define CDC_DATA_SZ 0x40
|
||||
|
||||
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len);
|
||||
|
||||
int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len);
|
264
firmware/targets/f7/furi-hal/furi-hal-usb-hid.c
Normal file
264
firmware/targets/f7/furi-hal/furi-hal-usb-hid.c
Normal file
@@ -0,0 +1,264 @@
|
||||
#include "furi-hal-version.h"
|
||||
#include "furi-hal-usb_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_hid.h"
|
||||
#include "hid_usage_desktop.h"
|
||||
#include "hid_usage_button.h"
|
||||
|
||||
#define HID_RIN_EP 0x81
|
||||
#define HID_RIN_SZ 0x10
|
||||
|
||||
struct HidIadDescriptor {
|
||||
struct usb_iad_descriptor hid_iad;
|
||||
struct usb_interface_descriptor hid;
|
||||
struct usb_hid_descriptor hid_desc;
|
||||
struct usb_endpoint_descriptor hid_ep;
|
||||
};
|
||||
|
||||
struct HidConfigDescriptor {
|
||||
struct usb_config_descriptor config;
|
||||
struct HidIadDescriptor iad_0;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* HID mouse report desscriptor. 2 axis 5 buttons */
|
||||
static const uint8_t hid_report_desc[] = {
|
||||
HID_USAGE_PAGE(HID_PAGE_DESKTOP),
|
||||
HID_USAGE(HID_DESKTOP_MOUSE),
|
||||
HID_COLLECTION(HID_APPLICATION_COLLECTION),
|
||||
HID_USAGE(HID_DESKTOP_POINTER),
|
||||
HID_COLLECTION(HID_PHYSICAL_COLLECTION),
|
||||
HID_USAGE(HID_DESKTOP_X),
|
||||
HID_USAGE(HID_DESKTOP_Y),
|
||||
HID_LOGICAL_MINIMUM(-127),
|
||||
HID_LOGICAL_MAXIMUM(127),
|
||||
HID_REPORT_SIZE(8),
|
||||
HID_REPORT_COUNT(2),
|
||||
HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE ),
|
||||
HID_USAGE_PAGE(HID_PAGE_BUTTON),
|
||||
HID_USAGE_MINIMUM(1),
|
||||
HID_USAGE_MAXIMUM(5),
|
||||
HID_LOGICAL_MINIMUM(0),
|
||||
HID_LOGICAL_MAXIMUM(1),
|
||||
HID_REPORT_SIZE(1),
|
||||
HID_REPORT_COUNT(5),
|
||||
HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE ),
|
||||
HID_REPORT_SIZE(1),
|
||||
HID_REPORT_COUNT(3),
|
||||
HID_INPUT(HID_IOF_CONSTANT),
|
||||
HID_END_COLLECTION,
|
||||
HID_END_COLLECTION,
|
||||
};
|
||||
|
||||
static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Logitech");
|
||||
static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("USB Receiver");
|
||||
static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("1234567890");
|
||||
|
||||
/* Device descriptor */
|
||||
static const struct usb_device_descriptor hid_device_desc = {
|
||||
.bLength = sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_DEVICE,
|
||||
.bcdUSB = VERSION_BCD(2,0,0),
|
||||
.bDeviceClass = USB_CLASS_IAD,
|
||||
.bDeviceSubClass = USB_SUBCLASS_IAD,
|
||||
.bDeviceProtocol = USB_PROTO_IAD,
|
||||
.bMaxPacketSize0 = USB_EP0_SIZE,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0xc529,
|
||||
.bcdDevice = VERSION_BCD(1,0,0),
|
||||
.iManufacturer = UsbDevManuf,
|
||||
.iProduct = UsbDevProduct,
|
||||
.iSerialNumber = UsbDevSerial,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
/* Device configuration descriptor */
|
||||
static const struct HidConfigDescriptor hid_cfg_desc = {
|
||||
.config = {
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_CONFIGURATION,
|
||||
.wTotalLength = sizeof(struct HidConfigDescriptor),
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = NO_DESCRIPTOR,
|
||||
.bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
|
||||
.bMaxPower = USB_CFG_POWER_MA(100),
|
||||
},
|
||||
.iad_0 = {
|
||||
.hid_iad = {
|
||||
.bLength = sizeof(struct usb_iad_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
||||
.bFirstInterface = 0,
|
||||
.bInterfaceCount = 1,
|
||||
.bFunctionClass = USB_CLASS_PER_INTERFACE,
|
||||
.bFunctionSubClass = USB_SUBCLASS_NONE,
|
||||
.bFunctionProtocol = USB_PROTO_NONE,
|
||||
.iFunction = NO_DESCRIPTOR,
|
||||
},
|
||||
.hid = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
.bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT,
|
||||
.bInterfaceProtocol = USB_HID_PROTO_NONBOOT,
|
||||
.iInterface = NO_DESCRIPTOR,
|
||||
},
|
||||
.hid_desc = {
|
||||
.bLength = sizeof(struct usb_hid_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_HID,
|
||||
.bcdHID = VERSION_BCD(1,0,0),
|
||||
.bCountryCode = USB_HID_COUNTRY_NONE,
|
||||
.bNumDescriptors = 1,
|
||||
.bDescriptorType0 = USB_DTYPE_HID_REPORT,
|
||||
.wDescriptorLength0 = sizeof(hid_report_desc),
|
||||
},
|
||||
.hid_ep = {
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
||||
.bEndpointAddress = HID_RIN_EP,
|
||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
||||
.wMaxPacketSize = HID_RIN_SZ,
|
||||
.bInterval = 50,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct {
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
uint8_t buttons;
|
||||
} __attribute__((packed)) hid_report_data;
|
||||
|
||||
static void hid_init(usbd_device* dev, struct UsbInterface* intf);
|
||||
static void hid_deinit(usbd_device *dev);
|
||||
static void hid_on_wakeup(usbd_device *dev);
|
||||
static void hid_on_suspend(usbd_device *dev);
|
||||
|
||||
static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg);
|
||||
static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback);
|
||||
static usbd_device* usb_dev;
|
||||
|
||||
struct UsbInterface usb_hid = {
|
||||
.init = hid_init,
|
||||
.deinit = hid_deinit,
|
||||
.wakeup = hid_on_wakeup,
|
||||
.suspend = hid_on_suspend,
|
||||
|
||||
.dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
|
||||
|
||||
.str_manuf_descr = (void*)&dev_manuf_desc,
|
||||
.str_prod_descr = (void*)&dev_prod_desc,
|
||||
.str_serial_descr = (void*)&dev_serial_desc,
|
||||
|
||||
.cfg_descr = (void*)&hid_cfg_desc,
|
||||
};
|
||||
|
||||
static void hid_init(usbd_device* dev, struct UsbInterface* intf) {
|
||||
usb_dev = dev;
|
||||
|
||||
usbd_reg_config(dev, hid_ep_config);
|
||||
usbd_reg_control(dev, hid_control);
|
||||
|
||||
usbd_connect(dev, true);
|
||||
}
|
||||
|
||||
static void hid_deinit(usbd_device *dev) {
|
||||
usbd_reg_config(dev, NULL);
|
||||
usbd_reg_control(dev, NULL);
|
||||
}
|
||||
|
||||
static void hid_on_wakeup(usbd_device *dev) {
|
||||
}
|
||||
|
||||
static void hid_on_suspend(usbd_device *dev) {
|
||||
}
|
||||
|
||||
/* HID mouse IN endpoint callback */
|
||||
static void hid_mouse_move(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
static uint8_t t = 0;
|
||||
if (t < 0x10) {
|
||||
hid_report_data.x = 1;
|
||||
hid_report_data.y = 0;
|
||||
} else if (t < 0x20) {
|
||||
hid_report_data.x = 1;
|
||||
hid_report_data.y = 1;
|
||||
} else if (t < 0x30) {
|
||||
hid_report_data.x = 0;
|
||||
hid_report_data.y = 1;
|
||||
} else if (t < 0x40) {
|
||||
hid_report_data.x = -1;
|
||||
hid_report_data.y = 1;
|
||||
} else if (t < 0x50) {
|
||||
hid_report_data.x = -1;
|
||||
hid_report_data.y = 0;
|
||||
} else if (t < 0x60) {
|
||||
hid_report_data.x = -1;
|
||||
hid_report_data.y = -1;
|
||||
} else if (t < 0x70) {
|
||||
hid_report_data.x = 0;
|
||||
hid_report_data.y = -1;
|
||||
} else {
|
||||
hid_report_data.x = 1;
|
||||
hid_report_data.y = -1;
|
||||
}
|
||||
t = (t + 1) & 0x7F;
|
||||
usbd_ep_write(dev, ep, &hid_report_data, sizeof(hid_report_data));
|
||||
}
|
||||
|
||||
/* Configure endpoints */
|
||||
static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg) {
|
||||
switch (cfg) {
|
||||
case 0:
|
||||
/* deconfiguring device */
|
||||
usbd_ep_deconfig(dev, HID_RIN_EP);
|
||||
usbd_reg_endpoint(dev, HID_RIN_EP, 0);
|
||||
return usbd_ack;
|
||||
case 1:
|
||||
/* configuring device */
|
||||
usbd_ep_config(dev, HID_RIN_EP, USB_EPTYPE_INTERRUPT, HID_RIN_SZ);
|
||||
usbd_reg_endpoint(dev, HID_RIN_EP, hid_mouse_move);
|
||||
usbd_ep_write(dev, HID_RIN_EP, 0, 0);
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Control requests handler */
|
||||
static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) {
|
||||
/* HID control requests */
|
||||
if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
|
||||
&& req->wIndex == 0 ) {
|
||||
switch (req->bRequest) {
|
||||
case USB_HID_SETIDLE:
|
||||
return usbd_ack;
|
||||
case USB_HID_GETREPORT:
|
||||
dev->status.data_ptr = &hid_report_data;
|
||||
dev->status.data_count = sizeof(hid_report_data);
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_STANDARD)
|
||||
&& req->wIndex == 0
|
||||
&& req->bRequest == USB_STD_GET_DESCRIPTOR) {
|
||||
switch (req->wValue >> 8) {
|
||||
case USB_DTYPE_HID:
|
||||
dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.iad_0.hid_desc);
|
||||
dev->status.data_count = sizeof(hid_cfg_desc.iad_0.hid_desc);
|
||||
return usbd_ack;
|
||||
case USB_DTYPE_HID_REPORT:
|
||||
dev->status.data_ptr = (uint8_t*)hid_report_desc;
|
||||
dev->status.data_count = sizeof(hid_report_desc);
|
||||
return usbd_ack;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
return usbd_fail;
|
||||
}
|
164
firmware/targets/f7/furi-hal/furi-hal-usb.c
Normal file
164
firmware/targets/f7/furi-hal/furi-hal-usb.c
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "furi-hal-version.h"
|
||||
#include "furi-hal-usb_i.h"
|
||||
#include "furi-hal-usb.h"
|
||||
#include "furi-hal-vcp_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#define USB_RECONNECT_DELAY 500
|
||||
|
||||
extern struct UsbInterface usb_cdc_single;
|
||||
extern struct UsbInterface usb_cdc_dual;
|
||||
extern struct UsbInterface usb_hid;
|
||||
|
||||
static struct UsbInterface* const usb_if_modes[UsbModesNum] = {
|
||||
NULL,
|
||||
&usb_cdc_single,
|
||||
&usb_cdc_dual,
|
||||
&usb_hid,
|
||||
NULL,//&usb_hid_u2f,
|
||||
};
|
||||
|
||||
static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US);
|
||||
|
||||
static uint32_t ubuf[0x20];
|
||||
usbd_device udev;
|
||||
|
||||
static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length);
|
||||
static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep);
|
||||
static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep);
|
||||
|
||||
struct UsbCfg{
|
||||
osTimerId_t reconnect_tmr;
|
||||
UsbMode mode_cur;
|
||||
UsbMode mode_next;
|
||||
bool enabled;
|
||||
} usb_config;
|
||||
|
||||
static void furi_hal_usb_tmr_cb(void* context);
|
||||
|
||||
/* Low-level init */
|
||||
void furi_hal_usb_init(void) {
|
||||
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
LL_PWR_EnableVddUSB();
|
||||
|
||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_11 | LL_GPIO_PIN_12;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf));
|
||||
usbd_enable(&udev, true);
|
||||
|
||||
usbd_reg_descr(&udev, usb_descriptor_get);
|
||||
usbd_reg_event(&udev, usbd_evt_susp, susp_evt);
|
||||
usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt);
|
||||
|
||||
usb_config.enabled = false;
|
||||
usb_config.reconnect_tmr = NULL;
|
||||
HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0);
|
||||
NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
|
||||
FURI_LOG_I("FuriHalUsb", "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_usb_set_config(UsbMode new_mode) {
|
||||
if (new_mode != usb_config.mode_cur) {
|
||||
if (usb_config.enabled) {
|
||||
usb_config.mode_next = new_mode;
|
||||
if (usb_config.reconnect_tmr == NULL)
|
||||
usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL);
|
||||
furi_hal_usb_disable();
|
||||
osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY);
|
||||
}
|
||||
else {
|
||||
if (usb_if_modes[usb_config.mode_cur] != NULL)
|
||||
usb_if_modes[usb_config.mode_cur]->deinit(&udev);
|
||||
if (usb_if_modes[new_mode] != NULL) {
|
||||
usb_if_modes[new_mode]->init(&udev, usb_if_modes[new_mode]);
|
||||
FURI_LOG_I("FuriHalUsb", "USB mode change %u -> %u", usb_config.mode_cur, new_mode);
|
||||
usb_config.enabled = true;
|
||||
usb_config.mode_cur = new_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_usb_disable() {
|
||||
if (usb_config.enabled) {
|
||||
susp_evt(&udev, 0, 0);
|
||||
usbd_connect(&udev, false);
|
||||
usb_config.enabled = false;
|
||||
FURI_LOG_I("FuriHalUsb", "USB Disable");
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_usb_enable() {
|
||||
if ((!usb_config.enabled) && (usb_if_modes[usb_config.mode_cur] != NULL)) {
|
||||
usbd_connect(&udev, true);
|
||||
usb_config.enabled = true;
|
||||
FURI_LOG_I("FuriHalUsb", "USB Enable");
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_usb_tmr_cb(void* context) {
|
||||
furi_hal_usb_set_config(usb_config.mode_next);
|
||||
}
|
||||
|
||||
/* Get device / configuration descriptors */
|
||||
static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length) {
|
||||
const uint8_t dtype = req->wValue >> 8;
|
||||
const uint8_t dnumber = req->wValue & 0xFF;
|
||||
const void* desc;
|
||||
uint16_t len = 0;
|
||||
if (usb_if_modes[usb_config.mode_cur] == NULL)
|
||||
return usbd_fail;
|
||||
|
||||
switch (dtype) {
|
||||
case USB_DTYPE_DEVICE:
|
||||
desc = usb_if_modes[usb_config.mode_cur]->dev_descr;
|
||||
break;
|
||||
case USB_DTYPE_CONFIGURATION:
|
||||
desc = usb_if_modes[usb_config.mode_cur]->cfg_descr;
|
||||
len = ((struct usb_string_descriptor*)(usb_if_modes[usb_config.mode_cur]->cfg_descr))->wString[0];
|
||||
break;
|
||||
case USB_DTYPE_STRING:
|
||||
if (dnumber == UsbDevLang) {
|
||||
desc = &dev_lang_desc;
|
||||
} else if (dnumber == UsbDevManuf) {
|
||||
desc = usb_if_modes[usb_config.mode_cur]->str_manuf_descr;
|
||||
} else if (dnumber == UsbDevProduct) {
|
||||
desc = usb_if_modes[usb_config.mode_cur]->str_prod_descr;
|
||||
} else if (dnumber == UsbDevSerial) {
|
||||
desc = usb_if_modes[usb_config.mode_cur]->str_serial_descr;
|
||||
} else
|
||||
return usbd_fail;
|
||||
break;
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
if (desc == NULL)
|
||||
return usbd_fail;
|
||||
|
||||
if (len == 0) {
|
||||
len = ((struct usb_header_descriptor*)desc)->bLength;
|
||||
}
|
||||
*address = (void*)desc;
|
||||
*length = len;
|
||||
return usbd_ack;
|
||||
}
|
||||
|
||||
static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
if (usb_if_modes[usb_config.mode_cur] != NULL)
|
||||
usb_if_modes[usb_config.mode_cur]->suspend(&udev);
|
||||
}
|
||||
|
||||
static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
if (usb_if_modes[usb_config.mode_cur] != NULL)
|
||||
usb_if_modes[usb_config.mode_cur]->wakeup(&udev);
|
||||
}
|
28
firmware/targets/f7/furi-hal/furi-hal-usb_i.h
Normal file
28
firmware/targets/f7/furi-hal/furi-hal-usb_i.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#define USB_EP0_SIZE 8
|
||||
|
||||
/* String descriptors */
|
||||
enum UsbDevDescStr{
|
||||
UsbDevLang = 0,
|
||||
UsbDevManuf = 1,
|
||||
UsbDevProduct = 2,
|
||||
UsbDevSerial = 3,
|
||||
};
|
||||
|
||||
struct UsbInterface {
|
||||
void (*init)(usbd_device *dev, struct UsbInterface* intf);
|
||||
void (*deinit)(usbd_device *dev);
|
||||
void (*wakeup)(usbd_device *dev);
|
||||
void (*suspend)(usbd_device *dev);
|
||||
|
||||
struct usb_device_descriptor* dev_descr;
|
||||
|
||||
void* str_manuf_descr;
|
||||
void* str_prod_descr;
|
||||
void* str_serial_descr;
|
||||
|
||||
void* cfg_descr;
|
||||
};
|
@@ -1,12 +1,12 @@
|
||||
#include <furi-hal-vcp_i.h>
|
||||
#include <furi-hal-usb-cdc_i.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <usbd_cdc_if.h>
|
||||
#include <stream_buffer.h>
|
||||
|
||||
#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 5)
|
||||
|
||||
extern USBD_HandleTypeDef hUsbDeviceFS;
|
||||
#define APP_RX_DATA_SIZE CDC_DATA_SZ
|
||||
#define APP_TX_DATA_SIZE CDC_DATA_SZ
|
||||
#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16)
|
||||
|
||||
typedef struct {
|
||||
volatile bool connected;
|
||||
@@ -22,8 +22,11 @@ static FuriHalVcp* furi_hal_vcp = NULL;
|
||||
static const uint8_t ascii_soh = 0x01;
|
||||
static const uint8_t ascii_eot = 0x04;
|
||||
|
||||
static uint8_t* vcp_rx_buf;
|
||||
|
||||
void furi_hal_vcp_init() {
|
||||
furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp));
|
||||
vcp_rx_buf = furi_alloc(APP_RX_DATA_SIZE);
|
||||
furi_hal_vcp->connected = false;
|
||||
|
||||
furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1);
|
||||
@@ -40,10 +43,8 @@ size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) {
|
||||
size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY);
|
||||
|
||||
if(furi_hal_vcp->rx_stream_full
|
||||
&&xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) {
|
||||
&& xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) {
|
||||
furi_hal_vcp->rx_stream_full = false;
|
||||
// data accepted, start waiting for next packet
|
||||
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
|
||||
}
|
||||
|
||||
return received;
|
||||
@@ -67,13 +68,9 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) {
|
||||
batch_size = APP_TX_DATA_SIZE;
|
||||
}
|
||||
|
||||
if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) {
|
||||
size -= batch_size;
|
||||
buffer += batch_size;
|
||||
} else {
|
||||
FURI_LOG_E("FuriHalVcp", "CDC_Transmit_FS failed");
|
||||
osDelay(50);
|
||||
}
|
||||
furi_hal_cdc_send(0, (uint8_t*)buffer, batch_size);
|
||||
size -= batch_size;
|
||||
buffer += batch_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +86,8 @@ void furi_hal_vcp_on_usb_suspend() {
|
||||
}
|
||||
|
||||
void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
|
||||
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// bit 0: DTR state, bit 1: RTS state
|
||||
// bool dtr = state & 0b01;
|
||||
bool dtr = state & 0b1;
|
||||
@@ -96,33 +95,45 @@ void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
|
||||
if (dtr) {
|
||||
if (!furi_hal_vcp->connected) {
|
||||
furi_hal_vcp->connected = true;
|
||||
furi_hal_vcp_on_cdc_rx(&ascii_soh, 1); // SOH
|
||||
xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_soh, 1, &xHigherPriorityTaskWoken); // SOH
|
||||
|
||||
}
|
||||
} else {
|
||||
if (furi_hal_vcp->connected) {
|
||||
furi_hal_vcp_on_cdc_rx(&ascii_eot, 1); // EOT
|
||||
xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_eot, 1, &xHigherPriorityTaskWoken); // EOT
|
||||
furi_hal_vcp->connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
|
||||
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size) {
|
||||
void furi_hal_vcp_on_cdc_rx(uint8_t if_num) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken);
|
||||
furi_check(ret == size);
|
||||
|
||||
if (xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) {
|
||||
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
|
||||
} else {
|
||||
furi_hal_vcp->rx_stream_full = true;
|
||||
|
||||
if (if_num == 0) {
|
||||
uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream);
|
||||
if (max_len > 0) {
|
||||
if (max_len > APP_RX_DATA_SIZE)
|
||||
max_len = APP_RX_DATA_SIZE;
|
||||
int32_t size = furi_hal_cdc_receive(0, vcp_rx_buf, max_len);
|
||||
|
||||
if (size > 0) {
|
||||
size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken);
|
||||
furi_check(ret == size);
|
||||
}
|
||||
} else {
|
||||
furi_hal_vcp->rx_stream_full = true;
|
||||
};
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
void furi_hal_vcp_on_cdc_tx_complete(size_t size) {
|
||||
osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
|
||||
void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num) {
|
||||
if (if_num == 0)
|
||||
osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,6 @@ void furi_hal_vcp_on_usb_suspend();
|
||||
|
||||
void furi_hal_vcp_on_cdc_control_line(uint8_t state);
|
||||
|
||||
void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size);
|
||||
void furi_hal_vcp_on_cdc_rx(uint8_t if_num);
|
||||
|
||||
void furi_hal_vcp_on_cdc_tx_complete(size_t size);
|
||||
void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num);
|
||||
|
@@ -8,10 +8,6 @@
|
||||
#include "ble.h"
|
||||
|
||||
#define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE
|
||||
#define FURI_HAL_VERSION_NAME_LENGTH 8
|
||||
#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1)
|
||||
/** BLE symbol + "Flipper " + name */
|
||||
#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + 8 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH)
|
||||
#define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE
|
||||
|
||||
/** OTP Versions enum */
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <comp.h>
|
||||
#include <rtc.h>
|
||||
#include <tim.h>
|
||||
#include <usb_device.h>
|
||||
#include <gpio.h>
|
||||
|
||||
void furi_hal_init() {
|
||||
@@ -35,7 +34,8 @@ void furi_hal_init() {
|
||||
|
||||
// VCP + USB
|
||||
furi_hal_vcp_init();
|
||||
MX_USB_Device_Init();
|
||||
furi_hal_usb_init();
|
||||
furi_hal_usb_set_config(UsbModeVcpSingle);
|
||||
FURI_LOG_I("HAL", "USB OK");
|
||||
|
||||
furi_hal_i2c_init();
|
||||
|
Reference in New Issue
Block a user