[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:
Nikolay Minaylov
2021-10-06 12:24:09 +03:00
committed by GitHub
parent 42e553bad5
commit e0c1928fde
49 changed files with 2387 additions and 2120 deletions

View 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;
}

View 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);

View 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;
}

View 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);
}

View 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;
};

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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();