Kaynağa Gözat

[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>
Nikolay Minaylov 4 yıl önce
ebeveyn
işleme
e0c1928fde
49 değiştirilmiş dosya ile 2387 ekleme ve 2120 silme
  1. 3 0
      .gitmodules
  2. 5 0
      applications/applications.c
  3. 9 0
      applications/applications.mk
  4. 102 0
      applications/debug_tools/usb_test.c
  5. 52 0
      firmware/targets/f6/Inc/stm32.h
  6. 3 2
      firmware/targets/f6/Src/stm32wbxx_it.c
  7. 555 0
      firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
  8. 7 0
      firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
  9. 264 0
      firmware/targets/f6/furi-hal/furi-hal-usb-hid.c
  10. 164 0
      firmware/targets/f6/furi-hal/furi-hal-usb.c
  11. 28 0
      firmware/targets/f6/furi-hal/furi-hal-usb_i.h
  12. 37 26
      firmware/targets/f6/furi-hal/furi-hal-vcp.c
  13. 2 2
      firmware/targets/f6/furi-hal/furi-hal-vcp_i.h
  14. 0 4
      firmware/targets/f6/furi-hal/furi-hal-version.c
  15. 2 2
      firmware/targets/f6/furi-hal/furi-hal.c
  16. 4 11
      firmware/targets/f6/target.mk
  17. 0 34
      firmware/targets/f6/usb-glue/usb_device.c
  18. 0 11
      firmware/targets/f6/usb-glue/usb_device.h
  19. 0 142
      firmware/targets/f6/usb-glue/usbd_cdc_if.c
  20. 0 22
      firmware/targets/f6/usb-glue/usbd_cdc_if.h
  21. 0 506
      firmware/targets/f6/usb-glue/usbd_conf.c
  22. 0 73
      firmware/targets/f6/usb-glue/usbd_conf.h
  23. 0 206
      firmware/targets/f6/usb-glue/usbd_desc.c
  24. 0 19
      firmware/targets/f6/usb-glue/usbd_desc.h
  25. 52 0
      firmware/targets/f7/Inc/stm32.h
  26. 3 2
      firmware/targets/f7/Src/stm32wbxx_it.c
  27. 555 0
      firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
  28. 7 0
      firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
  29. 264 0
      firmware/targets/f7/furi-hal/furi-hal-usb-hid.c
  30. 164 0
      firmware/targets/f7/furi-hal/furi-hal-usb.c
  31. 28 0
      firmware/targets/f7/furi-hal/furi-hal-usb_i.h
  32. 37 26
      firmware/targets/f7/furi-hal/furi-hal-vcp.c
  33. 2 2
      firmware/targets/f7/furi-hal/furi-hal-vcp_i.h
  34. 0 4
      firmware/targets/f7/furi-hal/furi-hal-version.c
  35. 2 2
      firmware/targets/f7/furi-hal/furi-hal.c
  36. 4 11
      firmware/targets/f7/target.mk
  37. 0 34
      firmware/targets/f7/usb-glue/usb_device.c
  38. 0 11
      firmware/targets/f7/usb-glue/usb_device.h
  39. 0 142
      firmware/targets/f7/usb-glue/usbd_cdc_if.c
  40. 0 22
      firmware/targets/f7/usb-glue/usbd_cdc_if.h
  41. 0 506
      firmware/targets/f7/usb-glue/usbd_conf.c
  42. 0 73
      firmware/targets/f7/usb-glue/usbd_conf.h
  43. 0 206
      firmware/targets/f7/usb-glue/usbd_desc.c
  44. 0 19
      firmware/targets/f7/usb-glue/usbd_desc.h
  45. 21 0
      firmware/targets/furi-hal-include/furi-hal-usb.h
  46. 5 0
      firmware/targets/furi-hal-include/furi-hal-version.h
  47. 1 0
      firmware/targets/furi-hal-include/furi-hal.h
  48. 4 0
      lib/lib.mk
  49. 1 0
      lib/libusb_stm32

+ 3 - 0
.gitmodules

@@ -7,3 +7,6 @@
 [submodule "lib/littlefs"]
 	path = lib/littlefs
 	url = https://github.com/littlefs-project/littlefs.git
+[submodule "lib/libusb_stm32"]
+	path = lib/libusb_stm32
+	url = https://github.com/flipperdevices/libusb_stm32.git

+ 5 - 0
applications/applications.c

@@ -33,6 +33,7 @@ extern int32_t storage_test_app(void* p);
 extern int32_t subghz_app(void* p);
 extern int32_t vibro_test_app(void* p);
 extern int32_t bt_debug_app(void* p);
+extern int32_t usb_test_app(void* p);
 
 // Plugins
 extern int32_t music_player_app(void* p);
@@ -210,6 +211,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
     {.app = accessor_app, .name = "Accessor", .stack_size = 4096, .icon = &A_Plugins_14},
 #endif
 
+#ifdef APP_USB_TEST
+    {.app = usb_test_app, .name = "USB Test", .stack_size = 1024, .icon = &A_Plugins_14},
+#endif
+
 #ifdef APP_UNIT_TESTS
     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = &A_Plugins_14},
 #endif

+ 9 - 0
applications/applications.mk

@@ -43,6 +43,7 @@ APP_KEYPAD_TEST = 1
 APP_SD_TEST	= 1
 APP_UNIT_TESTS = 0
 APP_VIBRO_DEMO = 1
+APP_USB_TEST = 1
 endif
 
 
@@ -121,6 +122,14 @@ SRV_GUI		= 1
 endif
 
 
+APP_USB_TEST ?= 0
+ifeq ($(APP_USB_TEST), 1)
+CFLAGS		+= -DAPP_USB_TEST
+SRV_INPUT = 1
+SRV_GUI = 1
+endif 
+
+
 APP_KEYPAD_TEST ?= 0
 ifeq ($(APP_KEYPAD_TEST), 1)
 CFLAGS		+= -DAPP_KEYPAD_TEST

+ 102 - 0
applications/debug_tools/usb_test.c

@@ -0,0 +1,102 @@
+#include <furi.h>
+#include <furi-hal.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+#include <gui/modules/submenu.h>
+#include <gui/gui.h>
+
+typedef struct {
+    Gui* gui;
+    ViewDispatcher* view_dispatcher;
+    Submenu* submenu;
+} UsbTestApp;
+
+typedef enum {
+    UsbTestSubmenuIndexEnable,
+    UsbTestSubmenuIndexDisable,
+    UsbTestSubmenuIndexVcpSingle,
+    UsbTestSubmenuIndexVcpDual,
+    UsbTestSubmenuIndexHid,
+    UsbTestSubmenuIndexHidU2F,
+} SubmenuIndex;
+
+void usb_test_submenu_callback(void* context, uint32_t index) {
+    furi_assert(context);
+    //UsbTestApp* app = context;
+    if(index == UsbTestSubmenuIndexEnable) {
+        furi_hal_usb_enable();
+    } else if(index == UsbTestSubmenuIndexDisable) {
+        furi_hal_usb_disable();
+    } else if(index == UsbTestSubmenuIndexVcpSingle) {
+        furi_hal_usb_set_config(UsbModeVcpSingle);
+    } else if(index == UsbTestSubmenuIndexVcpDual) {
+        furi_hal_usb_set_config(UsbModeVcpDual);
+    } else if(index == UsbTestSubmenuIndexHid) {
+        furi_hal_usb_set_config(UsbModeHid);
+    } else if(index == UsbTestSubmenuIndexHidU2F) {
+        //furi_hal_usb_set_config(UsbModeU2F);
+    }
+}
+
+uint32_t usb_test_exit(void* context) {
+    return VIEW_NONE;
+}
+
+UsbTestApp* usb_test_app_alloc() {
+    UsbTestApp* app = furi_alloc(sizeof(UsbTestApp));
+
+    // Gui
+    app->gui = furi_record_open("gui");
+
+    // View dispatcher
+    app->view_dispatcher = view_dispatcher_alloc();
+    view_dispatcher_enable_queue(app->view_dispatcher);
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    // Views
+    app->submenu = submenu_alloc();
+    submenu_add_item(
+        app->submenu, "Enable", UsbTestSubmenuIndexEnable, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu, "Disable", UsbTestSubmenuIndexDisable, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu, "Single VCP", UsbTestSubmenuIndexVcpSingle, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu, "Dual VCP", UsbTestSubmenuIndexVcpDual, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu, "TODO: HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app);
+    view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit);
+    view_dispatcher_add_view(app->view_dispatcher, 0, submenu_get_view(app->submenu));
+
+    // Switch to menu
+    view_dispatcher_switch_to_view(app->view_dispatcher, 0);
+
+    return app;
+}
+
+void usb_test_app_free(UsbTestApp* app) {
+    furi_assert(app);
+
+    // Free views
+    view_dispatcher_remove_view(app->view_dispatcher, 0);
+    submenu_free(app->submenu);
+    view_dispatcher_free(app->view_dispatcher);
+
+    // Close gui record
+    furi_record_close("gui");
+    app->gui = NULL;
+
+    // Free rest
+    free(app);
+}
+
+int32_t usb_test_app(void* p) {
+    UsbTestApp* app = usb_test_app_alloc();
+
+    view_dispatcher_run(app->view_dispatcher);
+
+    usb_test_app_free(app);
+    return 0;
+}

+ 52 - 0
firmware/targets/f6/Inc/stm32.h

@@ -0,0 +1,52 @@
+#ifndef _STM32_H_
+#define _STM32_H_
+
+/* modify bitfield */
+#define _BMD(reg, msk, val)     (reg) = (((reg) & ~(msk)) | (val))
+/* set bitfield */
+#define _BST(reg, bits)         (reg) = ((reg) | (bits))
+/* clear bitfield */
+#define _BCL(reg, bits)         (reg) = ((reg) & ~(bits))
+/* wait until bitfield set */
+#define _WBS(reg, bits)         while(((reg) & (bits)) == 0)
+/* wait until bitfield clear */
+#define _WBC(reg, bits)         while(((reg) & (bits)) != 0)
+/* wait for bitfield value */
+#define _WVL(reg, msk, val)     while(((reg) & (msk)) != (val))
+/* bit value */
+#define _BV(bit)                (0x01 << (bit))
+
+#if defined(STM32F0)
+    #include "STM32F0xx/Include/stm32f0xx.h"
+#elif defined(STM32F1)
+    #include "STM32F1xx/Include/stm32f1xx.h"
+#elif defined(STM32F2)
+    #include "STM32F2xx/Include/stm32f2xx.h"
+#elif defined(STM32F3)
+    #include "STM32F3xx/Include/stm32f3xx.h"
+#elif defined(STM32F4)
+    #include "STM32F4xx/Include/stm32f4xx.h"
+#elif defined(STM32F7)
+    #include "STM32F7xx/Include/stm32f7xx.h"
+#elif defined(STM32H7)
+    #include "STM32H7xx/Include/stm32h7xx.h"
+#elif defined(STM32L0)
+    #include "STM32L0xx/Include/stm32l0xx.h"
+#elif defined(STM32L1)
+    #include "STM32L1xx/Include/stm32l1xx.h"
+#elif defined(STM32L4)
+    #include "STM32L4xx/Include/stm32l4xx.h"
+#elif defined(STM32L5)
+    #include "STM32L5xx/Include/stm32l5xx.h"
+#elif defined(STM32G0)
+    #include "STM32G0xx/Include/stm32g0xx.h"
+#elif defined(STM32G4)
+    #include "STM32G4xx/Include/stm32g4xx.h"
+#elif defined(STM32WB)
+    #include "STM32WBxx/Include/stm32wbxx.h"
+#else
+    #error "STM32 family not defined"
+#endif
+
+
+#endif // _STM32_H_

+ 3 - 2
firmware/targets/f6/Src/stm32wbxx_it.c

@@ -2,8 +2,9 @@
 #include "stm32wbxx_it.h"
 #include "FreeRTOS.h"
 #include "task.h"
+#include "usbd_core.h"
 
-extern PCD_HandleTypeDef hpcd_USB_FS;
+extern usbd_device udev;
 extern COMP_HandleTypeDef hcomp1;
 extern RTC_HandleTypeDef hrtc;
 extern TIM_HandleTypeDef htim1;
@@ -20,7 +21,7 @@ void SysTick_Handler(void) {
 }
 
 void USB_LP_IRQHandler(void) {
-    HAL_PCD_IRQHandler(&hpcd_USB_FS);
+    usbd_poll(&udev);
 }
 
 void COMP_IRQHandler(void) {

+ 555 - 0
firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c

@@ -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 - 0
firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h

@@ -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 - 0
firmware/targets/f6/furi-hal/furi-hal-usb-hid.c

@@ -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 - 0
firmware/targets/f6/furi-hal/furi-hal-usb.c

@@ -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 - 0
firmware/targets/f6/furi-hal/furi-hal-usb_i.h

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

+ 37 - 26
firmware/targets/f6/furi-hal/furi-hal-vcp.c

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

+ 2 - 2
firmware/targets/f6/furi-hal/furi-hal-vcp_i.h

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

+ 0 - 4
firmware/targets/f6/furi-hal/furi-hal-version.c

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

+ 2 - 2
firmware/targets/f6/furi-hal/furi-hal.c

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

+ 4 - 11
firmware/targets/f6/target.mk

@@ -38,6 +38,7 @@ CFLAGS += \
 CFLAGS += \
 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
+	-I$(CUBE_DIR)/Drivers/CMSIS/Device/ST \
 	-I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include \
 	-I$(CUBE_DIR)/Drivers/CMSIS/Include
 C_SOURCES += \
@@ -69,7 +70,6 @@ C_SOURCES += \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
-	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c
 
 # FreeRTOS
@@ -116,17 +116,10 @@ C_SOURCES += \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c
 
-# USB glue 
+# USB stack
 CFLAGS += \
-	-I$(TARGET_DIR)/usb-glue \
-	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
-	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
-C_SOURCES += \
-	$(wildcard $(TARGET_DIR)/usb-glue/*.c) \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
+	-DSTM32WB \
+	-DUSB_PMASIZE=0x400
 
 # Furi HAL
 FURI_HAL_OS_DEBUG ?= 0

+ 0 - 34
firmware/targets/f6/usb-glue/usb_device.c

@@ -1,34 +0,0 @@
-#include "usb_device.h"
-
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#include "usbd_def.h"
-#include "usbd_core.h"
-#include "usbd_desc.h"
-#include "usbd_cdc.h"
-#include "usbd_cdc_if.h"
-
-extern void Error_Handler(void);
-
-/* USB Device Core handle declaration. */
-USBD_HandleTypeDef hUsbDeviceFS;
-
-extern USBD_DescriptorsTypeDef CDC_Desc;
-
-/** Init USB device Library, add supported class and start the library */
-void MX_USB_Device_Init(void) {
-    /* Init Device Library, add supported class and start the library. */
-    if (USBD_Init(&hUsbDeviceFS, &CDC_Desc, DEVICE_FS) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_Start(&hUsbDeviceFS) != USBD_OK) {
-        Error_Handler();
-    }
-}

+ 0 - 11
firmware/targets/f6/usb-glue/usb_device.h

@@ -1,11 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-void MX_USB_Device_Init();
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 142
firmware/targets/f6/usb-glue/usbd_cdc_if.c

@@ -1,142 +0,0 @@
-#include "usbd_cdc_if.h"
-#include <furi-hal-vcp_i.h>
-
-extern USBD_HandleTypeDef hUsbDeviceFS;
-
-static int8_t CDC_Init_FS(void);
-static int8_t CDC_DeInit_FS(void);
-static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
-static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
-static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);
-
-USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
-{
-    CDC_Init_FS,
-    CDC_DeInit_FS,
-    CDC_Control_FS,
-    CDC_Receive_FS,
-    CDC_TransmitCplt_FS
-};
-
-uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
-uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
-
-/** Initializes the CDC media low layer over the FS USB IP
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Init_FS(void) {
-    /* Set Application Buffers */
-    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
-    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
-    return (USBD_OK);
-}
-
-/**
- * @brief  DeInitializes the CDC media low layer
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_DeInit_FS(void) {
-    return (USBD_OK);
-}
-
-/** Manage the CDC class requests
- * @param  cmd: Command code
- * @param  pbuf: Buffer containing command data (request parameters)
- * @param  length: Number of data to be sent (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) {
-    if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) {
-    } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) {
-    } else if (cmd == CDC_SET_COMM_FEATURE) {
-    } else if (cmd == CDC_GET_COMM_FEATURE) {
-    } else if (cmd == CDC_CLEAR_COMM_FEATURE) {
-    } else if (cmd == CDC_SET_LINE_CODING) {
-        /*******************************************************************************/
-        /* Line Coding Structure                                                       */
-        /*-----------------------------------------------------------------------------*/
-        /* Offset | Field       | Size | Value  | Description                          */
-        /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
-        /* 4      | bCharFormat |   1  | Number | Stop bits                            */
-        /*                                        0 - 1 Stop bit                       */
-        /*                                        1 - 1.5 Stop bits                    */
-        /*                                        2 - 2 Stop bits                      */
-        /* 5      | bParityType |  1   | Number | Parity                               */
-        /*                                        0 - None                             */
-        /*                                        1 - Odd                              */
-        /*                                        2 - Even                             */
-        /*                                        3 - Mark                             */
-        /*                                        4 - Space                            */
-        /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
-        /*******************************************************************************/
-    } else if (cmd == CDC_GET_LINE_CODING) {
-    } else if (cmd == CDC_SET_CONTROL_LINE_STATE) {
-        furi_hal_vcp_on_cdc_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue);
-    } else if (cmd == CDC_SEND_BREAK) {
-    } else {
-    }
-
-    return (USBD_OK);
-}
-
-/** Data received over USB OUT endpoint are sent over CDC interface through this function.
- *
- * @note
- * This function will issue a NAK packet on any OUT packet received on
- * USB endpoint until exiting this function. If you exit this function
- * before transfer is complete on CDC interface (ie. using DMA controller)
- * it will result in receiving more data while previous ones are still
- * not sent.
- *
- * @param  Buf: Buffer of data to be received
- * @param  Len: Number of data received (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) {
-    if (*Len) {
-        furi_hal_vcp_on_cdc_rx(Buf, *Len);
-    } else {
-        USBD_CDC_ReceivePacket(&hUsbDeviceFS);
-    }
-    
-    return (USBD_OK);
-}
-
-/** CDC_Transmit_FS Data to send over USB IN endpoint are sent over CDC interface
- * through this function.
- * @param  Buf: Buffer of data to be sent
- * @param  Len: Number of data to be sent (in bytes)
- * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
- */
-uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
-{
-    uint8_t result = USBD_OK;
-
-    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
-    if (hcdc->TxState != 0){
-        return USBD_BUSY;
-    }
-    memcpy(UserTxBufferFS, Buf, Len);
-    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
-    result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
-
-    return result;
-}
-
-/** CDC_TransmitCplt_FS Data transmited callback
- *
- * @note
- * This function is IN transfer complete callback used to inform user that
- * the submitted Data is successfully sent over USB.
- *
- * @param  Buf: Buffer of data to be received
- * @param  Len: Number of data received (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) {
-    uint8_t result = USBD_OK;
-
-    furi_hal_vcp_on_cdc_tx_complete(*Len);
-
-    return result;
-}

+ 0 - 22
firmware/targets/f6/usb-glue/usbd_cdc_if.h

@@ -1,22 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_cdc.h"
-
-/* Define size for the receive and transmit buffer over CDC */
-/* It's up to user to redefine and/or remove those define */
-#define APP_RX_DATA_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
-#define APP_TX_DATA_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
-
-/** CDC Interface callback. */
-extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
-
-uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 506
firmware/targets/f6/usb-glue/usbd_conf.c

@@ -1,506 +0,0 @@
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#include <furi-hal-vcp_i.h>
-
-#include "usbd_def.h"
-#include "usbd_core.h"
-#include "usbd_cdc.h"
-
-PCD_HandleTypeDef hpcd_USB_FS;
-void Error_Handler(void);
-
-static USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status);
-
-static void SystemClockConfig_Resume(void);
-
-void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) {
-    GPIO_InitTypeDef GPIO_InitStruct = {0};
-    if(pcdHandle->Instance==USB) {
-        __HAL_RCC_GPIOA_CLK_ENABLE();
-        /**USB GPIO Configuration
-        PA11     ------> USB_DM
-        PA12     ------> USB_DP 
-        */
-        GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
-        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-        GPIO_InitStruct.Pull = GPIO_NOPULL;
-        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
-        GPIO_InitStruct.Alternate = GPIO_AF10_USB;
-        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
-        /* Peripheral clock enable */
-        __HAL_RCC_USB_CLK_ENABLE();
-
-        /* Peripheral interrupt init */
-        HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0);
-        HAL_NVIC_EnableIRQ(USB_LP_IRQn);
-    }
-}
-
-void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) {
-    if(pcdHandle->Instance==USB) {
-        /* Peripheral clock disable */
-        __HAL_RCC_USB_CLK_DISABLE();
-
-        /**USB GPIO Configuration
-        PA11     ------> USB_DM
-        PA12     ------> USB_DP
-        */
-        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
-
-        /* Peripheral interrupt Deinit*/
-        HAL_NVIC_DisableIRQ(USB_LP_IRQn);
-    }
-}
-
-/** Setup stage callback
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
-}
-
-/** Data Out stage callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
-}
-
-/** Data In stage callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
-}
-
-/** SOF callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Reset callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
-
-    if ( hpcd->Init.speed != PCD_SPEED_FULL) {
-        Error_Handler();
-    }
-
-    /* Set Speed. */
-    USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed);
-
-    /* Reset Device. */
-    USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Suspend callback.
- * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
-
-    furi_hal_vcp_on_usb_suspend();
-    
-    if (hpcd->Init.low_power_enable) {
-        /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
-        SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-    }
-}
-
-/** Resume callback.
- * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) {
-    if (hpcd->Init.low_power_enable) {
-        /* Reset SLEEPDEEP bit of Cortex System Control Register. */
-        SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        SystemClockConfig_Resume();
-    }
-
-    furi_hal_vcp_on_usb_resume();
-
-    USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** ISOOUTIncomplete callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
-}
-
-/** ISOINIncomplete callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
-}
-
-/** Connect callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Disconnect callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Initializes the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) {
-    /* Init USB Ip. */
-    hpcd_USB_FS.pData = pdev;
-
-    /* Link the driver to the stack. */
-    pdev->pData = &hpcd_USB_FS;
-
-    /* Enable USB power on Pwrctrl CR2 register. */
-    HAL_PWREx_EnableVddUSB();
-
-    hpcd_USB_FS.Instance = USB;
-    hpcd_USB_FS.Init.dev_endpoints = 8;
-    hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
-    hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
-    hpcd_USB_FS.Init.Sof_enable = DISABLE;
-    hpcd_USB_FS.Init.low_power_enable = DISABLE;
-    hpcd_USB_FS.Init.lpm_enable = DISABLE;
-    hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
-
-    if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) {
-        Error_Handler();
-    }
-
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
-
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100);
-
-    return USBD_OK;
-}
-
-/** De-Initializes the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
-{
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_DeInit(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Starts the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_Start(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Stops the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_Stop(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Opens an endpoint of the low level driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  ep_type: Endpoint type
- * @param  ep_mps: Endpoint max packet size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Closes an endpoint of the low level driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/**
- * @brief  Flushes an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Sets a Stall condition on an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Clears a Stall condition on an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Returns Stall condition.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval Stall (1: Yes, 0: No)
- */
-uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
-
-    if((ep_addr & 0x80) == 0x80)
-    {
-        return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
-    }
-    else
-    {
-        return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
-    }
-}
-
-/** Assigns a USB address to the device.
- * @param  pdev: Device handle
- * @param  dev_addr: Device address
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Transmits data over an endpoint.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  pbuf: Pointer to data to be sent
- * @param  size: Data size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Prepares an endpoint for reception.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  pbuf: Pointer to data to be received
- * @param  size: Data size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Returns the last transfered packet size.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval Recived Data Size
- */
-uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr);
-}
-
-/** Send LPM message to user layer
- * @param  hpcd: PCD handle
- * @param  msg: LPM message
- * @retval None
- */
-void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) {
-    switch (msg) {
-    case PCD_LPM_L0_ACTIVE:
-        if (hpcd->Init.low_power_enable) {
-            SystemClockConfig_Resume();
-            /* Reset SLEEPDEEP bit of Cortex System Control Register. */
-            SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        }
-        USBD_LL_Resume(hpcd->pData);
-        break;
-
-    case PCD_LPM_L1_ACTIVE:
-        USBD_LL_Suspend(hpcd->pData);
-
-        /* Enter in STOP mode. */
-        if (hpcd->Init.low_power_enable) {
-            /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
-            SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        }
-        break;
-    }
-}
-
-/** Delays routine for the USB Device Library.
- * @param  Delay: Delay in ms
- * @retval None
- */
-void USBD_LL_Delay(uint32_t Delay) {
-    HAL_Delay(Delay);
-}
-
-/** Static single allocation.
- * @param  size: Size of allocated memory
- * @retval None
- */
-void *USBD_static_malloc(uint32_t size) {
-    static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */
-    return mem;
-}
-
-/** Dummy memory free
- * @param  p: Pointer to allocated  memory address
- * @retval None
- */
-void USBD_static_free(void *p) {
-}
-
-/** Configures system clock after wake-up from USB resume callBack:
- * enable HSI, PLL and select PLL as system clock source.
- * @retval None
- */
-static void SystemClockConfig_Resume(void) {
-}
-
-/** Retuns the USB status depending on the HAL status:
- * @param  hal_status: HAL status
- * @retval USB status
- */
-USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status) {
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    switch (hal_status)
-    {
-        case HAL_OK :
-            usb_status = USBD_OK;
-        break;
-        case HAL_ERROR :
-            usb_status = USBD_FAIL;
-        break;
-        case HAL_BUSY :
-            usb_status = USBD_BUSY;
-        break;
-        case HAL_TIMEOUT :
-            usb_status = USBD_FAIL;
-        break;
-        default :
-            usb_status = USBD_FAIL;
-        break;
-    }
-    return usb_status;
-}

+ 0 - 73
firmware/targets/f6/usb-glue/usbd_conf.h

@@ -1,73 +0,0 @@
-#pragma once
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#define USBD_MAX_NUM_INTERFACES     1U
-#define USBD_MAX_NUM_CONFIGURATION  1U
-#define USBD_MAX_STR_DESC_SIZ       512U
-#define USBD_DEBUG_LEVEL            0U
-#define USBD_LPM_ENABLED            0U
-#define USBD_SELF_POWERED           0U
-
-/****************************************/
-/* #define for FS and HS identification */
-#define DEVICE_FS 0
-
-/* Memory management macros */
-
-/** Alias for memory allocation. */
-#define USBD_malloc         (void *)USBD_static_malloc
-
-/** Alias for memory release. */
-#define USBD_free           USBD_static_free
-
-/** Alias for memory set. */
-#define USBD_memset         memset
-
-/** Alias for memory copy. */
-#define USBD_memcpy         memcpy
-
-/** Alias for delay. */
-#define USBD_Delay          HAL_Delay
-
-/* DEBUG macros */
-
-#if (USBD_DEBUG_LEVEL > 0)
-#define USBD_UsrLog(...)    printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_UsrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 1)
-
-#define USBD_ErrLog(...)    printf("ERROR: ") ;\
-                            printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_ErrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 2)
-#define USBD_DbgLog(...)    printf("DEBUG : ") ;\
-                            printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_DbgLog(...)
-#endif
-
-void *USBD_static_malloc(uint32_t size);
-void USBD_static_free(void *p);
-
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 206
firmware/targets/f6/usb-glue/usbd_desc.c

@@ -1,206 +0,0 @@
-#include "usbd_core.h"
-#include "usbd_desc.h"
-#include "usbd_conf.h"
-#include "furi-hal-version.h"
-
-#define USBD_VID                    1155
-#define USBD_LANGID_STRING          1033
-#define USBD_MANUFACTURER_STRING    "Flipper Devices Inc."
-#define USBD_PID                    22336
-#define USBD_CONFIGURATION_STRING   "CDC Config"
-#define USBD_INTERFACE_STRING       "CDC Interface"
-
-static void Get_SerialNum(void);
-static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len);
-
-uint8_t* USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-
-USBD_DescriptorsTypeDef CDC_Desc = {
-    USBD_CDC_DeviceDescriptor,
-    USBD_CDC_LangIDStrDescriptor,
-    USBD_CDC_ManufacturerStrDescriptor,
-    USBD_CDC_ProductStrDescriptor,
-    USBD_CDC_SerialStrDescriptor,
-    USBD_CDC_ConfigStrDescriptor,
-    USBD_CDC_InterfaceStrDescriptor
-};
-
-/** USB standard device descriptor. */
-__ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
-    0x12,                       /*bLength */
-    USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
-    0x00,                       /*bcdUSB */
-    0x02,
-    0x02,                       /*bDeviceClass*/
-    0x02,                       /*bDeviceSubClass*/
-    0x00,                       /*bDeviceProtocol*/
-    USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
-    LOBYTE(USBD_VID),           /*idVendor*/
-    HIBYTE(USBD_VID),           /*idVendor*/
-    LOBYTE(USBD_PID),           /*idProduct*/
-    HIBYTE(USBD_PID),           /*idProduct*/
-    0x00,                       /*bcdDevice rel. 2.00*/
-    0x02,
-    USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
-    USBD_IDX_PRODUCT_STR,       /*Index of product string*/
-    USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
-    USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
-};
-
-/* USB_DeviceDescriptor */
-
-/** USB lang indentifier descriptor. */
-__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
-    USB_LEN_LANGID_STR_DESC,
-    USB_DESC_TYPE_STRING,
-    LOBYTE(USBD_LANGID_STRING),
-    HIBYTE(USBD_LANGID_STRING)
-};
-
-/* Internal string descriptor. */
-__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
-
-__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
-    USB_SIZ_STRING_SERIAL,
-    USB_DESC_TYPE_STRING,
-};
-
-/** Return the device descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = sizeof(USBD_CDC_DeviceDesc);
-    return USBD_CDC_DeviceDesc;
-}
-
-/** Return the LangID string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = sizeof(USBD_LangIDDesc);
-    return USBD_LangIDDesc;
-}
-
-/** Return the product string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    USBD_GetString((uint8_t*)furi_hal_version_get_device_name_ptr(), USBD_StrDesc, length);
-    return USBD_StrDesc;
-}
-
-/** Return the manufacturer string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
-    return USBD_StrDesc;
-}
-
-/** Return the serial number string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = USB_SIZ_STRING_SERIAL;
-
-    /* Update the serial number string descriptor with the data from the unique
-     * ID */
-    if(furi_hal_version_get_name_ptr()){
-        char buffer[14] = "flip_";
-        strncat(buffer, furi_hal_version_get_name_ptr(), 8);
-        USBD_GetString((uint8_t*) buffer, USBD_StringSerial, length);
-    } else {
-        Get_SerialNum();
-    }
-
-    return (uint8_t *) USBD_StringSerial;
-}
-
-/** Return the configuration string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    if(speed == USBD_SPEED_HIGH) {
-        USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
-    } else {
-        USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
-    }
-    return USBD_StrDesc;
-}
-
-/** Return the interface string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    if(speed == 0) {
-        USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
-    } else {
-        USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
-    }
-    return USBD_StrDesc;
-}
-
-/** Create the serial number string descriptor
- * @param  None
- * @retval None
- */
-static void Get_SerialNum(void) {
-    uint32_t deviceserial0, deviceserial1, deviceserial2;
-
-    deviceserial0 = *(uint32_t *) DEVICE_ID1;
-    deviceserial1 = *(uint32_t *) DEVICE_ID2;
-    deviceserial2 = *(uint32_t *) DEVICE_ID3;
-
-    deviceserial0 += deviceserial2;
-
-    if (deviceserial0 != 0) {
-        IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8);
-        IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4);
-    }
-}
-
-/** Convert Hex 32Bits value into char
- * @param  value: value to convert
- * @param  pbuf: pointer to the buffer
- * @param  len: buffer length
- * @retval None
- */
-static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len) {
-    uint8_t idx = 0;
-
-    for (idx = 0; idx < len; idx++) {
-        if (((value >> 28)) < 0xA) {
-            pbuf[2 * idx] = (value >> 28) + '0';
-        } else {
-            pbuf[2 * idx] = (value >> 28) + 'A' - 10;
-        }
-
-        value = value << 4;
-
-        pbuf[2 * idx + 1] = 0;
-    }
-}

+ 0 - 19
firmware/targets/f6/usb-glue/usbd_desc.h

@@ -1,19 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "usbd_def.h"
-
-#define DEVICE_ID1 (UID_BASE)
-#define DEVICE_ID2 (UID_BASE + 0x4)
-#define DEVICE_ID3 (UID_BASE + 0x8)
-
-#define USB_SIZ_STRING_SERIAL 0x1E
-
-extern USBD_DescriptorsTypeDef CDC_Desc;
-
-#ifdef __cplusplus
-}
-#endif

+ 52 - 0
firmware/targets/f7/Inc/stm32.h

@@ -0,0 +1,52 @@
+#ifndef _STM32_H_
+#define _STM32_H_
+
+/* modify bitfield */
+#define _BMD(reg, msk, val)     (reg) = (((reg) & ~(msk)) | (val))
+/* set bitfield */
+#define _BST(reg, bits)         (reg) = ((reg) | (bits))
+/* clear bitfield */
+#define _BCL(reg, bits)         (reg) = ((reg) & ~(bits))
+/* wait until bitfield set */
+#define _WBS(reg, bits)         while(((reg) & (bits)) == 0)
+/* wait until bitfield clear */
+#define _WBC(reg, bits)         while(((reg) & (bits)) != 0)
+/* wait for bitfield value */
+#define _WVL(reg, msk, val)     while(((reg) & (msk)) != (val))
+/* bit value */
+#define _BV(bit)                (0x01 << (bit))
+
+#if defined(STM32F0)
+    #include "STM32F0xx/Include/stm32f0xx.h"
+#elif defined(STM32F1)
+    #include "STM32F1xx/Include/stm32f1xx.h"
+#elif defined(STM32F2)
+    #include "STM32F2xx/Include/stm32f2xx.h"
+#elif defined(STM32F3)
+    #include "STM32F3xx/Include/stm32f3xx.h"
+#elif defined(STM32F4)
+    #include "STM32F4xx/Include/stm32f4xx.h"
+#elif defined(STM32F7)
+    #include "STM32F7xx/Include/stm32f7xx.h"
+#elif defined(STM32H7)
+    #include "STM32H7xx/Include/stm32h7xx.h"
+#elif defined(STM32L0)
+    #include "STM32L0xx/Include/stm32l0xx.h"
+#elif defined(STM32L1)
+    #include "STM32L1xx/Include/stm32l1xx.h"
+#elif defined(STM32L4)
+    #include "STM32L4xx/Include/stm32l4xx.h"
+#elif defined(STM32L5)
+    #include "STM32L5xx/Include/stm32l5xx.h"
+#elif defined(STM32G0)
+    #include "STM32G0xx/Include/stm32g0xx.h"
+#elif defined(STM32G4)
+    #include "STM32G4xx/Include/stm32g4xx.h"
+#elif defined(STM32WB)
+    #include "STM32WBxx/Include/stm32wbxx.h"
+#else
+    #error "STM32 family not defined"
+#endif
+
+
+#endif // _STM32_H_

+ 3 - 2
firmware/targets/f7/Src/stm32wbxx_it.c

@@ -2,8 +2,9 @@
 #include "stm32wbxx_it.h"
 #include "FreeRTOS.h"
 #include "task.h"
+#include "usbd_core.h"
 
-extern PCD_HandleTypeDef hpcd_USB_FS;
+extern usbd_device udev;
 extern COMP_HandleTypeDef hcomp1;
 extern RTC_HandleTypeDef hrtc;
 extern TIM_HandleTypeDef htim1;
@@ -20,7 +21,7 @@ void SysTick_Handler(void) {
 }
 
 void USB_LP_IRQHandler(void) {
-    HAL_PCD_IRQHandler(&hpcd_USB_FS);
+    usbd_poll(&udev);
 }
 
 void COMP_IRQHandler(void) {

+ 555 - 0
firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c

@@ -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 - 0
firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h

@@ -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 - 0
firmware/targets/f7/furi-hal/furi-hal-usb-hid.c

@@ -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 - 0
firmware/targets/f7/furi-hal/furi-hal-usb.c

@@ -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 - 0
firmware/targets/f7/furi-hal/furi-hal-usb_i.h

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

+ 37 - 26
firmware/targets/f7/furi-hal/furi-hal-vcp.c

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

+ 2 - 2
firmware/targets/f7/furi-hal/furi-hal-vcp_i.h

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

+ 0 - 4
firmware/targets/f7/furi-hal/furi-hal-version.c

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

+ 2 - 2
firmware/targets/f7/furi-hal/furi-hal.c

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

+ 4 - 11
firmware/targets/f7/target.mk

@@ -38,6 +38,7 @@ CFLAGS += \
 CFLAGS += \
 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
+	-I$(CUBE_DIR)/Drivers/CMSIS/Device/ST \
 	-I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include \
 	-I$(CUBE_DIR)/Drivers/CMSIS/Include
 C_SOURCES += \
@@ -69,7 +70,6 @@ C_SOURCES += \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
-	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c
 
 # FreeRTOS
@@ -116,17 +116,10 @@ C_SOURCES += \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c
 
-# USB glue 
+# USB stack
 CFLAGS += \
-	-I$(TARGET_DIR)/usb-glue \
-	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
-	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
-C_SOURCES += \
-	$(wildcard $(TARGET_DIR)/usb-glue/*.c) \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
+	-DSTM32WB \
+	-DUSB_PMASIZE=0x400
 
 # Furi HAL
 FURI_HAL_OS_DEBUG ?= 0

+ 0 - 34
firmware/targets/f7/usb-glue/usb_device.c

@@ -1,34 +0,0 @@
-#include "usb_device.h"
-
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#include "usbd_def.h"
-#include "usbd_core.h"
-#include "usbd_desc.h"
-#include "usbd_cdc.h"
-#include "usbd_cdc_if.h"
-
-extern void Error_Handler(void);
-
-/* USB Device Core handle declaration. */
-USBD_HandleTypeDef hUsbDeviceFS;
-
-extern USBD_DescriptorsTypeDef CDC_Desc;
-
-/** Init USB device Library, add supported class and start the library */
-void MX_USB_Device_Init(void) {
-    /* Init Device Library, add supported class and start the library. */
-    if (USBD_Init(&hUsbDeviceFS, &CDC_Desc, DEVICE_FS) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) {
-        Error_Handler();
-    }
-    if (USBD_Start(&hUsbDeviceFS) != USBD_OK) {
-        Error_Handler();
-    }
-}

+ 0 - 11
firmware/targets/f7/usb-glue/usb_device.h

@@ -1,11 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-void MX_USB_Device_Init();
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 142
firmware/targets/f7/usb-glue/usbd_cdc_if.c

@@ -1,142 +0,0 @@
-#include "usbd_cdc_if.h"
-#include <furi-hal-vcp_i.h>
-
-extern USBD_HandleTypeDef hUsbDeviceFS;
-
-static int8_t CDC_Init_FS(void);
-static int8_t CDC_DeInit_FS(void);
-static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
-static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
-static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);
-
-USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
-{
-    CDC_Init_FS,
-    CDC_DeInit_FS,
-    CDC_Control_FS,
-    CDC_Receive_FS,
-    CDC_TransmitCplt_FS
-};
-
-uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
-uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
-
-/** Initializes the CDC media low layer over the FS USB IP
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Init_FS(void) {
-    /* Set Application Buffers */
-    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
-    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
-    return (USBD_OK);
-}
-
-/**
- * @brief  DeInitializes the CDC media low layer
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_DeInit_FS(void) {
-    return (USBD_OK);
-}
-
-/** Manage the CDC class requests
- * @param  cmd: Command code
- * @param  pbuf: Buffer containing command data (request parameters)
- * @param  length: Number of data to be sent (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) {
-    if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) {
-    } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) {
-    } else if (cmd == CDC_SET_COMM_FEATURE) {
-    } else if (cmd == CDC_GET_COMM_FEATURE) {
-    } else if (cmd == CDC_CLEAR_COMM_FEATURE) {
-    } else if (cmd == CDC_SET_LINE_CODING) {
-        /*******************************************************************************/
-        /* Line Coding Structure                                                       */
-        /*-----------------------------------------------------------------------------*/
-        /* Offset | Field       | Size | Value  | Description                          */
-        /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
-        /* 4      | bCharFormat |   1  | Number | Stop bits                            */
-        /*                                        0 - 1 Stop bit                       */
-        /*                                        1 - 1.5 Stop bits                    */
-        /*                                        2 - 2 Stop bits                      */
-        /* 5      | bParityType |  1   | Number | Parity                               */
-        /*                                        0 - None                             */
-        /*                                        1 - Odd                              */
-        /*                                        2 - Even                             */
-        /*                                        3 - Mark                             */
-        /*                                        4 - Space                            */
-        /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
-        /*******************************************************************************/
-    } else if (cmd == CDC_GET_LINE_CODING) {
-    } else if (cmd == CDC_SET_CONTROL_LINE_STATE) {
-        furi_hal_vcp_on_cdc_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue);
-    } else if (cmd == CDC_SEND_BREAK) {
-    } else {
-    }
-
-    return (USBD_OK);
-}
-
-/** Data received over USB OUT endpoint are sent over CDC interface through this function.
- *
- * @note
- * This function will issue a NAK packet on any OUT packet received on
- * USB endpoint until exiting this function. If you exit this function
- * before transfer is complete on CDC interface (ie. using DMA controller)
- * it will result in receiving more data while previous ones are still
- * not sent.
- *
- * @param  Buf: Buffer of data to be received
- * @param  Len: Number of data received (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) {
-    if (*Len) {
-        furi_hal_vcp_on_cdc_rx(Buf, *Len);
-    } else {
-        USBD_CDC_ReceivePacket(&hUsbDeviceFS);
-    }
-    
-    return (USBD_OK);
-}
-
-/** CDC_Transmit_FS Data to send over USB IN endpoint are sent over CDC interface
- * through this function.
- * @param  Buf: Buffer of data to be sent
- * @param  Len: Number of data to be sent (in bytes)
- * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
- */
-uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
-{
-    uint8_t result = USBD_OK;
-
-    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
-    if (hcdc->TxState != 0){
-        return USBD_BUSY;
-    }
-    memcpy(UserTxBufferFS, Buf, Len);
-    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
-    result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
-
-    return result;
-}
-
-/** CDC_TransmitCplt_FS Data transmited callback
- *
- * @note
- * This function is IN transfer complete callback used to inform user that
- * the submitted Data is successfully sent over USB.
- *
- * @param  Buf: Buffer of data to be received
- * @param  Len: Number of data received (in bytes)
- * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
- */
-static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) {
-    uint8_t result = USBD_OK;
-
-    furi_hal_vcp_on_cdc_tx_complete(*Len);
-
-    return result;
-}

+ 0 - 22
firmware/targets/f7/usb-glue/usbd_cdc_if.h

@@ -1,22 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_cdc.h"
-
-/* Define size for the receive and transmit buffer over CDC */
-/* It's up to user to redefine and/or remove those define */
-#define APP_RX_DATA_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
-#define APP_TX_DATA_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
-
-/** CDC Interface callback. */
-extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
-
-uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 506
firmware/targets/f7/usb-glue/usbd_conf.c

@@ -1,506 +0,0 @@
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#include <furi-hal-vcp_i.h>
-
-#include "usbd_def.h"
-#include "usbd_core.h"
-#include "usbd_cdc.h"
-
-PCD_HandleTypeDef hpcd_USB_FS;
-void Error_Handler(void);
-
-static USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status);
-
-static void SystemClockConfig_Resume(void);
-
-void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) {
-    GPIO_InitTypeDef GPIO_InitStruct = {0};
-    if(pcdHandle->Instance==USB) {
-        __HAL_RCC_GPIOA_CLK_ENABLE();
-        /**USB GPIO Configuration
-        PA11     ------> USB_DM
-        PA12     ------> USB_DP 
-        */
-        GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
-        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-        GPIO_InitStruct.Pull = GPIO_NOPULL;
-        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
-        GPIO_InitStruct.Alternate = GPIO_AF10_USB;
-        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
-        /* Peripheral clock enable */
-        __HAL_RCC_USB_CLK_ENABLE();
-
-        /* Peripheral interrupt init */
-        HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0);
-        HAL_NVIC_EnableIRQ(USB_LP_IRQn);
-    }
-}
-
-void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) {
-    if(pcdHandle->Instance==USB) {
-        /* Peripheral clock disable */
-        __HAL_RCC_USB_CLK_DISABLE();
-
-        /**USB GPIO Configuration
-        PA11     ------> USB_DM
-        PA12     ------> USB_DP
-        */
-        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
-
-        /* Peripheral interrupt Deinit*/
-        HAL_NVIC_DisableIRQ(USB_LP_IRQn);
-    }
-}
-
-/** Setup stage callback
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
-}
-
-/** Data Out stage callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
-}
-
-/** Data In stage callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
-}
-
-/** SOF callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Reset callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
-
-    if ( hpcd->Init.speed != PCD_SPEED_FULL) {
-        Error_Handler();
-    }
-
-    /* Set Speed. */
-    USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed);
-
-    /* Reset Device. */
-    USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Suspend callback.
- * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
-
-    furi_hal_vcp_on_usb_suspend();
-    
-    if (hpcd->Init.low_power_enable) {
-        /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
-        SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-    }
-}
-
-/** Resume callback.
- * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) {
-    if (hpcd->Init.low_power_enable) {
-        /* Reset SLEEPDEEP bit of Cortex System Control Register. */
-        SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        SystemClockConfig_Resume();
-    }
-
-    furi_hal_vcp_on_usb_resume();
-
-    USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** ISOOUTIncomplete callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
-}
-
-/** ISOINIncomplete callback.
- * @param  hpcd: PCD handle
- * @param  epnum: Endpoint number
- * @retval None
- */
-void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
-    USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
-}
-
-/** Connect callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Disconnect callback.
- * @param  hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) {
-    USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
-}
-
-/** Initializes the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) {
-    /* Init USB Ip. */
-    hpcd_USB_FS.pData = pdev;
-
-    /* Link the driver to the stack. */
-    pdev->pData = &hpcd_USB_FS;
-
-    /* Enable USB power on Pwrctrl CR2 register. */
-    HAL_PWREx_EnableVddUSB();
-
-    hpcd_USB_FS.Instance = USB;
-    hpcd_USB_FS.Init.dev_endpoints = 8;
-    hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
-    hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
-    hpcd_USB_FS.Init.Sof_enable = DISABLE;
-    hpcd_USB_FS.Init.low_power_enable = DISABLE;
-    hpcd_USB_FS.Init.lpm_enable = DISABLE;
-    hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
-
-    if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) {
-        Error_Handler();
-    }
-
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
-
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110);
-    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100);
-
-    return USBD_OK;
-}
-
-/** De-Initializes the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
-{
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_DeInit(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Starts the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_Start(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Stops the low level portion of the device driver.
- * @param  pdev: Device handle
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_Stop(pdev->pData);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Opens an endpoint of the low level driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  ep_type: Endpoint type
- * @param  ep_mps: Endpoint max packet size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Closes an endpoint of the low level driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/**
- * @brief  Flushes an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Sets a Stall condition on an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Clears a Stall condition on an endpoint of the Low Level Driver.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Returns Stall condition.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval Stall (1: Yes, 0: No)
- */
-uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
-
-    if((ep_addr & 0x80) == 0x80)
-    {
-        return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
-    }
-    else
-    {
-        return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
-    }
-}
-
-/** Assigns a USB address to the device.
- * @param  pdev: Device handle
- * @param  dev_addr: Device address
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Transmits data over an endpoint.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  pbuf: Pointer to data to be sent
- * @param  size: Data size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Prepares an endpoint for reception.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @param  pbuf: Pointer to data to be received
- * @param  size: Data size
- * @retval USBD status
- */
-USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) {
-    HAL_StatusTypeDef hal_status = HAL_OK;
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
-
-    usb_status =  USBD_Get_USB_Status(hal_status);
-
-    return usb_status;
-}
-
-/** Returns the last transfered packet size.
- * @param  pdev: Device handle
- * @param  ep_addr: Endpoint number
- * @retval Recived Data Size
- */
-uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
-    return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr);
-}
-
-/** Send LPM message to user layer
- * @param  hpcd: PCD handle
- * @param  msg: LPM message
- * @retval None
- */
-void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) {
-    switch (msg) {
-    case PCD_LPM_L0_ACTIVE:
-        if (hpcd->Init.low_power_enable) {
-            SystemClockConfig_Resume();
-            /* Reset SLEEPDEEP bit of Cortex System Control Register. */
-            SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        }
-        USBD_LL_Resume(hpcd->pData);
-        break;
-
-    case PCD_LPM_L1_ACTIVE:
-        USBD_LL_Suspend(hpcd->pData);
-
-        /* Enter in STOP mode. */
-        if (hpcd->Init.low_power_enable) {
-            /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
-            SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
-        }
-        break;
-    }
-}
-
-/** Delays routine for the USB Device Library.
- * @param  Delay: Delay in ms
- * @retval None
- */
-void USBD_LL_Delay(uint32_t Delay) {
-    HAL_Delay(Delay);
-}
-
-/** Static single allocation.
- * @param  size: Size of allocated memory
- * @retval None
- */
-void *USBD_static_malloc(uint32_t size) {
-    static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */
-    return mem;
-}
-
-/** Dummy memory free
- * @param  p: Pointer to allocated  memory address
- * @retval None
- */
-void USBD_static_free(void *p) {
-}
-
-/** Configures system clock after wake-up from USB resume callBack:
- * enable HSI, PLL and select PLL as system clock source.
- * @retval None
- */
-static void SystemClockConfig_Resume(void) {
-}
-
-/** Retuns the USB status depending on the HAL status:
- * @param  hal_status: HAL status
- * @retval USB status
- */
-USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status) {
-    USBD_StatusTypeDef usb_status = USBD_OK;
-
-    switch (hal_status)
-    {
-        case HAL_OK :
-            usb_status = USBD_OK;
-        break;
-        case HAL_ERROR :
-            usb_status = USBD_FAIL;
-        break;
-        case HAL_BUSY :
-            usb_status = USBD_BUSY;
-        break;
-        case HAL_TIMEOUT :
-            usb_status = USBD_FAIL;
-        break;
-        default :
-            usb_status = USBD_FAIL;
-        break;
-    }
-    return usb_status;
-}

+ 0 - 73
firmware/targets/f7/usb-glue/usbd_conf.h

@@ -1,73 +0,0 @@
-#pragma once
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "stm32wbxx.h"
-#include "stm32wbxx_hal.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#define USBD_MAX_NUM_INTERFACES     1U
-#define USBD_MAX_NUM_CONFIGURATION  1U
-#define USBD_MAX_STR_DESC_SIZ       512U
-#define USBD_DEBUG_LEVEL            0U
-#define USBD_LPM_ENABLED            0U
-#define USBD_SELF_POWERED           0U
-
-/****************************************/
-/* #define for FS and HS identification */
-#define DEVICE_FS 0
-
-/* Memory management macros */
-
-/** Alias for memory allocation. */
-#define USBD_malloc         (void *)USBD_static_malloc
-
-/** Alias for memory release. */
-#define USBD_free           USBD_static_free
-
-/** Alias for memory set. */
-#define USBD_memset         memset
-
-/** Alias for memory copy. */
-#define USBD_memcpy         memcpy
-
-/** Alias for delay. */
-#define USBD_Delay          HAL_Delay
-
-/* DEBUG macros */
-
-#if (USBD_DEBUG_LEVEL > 0)
-#define USBD_UsrLog(...)    printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_UsrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 1)
-
-#define USBD_ErrLog(...)    printf("ERROR: ") ;\
-                            printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_ErrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 2)
-#define USBD_DbgLog(...)    printf("DEBUG : ") ;\
-                            printf(__VA_ARGS__);\
-                            printf("\n");
-#else
-#define USBD_DbgLog(...)
-#endif
-
-void *USBD_static_malloc(uint32_t size);
-void USBD_static_free(void *p);
-
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 206
firmware/targets/f7/usb-glue/usbd_desc.c

@@ -1,206 +0,0 @@
-#include "usbd_core.h"
-#include "usbd_desc.h"
-#include "usbd_conf.h"
-#include "furi-hal-version.h"
-
-#define USBD_VID                    1155
-#define USBD_LANGID_STRING          1033
-#define USBD_MANUFACTURER_STRING    "Flipper Devices Inc."
-#define USBD_PID                    22336
-#define USBD_CONFIGURATION_STRING   "CDC Config"
-#define USBD_INTERFACE_STRING       "CDC Interface"
-
-static void Get_SerialNum(void);
-static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len);
-
-uint8_t* USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-uint8_t* USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
-
-USBD_DescriptorsTypeDef CDC_Desc = {
-    USBD_CDC_DeviceDescriptor,
-    USBD_CDC_LangIDStrDescriptor,
-    USBD_CDC_ManufacturerStrDescriptor,
-    USBD_CDC_ProductStrDescriptor,
-    USBD_CDC_SerialStrDescriptor,
-    USBD_CDC_ConfigStrDescriptor,
-    USBD_CDC_InterfaceStrDescriptor
-};
-
-/** USB standard device descriptor. */
-__ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
-    0x12,                       /*bLength */
-    USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
-    0x00,                       /*bcdUSB */
-    0x02,
-    0x02,                       /*bDeviceClass*/
-    0x02,                       /*bDeviceSubClass*/
-    0x00,                       /*bDeviceProtocol*/
-    USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
-    LOBYTE(USBD_VID),           /*idVendor*/
-    HIBYTE(USBD_VID),           /*idVendor*/
-    LOBYTE(USBD_PID),           /*idProduct*/
-    HIBYTE(USBD_PID),           /*idProduct*/
-    0x00,                       /*bcdDevice rel. 2.00*/
-    0x02,
-    USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
-    USBD_IDX_PRODUCT_STR,       /*Index of product string*/
-    USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
-    USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
-};
-
-/* USB_DeviceDescriptor */
-
-/** USB lang indentifier descriptor. */
-__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
-    USB_LEN_LANGID_STR_DESC,
-    USB_DESC_TYPE_STRING,
-    LOBYTE(USBD_LANGID_STRING),
-    HIBYTE(USBD_LANGID_STRING)
-};
-
-/* Internal string descriptor. */
-__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
-
-__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
-    USB_SIZ_STRING_SERIAL,
-    USB_DESC_TYPE_STRING,
-};
-
-/** Return the device descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = sizeof(USBD_CDC_DeviceDesc);
-    return USBD_CDC_DeviceDesc;
-}
-
-/** Return the LangID string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = sizeof(USBD_LangIDDesc);
-    return USBD_LangIDDesc;
-}
-
-/** Return the product string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    USBD_GetString((uint8_t*)furi_hal_version_get_device_name_ptr(), USBD_StrDesc, length);
-    return USBD_StrDesc;
-}
-
-/** Return the manufacturer string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
-    return USBD_StrDesc;
-}
-
-/** Return the serial number string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    UNUSED(speed);
-    *length = USB_SIZ_STRING_SERIAL;
-
-    /* Update the serial number string descriptor with the data from the unique
-     * ID */
-    if(furi_hal_version_get_name_ptr()){
-        char buffer[14] = "flip_";
-        strncat(buffer, furi_hal_version_get_name_ptr(), 8);
-        USBD_GetString((uint8_t*) buffer, USBD_StringSerial, length);
-    } else {
-        Get_SerialNum();
-    }
-
-    return (uint8_t *) USBD_StringSerial;
-}
-
-/** Return the configuration string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    if(speed == USBD_SPEED_HIGH) {
-        USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
-    } else {
-        USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
-    }
-    return USBD_StrDesc;
-}
-
-/** Return the interface string descriptor
- * @param  speed : Current device speed
- * @param  length : Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
-    if(speed == 0) {
-        USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
-    } else {
-        USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
-    }
-    return USBD_StrDesc;
-}
-
-/** Create the serial number string descriptor
- * @param  None
- * @retval None
- */
-static void Get_SerialNum(void) {
-    uint32_t deviceserial0, deviceserial1, deviceserial2;
-
-    deviceserial0 = *(uint32_t *) DEVICE_ID1;
-    deviceserial1 = *(uint32_t *) DEVICE_ID2;
-    deviceserial2 = *(uint32_t *) DEVICE_ID3;
-
-    deviceserial0 += deviceserial2;
-
-    if (deviceserial0 != 0) {
-        IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8);
-        IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4);
-    }
-}
-
-/** Convert Hex 32Bits value into char
- * @param  value: value to convert
- * @param  pbuf: pointer to the buffer
- * @param  len: buffer length
- * @retval None
- */
-static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len) {
-    uint8_t idx = 0;
-
-    for (idx = 0; idx < len; idx++) {
-        if (((value >> 28)) < 0xA) {
-            pbuf[2 * idx] = (value >> 28) + '0';
-        } else {
-            pbuf[2 * idx] = (value >> 28) + 'A' - 10;
-        }
-
-        value = value << 4;
-
-        pbuf[2 * idx + 1] = 0;
-    }
-}

+ 0 - 19
firmware/targets/f7/usb-glue/usbd_desc.h

@@ -1,19 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "usbd_def.h"
-
-#define DEVICE_ID1 (UID_BASE)
-#define DEVICE_ID2 (UID_BASE + 0x4)
-#define DEVICE_ID3 (UID_BASE + 0x8)
-
-#define USB_SIZ_STRING_SERIAL 0x1E
-
-extern USBD_DescriptorsTypeDef CDC_Desc;
-
-#ifdef __cplusplus
-}
-#endif

+ 21 - 0
firmware/targets/furi-hal-include/furi-hal-usb.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "usb.h"
+
+typedef enum {
+    UsbModeNone,
+    UsbModeVcpSingle,
+    UsbModeVcpDual,
+    UsbModeHid,
+    UsbModeU2F,
+
+    UsbModesNum,
+} UsbMode;
+
+void furi_hal_usb_init();
+
+void furi_hal_usb_set_config(UsbMode mode);
+
+void furi_hal_usb_disable();
+
+void furi_hal_usb_enable();

+ 5 - 0
firmware/targets/furi-hal-include/furi-hal-version.h

@@ -14,6 +14,11 @@
 extern "C" {
 #endif
 
+#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)
+
 /** Device Colors */
 typedef enum {
     FuriHalVersionColorUnknown=0x00,

+ 1 - 0
firmware/targets/furi-hal-include/furi-hal.h

@@ -33,6 +33,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
 #include "furi-hal-ibutton.h"
 #include "furi-hal-rfid.h"
 #include "furi-hal-nfc.h"
+#include "furi-hal-usb.h"
 
 /** Init furi-hal */
 void furi_hal_init();

+ 4 - 0
lib/lib.mk

@@ -108,3 +108,7 @@ CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp)
 
 # Toolbox
 C_SOURCES		+= $(wildcard $(LIB_DIR)/toolbox/*.c)
+
+# USB Stack
+CFLAGS			+= -I$(LIB_DIR)/libusb_stm32/inc
+C_SOURCES		+= $(wildcard $(LIB_DIR)/libusb_stm32/src/*.c)

+ 1 - 0
lib/libusb_stm32

@@ -0,0 +1 @@
+Subproject commit fe3890e10e35a837184cb05f835ef6ab14bfd04f