[FL-1857] New USB stack (#735)
* libusb_stm32 USB stack test * USB: Add dual CDC mode * USB HID demo, added libusb_stm32 as submodule * Target F6/F7: remomve unused ll_usb Co-authored-by: n.minaylov <n.minaylov@flipperdevices.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									42e553bad5
								
							
						
					
					
						commit
						e0c1928fde
					
				
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -7,3 +7,6 @@ | |||||||
| [submodule "lib/littlefs"] | [submodule "lib/littlefs"] | ||||||
| 	path = lib/littlefs | 	path = lib/littlefs | ||||||
| 	url = https://github.com/littlefs-project/littlefs.git | 	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
									
								
								applications/applications.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										5
									
								
								applications/applications.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -33,6 +33,7 @@ extern int32_t storage_test_app(void* p); | |||||||
| extern int32_t subghz_app(void* p); | extern int32_t subghz_app(void* p); | ||||||
| extern int32_t vibro_test_app(void* p); | extern int32_t vibro_test_app(void* p); | ||||||
| extern int32_t bt_debug_app(void* p); | extern int32_t bt_debug_app(void* p); | ||||||
|  | extern int32_t usb_test_app(void* p); | ||||||
| 
 | 
 | ||||||
| // Plugins
 | // Plugins
 | ||||||
| extern int32_t music_player_app(void* p); | 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}, |     {.app = accessor_app, .name = "Accessor", .stack_size = 4096, .icon = &A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef APP_USB_TEST | ||||||
|  |     {.app = usb_test_app, .name = "USB Test", .stack_size = 1024, .icon = &A_Plugins_14}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef APP_UNIT_TESTS | #ifdef APP_UNIT_TESTS | ||||||
|     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = &A_Plugins_14}, |     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = &A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ APP_KEYPAD_TEST = 1 | |||||||
| APP_SD_TEST	= 1 | APP_SD_TEST	= 1 | ||||||
| APP_UNIT_TESTS = 0 | APP_UNIT_TESTS = 0 | ||||||
| APP_VIBRO_DEMO = 1 | APP_VIBRO_DEMO = 1 | ||||||
|  | APP_USB_TEST = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -121,6 +122,14 @@ SRV_GUI		= 1 | |||||||
| endif | 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 | APP_KEYPAD_TEST ?= 0 | ||||||
| ifeq ($(APP_KEYPAD_TEST), 1) | ifeq ($(APP_KEYPAD_TEST), 1) | ||||||
| CFLAGS		+= -DAPP_KEYPAD_TEST | CFLAGS		+= -DAPP_KEYPAD_TEST | ||||||
|  | |||||||
							
								
								
									
										102
									
								
								applications/debug_tools/usb_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								applications/debug_tools/usb_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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
									
								
								firmware/targets/f6/Inc/stm32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								firmware/targets/f6/Inc/stm32.h
									
									
									
									
									
										Normal file
									
								
							| @ -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_
 | ||||||
| @ -2,8 +2,9 @@ | |||||||
| #include "stm32wbxx_it.h" | #include "stm32wbxx_it.h" | ||||||
| #include "FreeRTOS.h" | #include "FreeRTOS.h" | ||||||
| #include "task.h" | #include "task.h" | ||||||
|  | #include "usbd_core.h" | ||||||
| 
 | 
 | ||||||
| extern PCD_HandleTypeDef hpcd_USB_FS; | extern usbd_device udev; | ||||||
| extern COMP_HandleTypeDef hcomp1; | extern COMP_HandleTypeDef hcomp1; | ||||||
| extern RTC_HandleTypeDef hrtc; | extern RTC_HandleTypeDef hrtc; | ||||||
| extern TIM_HandleTypeDef htim1; | extern TIM_HandleTypeDef htim1; | ||||||
| @ -20,7 +21,7 @@ void SysTick_Handler(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void USB_LP_IRQHandler(void) { | void USB_LP_IRQHandler(void) { | ||||||
|     HAL_PCD_IRQHandler(&hpcd_USB_FS); |     usbd_poll(&udev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void COMP_IRQHandler(void) { | void COMP_IRQHandler(void) { | ||||||
|  | |||||||
							
								
								
									
										555
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,555 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-vcp_i.h" | ||||||
|  | #include "furi-hal-usb-cdc_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_cdc.h" | ||||||
|  | 
 | ||||||
|  | #define CDC0_RXD_EP      0x01 | ||||||
|  | #define CDC0_TXD_EP      0x82 | ||||||
|  | #define CDC0_NTF_EP      0x83 | ||||||
|  | 
 | ||||||
|  | #define CDC1_RXD_EP      0x04 | ||||||
|  | #define CDC1_TXD_EP      0x85 | ||||||
|  | #define CDC1_NTF_EP      0x86 | ||||||
|  | 
 | ||||||
|  | #define CDC_NTF_SZ      0x08 | ||||||
|  | 
 | ||||||
|  | struct CdcIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor           comm_iad; | ||||||
|  |     struct usb_interface_descriptor     comm; | ||||||
|  |     struct usb_cdc_header_desc          cdc_hdr; | ||||||
|  |     struct usb_cdc_call_mgmt_desc       cdc_mgmt; | ||||||
|  |     struct usb_cdc_acm_desc             cdc_acm; | ||||||
|  |     struct usb_cdc_union_desc           cdc_union; | ||||||
|  |     struct usb_endpoint_descriptor      comm_ep; | ||||||
|  |     struct usb_interface_descriptor     data; | ||||||
|  |     struct usb_endpoint_descriptor      data_eprx; | ||||||
|  |     struct usb_endpoint_descriptor      data_eptx; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct CdcConfigDescriptorSingle { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct CdcIadDescriptor             iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | struct CdcConfigDescriptorDual { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct CdcIadDescriptor             iad_0; | ||||||
|  |     struct CdcIadDescriptor             iad_1; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor cdc_device_desc = { | ||||||
|  |     .bLength            = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType    = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB             = VERSION_BCD(2,0,0), | ||||||
|  |     .bDeviceClass       = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass    = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol    = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0    = USB_EP0_SIZE, | ||||||
|  |     .idVendor           = 0x0483, | ||||||
|  |     .idProduct          = 0x5740, | ||||||
|  |     .bcdDevice          = VERSION_BCD(1,0,0), | ||||||
|  |     .iManufacturer      = UsbDevManuf, | ||||||
|  |     .iProduct           = UsbDevProduct, | ||||||
|  |     .iSerialNumber      = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor - single mode*/ | ||||||
|  | static const struct CdcConfigDescriptorSingle cdc_cfg_desc_single = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct CdcConfigDescriptorSingle), | ||||||
|  |         .bNumInterfaces         = 2, | ||||||
|  | 
 | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 0, | ||||||
|  |             .bSlaveInterface0       = 1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor - dual mode*/ | ||||||
|  | static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct CdcConfigDescriptorDual), | ||||||
|  |         .bNumInterfaces         = 4, | ||||||
|  | 
 | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 0, | ||||||
|  |             .bSlaveInterface0       = 1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  |     .iad_1 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 2, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 2+0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 2+1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 2+0, | ||||||
|  |             .bSlaveInterface0       = 2+1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 2+1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct usb_cdc_line_coding cdc_line = { | ||||||
|  |     .dwDTERate          = 38400, | ||||||
|  |     .bCharFormat        = USB_CDC_1_STOP_BITS, | ||||||
|  |     .bParityType        = USB_CDC_NO_PARITY, | ||||||
|  |     .bDataBits          = 8, | ||||||
|  | }; | ||||||
|  | static void cdc_init(usbd_device* dev, struct UsbInterface* intf); | ||||||
|  | static void cdc_deinit(usbd_device *dev); | ||||||
|  | static void cdc_on_wakeup(usbd_device *dev); | ||||||
|  | static void cdc_on_suspend(usbd_device *dev); | ||||||
|  | 
 | ||||||
|  | static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg); | ||||||
|  | static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | static struct UsbInterface* cdc_if_cur = NULL; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_cdc_single = { | ||||||
|  |     .init = cdc_init, | ||||||
|  |     .deinit = cdc_deinit, | ||||||
|  |     .wakeup = cdc_on_wakeup, | ||||||
|  |     .suspend = cdc_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = NULL, | ||||||
|  |     .str_serial_descr = NULL, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&cdc_cfg_desc_single, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_cdc_dual = { | ||||||
|  |     .init = cdc_init, | ||||||
|  |     .deinit = cdc_deinit, | ||||||
|  |     .wakeup = cdc_on_wakeup, | ||||||
|  |     .suspend = cdc_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = NULL, | ||||||
|  |     .str_serial_descr = NULL, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&cdc_cfg_desc_dual, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void cdc_init(usbd_device* dev, struct UsbInterface* intf) { | ||||||
|  |     usb_dev = dev; | ||||||
|  |     cdc_if_cur = intf; | ||||||
|  |      | ||||||
|  |     char* name = (char*)furi_hal_version_get_device_name_ptr(); | ||||||
|  |     uint8_t len = (name == NULL) ? (0) : (strlen(name)); | ||||||
|  |     struct usb_string_descriptor* dev_prod_desc = furi_alloc(len * 2 + 2); | ||||||
|  |     dev_prod_desc->bLength = len * 2 + 2; | ||||||
|  |     dev_prod_desc->bDescriptorType = USB_DTYPE_STRING; | ||||||
|  |     for (uint8_t i = 0; i < len; i++) | ||||||
|  |         dev_prod_desc->wString[i] = name[i]; | ||||||
|  | 
 | ||||||
|  |     name = (char*)furi_hal_version_get_name_ptr(); | ||||||
|  |     len = (name == NULL) ? (0) : (strlen(name)); | ||||||
|  |     struct usb_string_descriptor* dev_serial_desc = furi_alloc((len + 5) * 2 + 2); | ||||||
|  |     dev_serial_desc->bLength = (len + 5) * 2 + 2; | ||||||
|  |     dev_serial_desc->bDescriptorType = USB_DTYPE_STRING; | ||||||
|  |     memcpy(dev_serial_desc->wString, "f\0l\0i\0p\0_\0", 5*2); | ||||||
|  |     for (uint8_t i = 0; i < len; i++) | ||||||
|  |         dev_serial_desc->wString[i+5] = name[i]; | ||||||
|  | 
 | ||||||
|  |     cdc_if_cur->str_prod_descr = dev_prod_desc; | ||||||
|  |     cdc_if_cur->str_serial_descr = dev_serial_desc; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, cdc_ep_config); | ||||||
|  |     usbd_reg_control(dev, cdc_control);     | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_deinit(usbd_device *dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | 
 | ||||||
|  |     free(cdc_if_cur->str_prod_descr); | ||||||
|  |     free(cdc_if_cur->str_serial_descr); | ||||||
|  | 
 | ||||||
|  |     cdc_if_cur = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) { | ||||||
|  |     if (if_num == 0) | ||||||
|  |         usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len); | ||||||
|  |     else | ||||||
|  |         usbd_ep_write(usb_dev, CDC1_TXD_EP, buf, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) { | ||||||
|  |     if (if_num == 0) | ||||||
|  |         return usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); | ||||||
|  |     else | ||||||
|  |         return usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_on_wakeup(usbd_device *dev) { | ||||||
|  |     furi_hal_vcp_on_usb_resume(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_on_suspend(usbd_device *dev) { | ||||||
|  |     furi_hal_vcp_on_usb_suspend(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (ep == CDC0_RXD_EP) | ||||||
|  |         furi_hal_vcp_on_cdc_rx(0); | ||||||
|  |     else | ||||||
|  |         furi_hal_vcp_on_cdc_rx(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (ep == CDC0_TXD_EP) | ||||||
|  |         furi_hal_vcp_on_cdc_tx_complete(0); | ||||||
|  |     else | ||||||
|  |         furi_hal_vcp_on_cdc_tx_complete(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (event == usbd_evt_eptx) { | ||||||
|  |         cdc_tx_ep_callback(dev, event, ep); | ||||||
|  |     } else { | ||||||
|  |         cdc_rx_ep_callback(dev, event, ep); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) { | ||||||
|  |     uint8_t if_cnt = ((struct usb_config_descriptor*)(cdc_if_cur->cfg_descr))->bNumInterfaces; | ||||||
|  |     switch (cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_NTF_EP); | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_TXD_EP); | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_RXD_EP); | ||||||
|  |         usbd_reg_endpoint(dev, CDC0_RXD_EP, 0); | ||||||
|  |         usbd_reg_endpoint(dev, CDC0_TXD_EP, 0); | ||||||
|  |         if (if_cnt == 4) { | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_NTF_EP); | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_TXD_EP); | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_RXD_EP); | ||||||
|  |             usbd_reg_endpoint(dev, CDC1_RXD_EP, 0); | ||||||
|  |             usbd_reg_endpoint(dev, CDC1_TXD_EP, 0); | ||||||
|  |         } | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) { | ||||||
|  |             usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_rx_ep_callback); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_tx_ep_callback); | ||||||
|  |         } else { | ||||||
|  |             usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_txrx_ep_callback); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_txrx_ep_callback); | ||||||
|  |         } | ||||||
|  |         usbd_ep_write(dev, CDC0_TXD_EP, 0, 0); | ||||||
|  | 
 | ||||||
|  |         if (if_cnt == 4) { | ||||||
|  |             if ((CDC1_TXD_EP & 0x7F) != (CDC1_RXD_EP & 0x7F)) { | ||||||
|  |                 usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_rx_ep_callback); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_tx_ep_callback); | ||||||
|  |             } else { | ||||||
|  |                 usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_txrx_ep_callback); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_txrx_ep_callback); | ||||||
|  |             } | ||||||
|  |             usbd_ep_write(dev, CDC1_TXD_EP, 0, 0); | ||||||
|  |         } | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { | ||||||
|  |     /* CDC control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS) | ||||||
|  |         && req->wIndex == 0 ) { | ||||||
|  |         switch (req->bRequest) { | ||||||
|  |         case USB_CDC_SET_CONTROL_LINE_STATE: | ||||||
|  |             furi_hal_vcp_on_cdc_control_line(req->wValue); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_CDC_SET_LINE_CODING: | ||||||
|  |             memcpy(&cdc_line, req->data, sizeof(cdc_line)); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_CDC_GET_LINE_CODING: | ||||||
|  |             dev->status.data_ptr = &cdc_line; | ||||||
|  |             dev->status.data_count = sizeof(cdc_line); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #define CDC_DATA_SZ     0x40 | ||||||
|  | 
 | ||||||
|  | void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len); | ||||||
|  | 
 | ||||||
|  | int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len); | ||||||
							
								
								
									
										264
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-hid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-hid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,264 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_hid.h" | ||||||
|  | #include "hid_usage_desktop.h" | ||||||
|  | #include "hid_usage_button.h" | ||||||
|  | 
 | ||||||
|  | #define HID_RIN_EP      0x81 | ||||||
|  | #define HID_RIN_SZ      0x10 | ||||||
|  | 
 | ||||||
|  | struct HidIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor           hid_iad; | ||||||
|  |     struct usb_interface_descriptor     hid; | ||||||
|  |     struct usb_hid_descriptor           hid_desc; | ||||||
|  |     struct usb_endpoint_descriptor      hid_ep;     | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HidConfigDescriptor { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct HidIadDescriptor             iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | /* HID mouse report desscriptor. 2 axis 5 buttons */ | ||||||
|  | static const uint8_t hid_report_desc[] = { | ||||||
|  |     HID_USAGE_PAGE(HID_PAGE_DESKTOP), | ||||||
|  |     HID_USAGE(HID_DESKTOP_MOUSE), | ||||||
|  |     HID_COLLECTION(HID_APPLICATION_COLLECTION), | ||||||
|  |         HID_USAGE(HID_DESKTOP_POINTER), | ||||||
|  |         HID_COLLECTION(HID_PHYSICAL_COLLECTION), | ||||||
|  |             HID_USAGE(HID_DESKTOP_X), | ||||||
|  |             HID_USAGE(HID_DESKTOP_Y), | ||||||
|  |             HID_LOGICAL_MINIMUM(-127), | ||||||
|  |             HID_LOGICAL_MAXIMUM(127), | ||||||
|  |             HID_REPORT_SIZE(8), | ||||||
|  |             HID_REPORT_COUNT(2), | ||||||
|  |             HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE ), | ||||||
|  |             HID_USAGE_PAGE(HID_PAGE_BUTTON), | ||||||
|  |             HID_USAGE_MINIMUM(1), | ||||||
|  |             HID_USAGE_MAXIMUM(5), | ||||||
|  |             HID_LOGICAL_MINIMUM(0), | ||||||
|  |             HID_LOGICAL_MAXIMUM(1), | ||||||
|  |             HID_REPORT_SIZE(1), | ||||||
|  |             HID_REPORT_COUNT(5), | ||||||
|  |             HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE ), | ||||||
|  |             HID_REPORT_SIZE(1), | ||||||
|  |             HID_REPORT_COUNT(3), | ||||||
|  |             HID_INPUT(HID_IOF_CONSTANT), | ||||||
|  |         HID_END_COLLECTION, | ||||||
|  |     HID_END_COLLECTION, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Logitech"); | ||||||
|  | static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("USB Receiver"); | ||||||
|  | static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("1234567890"); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor hid_device_desc = { | ||||||
|  |     .bLength            = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType    = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB             = VERSION_BCD(2,0,0), | ||||||
|  |     .bDeviceClass       = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass    = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol    = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0    = USB_EP0_SIZE, | ||||||
|  |     .idVendor           = 0x046d, | ||||||
|  |     .idProduct          = 0xc529, | ||||||
|  |     .bcdDevice          = VERSION_BCD(1,0,0), | ||||||
|  |     .iManufacturer      = UsbDevManuf, | ||||||
|  |     .iProduct           = UsbDevProduct, | ||||||
|  |     .iSerialNumber      = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor */ | ||||||
|  | static const struct HidConfigDescriptor hid_cfg_desc = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct HidConfigDescriptor), | ||||||
|  |         .bNumInterfaces         = 1, | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .hid_iad = { | ||||||
|  |             .bLength = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 1, | ||||||
|  |             .bFunctionClass         = USB_CLASS_PER_INTERFACE, | ||||||
|  |             .bFunctionSubClass      = USB_SUBCLASS_NONE, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .hid = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_HID, | ||||||
|  |             .bInterfaceSubClass     = USB_HID_SUBCLASS_NONBOOT, | ||||||
|  |             .bInterfaceProtocol     = USB_HID_PROTO_NONBOOT, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .hid_desc = { | ||||||
|  |             .bLength                = sizeof(struct usb_hid_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_HID, | ||||||
|  |             .bcdHID                 = VERSION_BCD(1,0,0), | ||||||
|  |             .bCountryCode           = USB_HID_COUNTRY_NONE, | ||||||
|  |             .bNumDescriptors        = 1, | ||||||
|  |             .bDescriptorType0       = USB_DTYPE_HID_REPORT, | ||||||
|  |             .wDescriptorLength0     = sizeof(hid_report_desc), | ||||||
|  |         }, | ||||||
|  |         .hid_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = HID_RIN_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = HID_RIN_SZ, | ||||||
|  |             .bInterval              = 50, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct { | ||||||
|  |     int8_t      x; | ||||||
|  |     int8_t      y; | ||||||
|  |     uint8_t     buttons; | ||||||
|  | } __attribute__((packed)) hid_report_data; | ||||||
|  | 
 | ||||||
|  | static void hid_init(usbd_device* dev, struct UsbInterface* intf); | ||||||
|  | static void hid_deinit(usbd_device *dev); | ||||||
|  | static void hid_on_wakeup(usbd_device *dev); | ||||||
|  | static void hid_on_suspend(usbd_device *dev); | ||||||
|  | 
 | ||||||
|  | static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg); | ||||||
|  | static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_hid = { | ||||||
|  |     .init = hid_init, | ||||||
|  |     .deinit = hid_deinit, | ||||||
|  |     .wakeup = hid_on_wakeup, | ||||||
|  |     .suspend = hid_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = (void*)&dev_prod_desc, | ||||||
|  |     .str_serial_descr = (void*)&dev_serial_desc, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&hid_cfg_desc, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_init(usbd_device* dev, struct UsbInterface* intf) { | ||||||
|  |     usb_dev = dev; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, hid_ep_config); | ||||||
|  |     usbd_reg_control(dev, hid_control);     | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_deinit(usbd_device *dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_on_wakeup(usbd_device *dev) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_on_suspend(usbd_device *dev) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* HID mouse IN endpoint callback */ | ||||||
|  | static void hid_mouse_move(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     static uint8_t t = 0; | ||||||
|  |     if (t < 0x10) { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = 0; | ||||||
|  |     } else if (t < 0x20) { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x30) { | ||||||
|  |         hid_report_data.x = 0; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x40) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x50) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = 0; | ||||||
|  |     } else if (t < 0x60) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } else if (t < 0x70) { | ||||||
|  |         hid_report_data.x = 0; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } else  { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } | ||||||
|  |     t = (t + 1) & 0x7F; | ||||||
|  |     usbd_ep_write(dev, ep, &hid_report_data, sizeof(hid_report_data)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg) { | ||||||
|  |     switch (cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, HID_RIN_EP); | ||||||
|  |         usbd_reg_endpoint(dev, HID_RIN_EP, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         usbd_ep_config(dev, HID_RIN_EP, USB_EPTYPE_INTERRUPT, HID_RIN_SZ); | ||||||
|  |         usbd_reg_endpoint(dev, HID_RIN_EP, hid_mouse_move); | ||||||
|  |         usbd_ep_write(dev, HID_RIN_EP, 0, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { | ||||||
|  |     /* HID control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS) | ||||||
|  |         && req->wIndex == 0 ) { | ||||||
|  |         switch (req->bRequest) { | ||||||
|  |         case USB_HID_SETIDLE: | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_HID_GETREPORT: | ||||||
|  |             dev->status.data_ptr = &hid_report_data; | ||||||
|  |             dev->status.data_count = sizeof(hid_report_data); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_STANDARD) | ||||||
|  |         && req->wIndex == 0 | ||||||
|  |         && req->bRequest == USB_STD_GET_DESCRIPTOR) { | ||||||
|  |         switch (req->wValue >> 8) { | ||||||
|  |         case USB_DTYPE_HID: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.iad_0.hid_desc); | ||||||
|  |             dev->status.data_count = sizeof(hid_cfg_desc.iad_0.hid_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_DTYPE_HID_REPORT: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)hid_report_desc; | ||||||
|  |             dev->status.data_count = sizeof(hid_report_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
							
								
								
									
										164
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,164 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-usb.h" | ||||||
|  | #include "furi-hal-vcp_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | 
 | ||||||
|  | #define USB_RECONNECT_DELAY 500 | ||||||
|  | 
 | ||||||
|  | extern struct UsbInterface usb_cdc_single; | ||||||
|  | extern struct UsbInterface usb_cdc_dual; | ||||||
|  | extern struct UsbInterface usb_hid; | ||||||
|  | 
 | ||||||
|  | static struct UsbInterface* const usb_if_modes[UsbModesNum] = { | ||||||
|  |     NULL, | ||||||
|  |     &usb_cdc_single, | ||||||
|  |     &usb_cdc_dual, | ||||||
|  |     &usb_hid, | ||||||
|  |     NULL,//&usb_hid_u2f,
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); | ||||||
|  | 
 | ||||||
|  | static uint32_t ubuf[0x20]; | ||||||
|  | usbd_device udev; | ||||||
|  | 
 | ||||||
|  | static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length); | ||||||
|  | static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep); | ||||||
|  | static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep); | ||||||
|  | 
 | ||||||
|  | struct UsbCfg{ | ||||||
|  |     osTimerId_t reconnect_tmr; | ||||||
|  |     UsbMode mode_cur; | ||||||
|  |     UsbMode mode_next; | ||||||
|  |     bool enabled; | ||||||
|  | } usb_config; | ||||||
|  | 
 | ||||||
|  | static void furi_hal_usb_tmr_cb(void* context); | ||||||
|  | 
 | ||||||
|  | /* Low-level init */ | ||||||
|  | void furi_hal_usb_init(void) { | ||||||
|  |      | ||||||
|  |     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||||
|  |     LL_PWR_EnableVddUSB(); | ||||||
|  |      | ||||||
|  |     GPIO_InitStruct.Pin = LL_GPIO_PIN_11 | LL_GPIO_PIN_12; | ||||||
|  |     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||||
|  |     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; | ||||||
|  |     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||||
|  |     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||||
|  |     GPIO_InitStruct.Alternate = LL_GPIO_AF_10; | ||||||
|  |     LL_GPIO_Init(GPIOA, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |     usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); | ||||||
|  |     usbd_enable(&udev, true); | ||||||
|  | 
 | ||||||
|  |     usbd_reg_descr(&udev, usb_descriptor_get); | ||||||
|  |     usbd_reg_event(&udev, usbd_evt_susp, susp_evt); | ||||||
|  |     usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); | ||||||
|  | 
 | ||||||
|  |     usb_config.enabled = false; | ||||||
|  |     usb_config.reconnect_tmr = NULL; | ||||||
|  |     HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); | ||||||
|  |     NVIC_EnableIRQ(USB_LP_IRQn); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I("FuriHalUsb", "Init OK"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_set_config(UsbMode new_mode) { | ||||||
|  |     if (new_mode != usb_config.mode_cur) { | ||||||
|  |         if (usb_config.enabled) { | ||||||
|  |             usb_config.mode_next = new_mode; | ||||||
|  |             if (usb_config.reconnect_tmr == NULL) | ||||||
|  |                 usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); | ||||||
|  |             furi_hal_usb_disable(); | ||||||
|  |             osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |                 usb_if_modes[usb_config.mode_cur]->deinit(&udev); | ||||||
|  |             if (usb_if_modes[new_mode] != NULL) { | ||||||
|  |                 usb_if_modes[new_mode]->init(&udev, usb_if_modes[new_mode]); | ||||||
|  |                 FURI_LOG_I("FuriHalUsb", "USB mode change %u -> %u", usb_config.mode_cur, new_mode); | ||||||
|  |                 usb_config.enabled = true; | ||||||
|  |                 usb_config.mode_cur = new_mode; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_disable() { | ||||||
|  |     if (usb_config.enabled) { | ||||||
|  |         susp_evt(&udev, 0, 0); | ||||||
|  |         usbd_connect(&udev, false); | ||||||
|  |         usb_config.enabled = false; | ||||||
|  |         FURI_LOG_I("FuriHalUsb", "USB Disable"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_enable() { | ||||||
|  |     if ((!usb_config.enabled) && (usb_if_modes[usb_config.mode_cur] != NULL)) { | ||||||
|  |         usbd_connect(&udev, true); | ||||||
|  |         usb_config.enabled = true; | ||||||
|  |         FURI_LOG_I("FuriHalUsb", "USB Enable"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_usb_tmr_cb(void* context) { | ||||||
|  |     furi_hal_usb_set_config(usb_config.mode_next); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Get device / configuration descriptors */ | ||||||
|  | static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length) { | ||||||
|  |     const uint8_t dtype = req->wValue >> 8; | ||||||
|  |     const uint8_t dnumber = req->wValue & 0xFF; | ||||||
|  |     const void* desc; | ||||||
|  |     uint16_t len = 0; | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] == NULL) | ||||||
|  |         return usbd_fail; | ||||||
|  | 
 | ||||||
|  |     switch (dtype) { | ||||||
|  |     case USB_DTYPE_DEVICE: | ||||||
|  |         desc = usb_if_modes[usb_config.mode_cur]->dev_descr; | ||||||
|  |         break; | ||||||
|  |     case USB_DTYPE_CONFIGURATION: | ||||||
|  |         desc = usb_if_modes[usb_config.mode_cur]->cfg_descr; | ||||||
|  |         len = ((struct usb_string_descriptor*)(usb_if_modes[usb_config.mode_cur]->cfg_descr))->wString[0]; | ||||||
|  |         break; | ||||||
|  |     case USB_DTYPE_STRING: | ||||||
|  |         if (dnumber == UsbDevLang) { | ||||||
|  |             desc = &dev_lang_desc; | ||||||
|  |         } else if (dnumber == UsbDevManuf) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_manuf_descr; | ||||||
|  |         } else if (dnumber == UsbDevProduct) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_prod_descr; | ||||||
|  |         } else if (dnumber == UsbDevSerial) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_serial_descr; | ||||||
|  |         } else  | ||||||
|  |             return usbd_fail; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  |     if (desc == NULL) | ||||||
|  |         return usbd_fail; | ||||||
|  | 
 | ||||||
|  |     if (len == 0) { | ||||||
|  |         len = ((struct usb_header_descriptor*)desc)->bLength; | ||||||
|  |     } | ||||||
|  |     *address = (void*)desc; | ||||||
|  |     *length = len; | ||||||
|  |     return usbd_ack; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |         usb_if_modes[usb_config.mode_cur]->suspend(&udev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |         usb_if_modes[usb_config.mode_cur]->wakeup(&udev); | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | 
 | ||||||
|  | #define USB_EP0_SIZE 8 | ||||||
|  | 
 | ||||||
|  | /* String descriptors */ | ||||||
|  | enum UsbDevDescStr{ | ||||||
|  |     UsbDevLang      = 0, | ||||||
|  |     UsbDevManuf     = 1, | ||||||
|  |     UsbDevProduct   = 2, | ||||||
|  |     UsbDevSerial    = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface { | ||||||
|  |     void (*init)(usbd_device *dev, struct UsbInterface* intf); | ||||||
|  |     void (*deinit)(usbd_device *dev); | ||||||
|  |     void (*wakeup)(usbd_device *dev); | ||||||
|  |     void (*suspend)(usbd_device *dev);     | ||||||
|  | 
 | ||||||
|  |     struct usb_device_descriptor* dev_descr; | ||||||
|  | 
 | ||||||
|  |     void* str_manuf_descr; | ||||||
|  |     void* str_prod_descr; | ||||||
|  |     void* str_serial_descr; | ||||||
|  | 
 | ||||||
|  |     void* cfg_descr; | ||||||
|  | }; | ||||||
| @ -1,12 +1,12 @@ | |||||||
| #include <furi-hal-vcp_i.h> | #include <furi-hal-vcp_i.h> | ||||||
|  | #include <furi-hal-usb-cdc_i.h> | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <usbd_cdc_if.h> |  | ||||||
| #include <stream_buffer.h> | #include <stream_buffer.h> | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 5) | #define APP_RX_DATA_SIZE CDC_DATA_SZ | ||||||
| 
 | #define APP_TX_DATA_SIZE CDC_DATA_SZ | ||||||
| extern USBD_HandleTypeDef hUsbDeviceFS; | #define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16) | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     volatile bool connected; |     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_soh = 0x01; | ||||||
| static const uint8_t ascii_eot = 0x04; | static const uint8_t ascii_eot = 0x04; | ||||||
| 
 | 
 | ||||||
|  | static uint8_t* vcp_rx_buf; | ||||||
|  | 
 | ||||||
| void furi_hal_vcp_init() { | void furi_hal_vcp_init() { | ||||||
|     furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); |     furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); | ||||||
|  |     vcp_rx_buf = furi_alloc(APP_RX_DATA_SIZE); | ||||||
|     furi_hal_vcp->connected = false; |     furi_hal_vcp->connected = false; | ||||||
|      |      | ||||||
|     furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1); |     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); |     size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); | ||||||
| 
 | 
 | ||||||
|     if(furi_hal_vcp->rx_stream_full |     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; |         furi_hal_vcp->rx_stream_full = false; | ||||||
|         // data accepted, start waiting for next packet
 |  | ||||||
|         USBD_CDC_ReceivePacket(&hUsbDeviceFS); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return received; |     return received; | ||||||
| @ -67,13 +68,9 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { | |||||||
|             batch_size = APP_TX_DATA_SIZE; |             batch_size = APP_TX_DATA_SIZE; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) { |         furi_hal_cdc_send(0, (uint8_t*)buffer, batch_size); | ||||||
|         size -= batch_size; |         size -= batch_size; | ||||||
|         buffer += batch_size; |         buffer += batch_size; | ||||||
|         } else { |  | ||||||
|             FURI_LOG_E("FuriHalVcp", "CDC_Transmit_FS failed"); |  | ||||||
|             osDelay(50); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -89,6 +86,8 @@ void furi_hal_vcp_on_usb_suspend() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | ||||||
|  | 
 | ||||||
|  |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
|     // bit 0: DTR state, bit 1: RTS state
 |     // bit 0: DTR state, bit 1: RTS state
 | ||||||
|     // bool dtr = state & 0b01;
 |     // bool dtr = state & 0b01;
 | ||||||
|     bool dtr = state & 0b1; |     bool dtr = state & 0b1; | ||||||
| @ -96,33 +95,45 @@ void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | |||||||
|     if (dtr) { |     if (dtr) { | ||||||
|         if (!furi_hal_vcp->connected) { |         if (!furi_hal_vcp->connected) { | ||||||
|             furi_hal_vcp->connected = true; |             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 { |     } else { | ||||||
|         if (furi_hal_vcp->connected) { |         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; |             furi_hal_vcp->connected = false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     osSemaphoreRelease(furi_hal_vcp->tx_semaphore); |     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; |     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) { |     if (if_num == 0) { | ||||||
|         USBD_CDC_ReceivePacket(&hUsbDeviceFS); |         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 { |         } else { | ||||||
|             furi_hal_vcp->rx_stream_full = true; |             furi_hal_vcp->rx_stream_full = true; | ||||||
|  |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_tx_complete(size_t size) { | void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num) { | ||||||
|  |     if (if_num == 0) | ||||||
|         osSemaphoreRelease(furi_hal_vcp->tx_semaphore); |         osSemaphoreRelease(furi_hal_vcp->tx_semaphore); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,6 +8,6 @@ void furi_hal_vcp_on_usb_suspend(); | |||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_control_line(uint8_t state); | void furi_hal_vcp_on_cdc_control_line(uint8_t state); | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size); | void furi_hal_vcp_on_cdc_rx(uint8_t if_num); | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_tx_complete(size_t size); | void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num); | ||||||
|  | |||||||
| @ -8,10 +8,6 @@ | |||||||
| #include "ble.h" | #include "ble.h" | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | #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 | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
| 
 | 
 | ||||||
| /** OTP Versions enum */ | /** OTP Versions enum */ | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ | |||||||
| #include <comp.h> | #include <comp.h> | ||||||
| #include <rtc.h> | #include <rtc.h> | ||||||
| #include <tim.h> | #include <tim.h> | ||||||
| #include <usb_device.h> |  | ||||||
| #include <gpio.h> | #include <gpio.h> | ||||||
| 
 | 
 | ||||||
| void furi_hal_init() { | void furi_hal_init() { | ||||||
| @ -35,7 +34,8 @@ void furi_hal_init() { | |||||||
| 
 | 
 | ||||||
|     // VCP + USB
 |     // VCP + USB
 | ||||||
|     furi_hal_vcp_init(); |     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_LOG_I("HAL", "USB OK"); | ||||||
| 
 | 
 | ||||||
|     furi_hal_i2c_init(); |     furi_hal_i2c_init(); | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ CFLAGS += \ | |||||||
| CFLAGS += \
 | CFLAGS += \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 | 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
 | 	-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/Device/ST/STM32WBxx/Include \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/CMSIS/Include | 	-I$(CUBE_DIR)/Drivers/CMSIS/Include | ||||||
| C_SOURCES += \
 | 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_spi.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.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_usart.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 |  | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | ||||||
| 
 | 
 | ||||||
| # FreeRTOS
 | # 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/tl/shci_tl_if.c \
 | ||||||
| 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c | 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c | ||||||
| 
 | 
 | ||||||
| # USB glue 
 | # USB stack
 | ||||||
| CFLAGS += \
 | CFLAGS += \
 | ||||||
| 	-I$(TARGET_DIR)/usb-glue \
 | 	-DSTM32WB \
 | ||||||
| 	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
 | 	-DUSB_PMASIZE=0x400 | ||||||
| 	-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 |  | ||||||
| 
 | 
 | ||||||
| # Furi HAL
 | # Furi HAL
 | ||||||
| FURI_HAL_OS_DEBUG ?= 0 | FURI_HAL_OS_DEBUG ?= 0 | ||||||
|  | |||||||
| @ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
|  extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| void MX_USB_Device_Init(); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @ -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; |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -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; |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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
									
								
								firmware/targets/f7/Inc/stm32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								firmware/targets/f7/Inc/stm32.h
									
									
									
									
									
										Normal file
									
								
							| @ -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_
 | ||||||
| @ -2,8 +2,9 @@ | |||||||
| #include "stm32wbxx_it.h" | #include "stm32wbxx_it.h" | ||||||
| #include "FreeRTOS.h" | #include "FreeRTOS.h" | ||||||
| #include "task.h" | #include "task.h" | ||||||
|  | #include "usbd_core.h" | ||||||
| 
 | 
 | ||||||
| extern PCD_HandleTypeDef hpcd_USB_FS; | extern usbd_device udev; | ||||||
| extern COMP_HandleTypeDef hcomp1; | extern COMP_HandleTypeDef hcomp1; | ||||||
| extern RTC_HandleTypeDef hrtc; | extern RTC_HandleTypeDef hrtc; | ||||||
| extern TIM_HandleTypeDef htim1; | extern TIM_HandleTypeDef htim1; | ||||||
| @ -20,7 +21,7 @@ void SysTick_Handler(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void USB_LP_IRQHandler(void) { | void USB_LP_IRQHandler(void) { | ||||||
|     HAL_PCD_IRQHandler(&hpcd_USB_FS); |     usbd_poll(&udev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void COMP_IRQHandler(void) { | void COMP_IRQHandler(void) { | ||||||
|  | |||||||
							
								
								
									
										555
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,555 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-vcp_i.h" | ||||||
|  | #include "furi-hal-usb-cdc_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_cdc.h" | ||||||
|  | 
 | ||||||
|  | #define CDC0_RXD_EP      0x01 | ||||||
|  | #define CDC0_TXD_EP      0x82 | ||||||
|  | #define CDC0_NTF_EP      0x83 | ||||||
|  | 
 | ||||||
|  | #define CDC1_RXD_EP      0x04 | ||||||
|  | #define CDC1_TXD_EP      0x85 | ||||||
|  | #define CDC1_NTF_EP      0x86 | ||||||
|  | 
 | ||||||
|  | #define CDC_NTF_SZ      0x08 | ||||||
|  | 
 | ||||||
|  | struct CdcIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor           comm_iad; | ||||||
|  |     struct usb_interface_descriptor     comm; | ||||||
|  |     struct usb_cdc_header_desc          cdc_hdr; | ||||||
|  |     struct usb_cdc_call_mgmt_desc       cdc_mgmt; | ||||||
|  |     struct usb_cdc_acm_desc             cdc_acm; | ||||||
|  |     struct usb_cdc_union_desc           cdc_union; | ||||||
|  |     struct usb_endpoint_descriptor      comm_ep; | ||||||
|  |     struct usb_interface_descriptor     data; | ||||||
|  |     struct usb_endpoint_descriptor      data_eprx; | ||||||
|  |     struct usb_endpoint_descriptor      data_eptx; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct CdcConfigDescriptorSingle { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct CdcIadDescriptor             iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | struct CdcConfigDescriptorDual { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct CdcIadDescriptor             iad_0; | ||||||
|  |     struct CdcIadDescriptor             iad_1; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor cdc_device_desc = { | ||||||
|  |     .bLength            = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType    = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB             = VERSION_BCD(2,0,0), | ||||||
|  |     .bDeviceClass       = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass    = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol    = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0    = USB_EP0_SIZE, | ||||||
|  |     .idVendor           = 0x0483, | ||||||
|  |     .idProduct          = 0x5740, | ||||||
|  |     .bcdDevice          = VERSION_BCD(1,0,0), | ||||||
|  |     .iManufacturer      = UsbDevManuf, | ||||||
|  |     .iProduct           = UsbDevProduct, | ||||||
|  |     .iSerialNumber      = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor - single mode*/ | ||||||
|  | static const struct CdcConfigDescriptorSingle cdc_cfg_desc_single = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct CdcConfigDescriptorSingle), | ||||||
|  |         .bNumInterfaces         = 2, | ||||||
|  | 
 | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 0, | ||||||
|  |             .bSlaveInterface0       = 1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor - dual mode*/ | ||||||
|  | static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct CdcConfigDescriptorDual), | ||||||
|  |         .bNumInterfaces         = 4, | ||||||
|  | 
 | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 0, | ||||||
|  |             .bSlaveInterface0       = 1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC0_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  |     .iad_1 = { | ||||||
|  |         .comm_iad = { | ||||||
|  |             .bLength                = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 2, | ||||||
|  |             .bInterfaceCount        = 2, | ||||||
|  |             .bFunctionClass         = USB_CLASS_CDC, | ||||||
|  |             .bFunctionSubClass      = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .comm = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 2+0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC, | ||||||
|  |             .bInterfaceSubClass     = USB_CDC_SUBCLASS_ACM, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .cdc_hdr = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_header_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_HEADER, | ||||||
|  |             .bcdCDC                 = VERSION_BCD(1,1,0), | ||||||
|  |         }, | ||||||
|  |         .cdc_mgmt = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_call_mgmt_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_CALL_MANAGEMENT, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |             .bDataInterface         = 2+1, | ||||||
|  |         }, | ||||||
|  |         .cdc_acm = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_acm_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_ACM, | ||||||
|  |             .bmCapabilities         = 0, | ||||||
|  |         }, | ||||||
|  |         .cdc_union = { | ||||||
|  |             .bFunctionLength        = sizeof(struct usb_cdc_union_desc), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_CS_INTERFACE, | ||||||
|  |             .bDescriptorSubType     = USB_DTYPE_CDC_UNION, | ||||||
|  |             .bMasterInterface0      = 2+0, | ||||||
|  |             .bSlaveInterface0       = 2+1, | ||||||
|  |         }, | ||||||
|  |         .comm_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_NTF_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = CDC_NTF_SZ, | ||||||
|  |             .bInterval              = 0xFF, | ||||||
|  |         }, | ||||||
|  |         .data = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 2+1, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 2, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_CDC_DATA, | ||||||
|  |             .bInterfaceSubClass     = USB_SUBCLASS_NONE, | ||||||
|  |             .bInterfaceProtocol     = USB_PROTO_NONE, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .data_eprx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_RXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |         .data_eptx = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = CDC1_TXD_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_BULK, | ||||||
|  |             .wMaxPacketSize         = CDC_DATA_SZ, | ||||||
|  |             .bInterval              = 0x01, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct usb_cdc_line_coding cdc_line = { | ||||||
|  |     .dwDTERate          = 38400, | ||||||
|  |     .bCharFormat        = USB_CDC_1_STOP_BITS, | ||||||
|  |     .bParityType        = USB_CDC_NO_PARITY, | ||||||
|  |     .bDataBits          = 8, | ||||||
|  | }; | ||||||
|  | static void cdc_init(usbd_device* dev, struct UsbInterface* intf); | ||||||
|  | static void cdc_deinit(usbd_device *dev); | ||||||
|  | static void cdc_on_wakeup(usbd_device *dev); | ||||||
|  | static void cdc_on_suspend(usbd_device *dev); | ||||||
|  | 
 | ||||||
|  | static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg); | ||||||
|  | static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | static struct UsbInterface* cdc_if_cur = NULL; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_cdc_single = { | ||||||
|  |     .init = cdc_init, | ||||||
|  |     .deinit = cdc_deinit, | ||||||
|  |     .wakeup = cdc_on_wakeup, | ||||||
|  |     .suspend = cdc_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = NULL, | ||||||
|  |     .str_serial_descr = NULL, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&cdc_cfg_desc_single, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_cdc_dual = { | ||||||
|  |     .init = cdc_init, | ||||||
|  |     .deinit = cdc_deinit, | ||||||
|  |     .wakeup = cdc_on_wakeup, | ||||||
|  |     .suspend = cdc_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&cdc_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = NULL, | ||||||
|  |     .str_serial_descr = NULL, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&cdc_cfg_desc_dual, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void cdc_init(usbd_device* dev, struct UsbInterface* intf) { | ||||||
|  |     usb_dev = dev; | ||||||
|  |     cdc_if_cur = intf; | ||||||
|  |      | ||||||
|  |     char* name = (char*)furi_hal_version_get_device_name_ptr(); | ||||||
|  |     uint8_t len = (name == NULL) ? (0) : (strlen(name)); | ||||||
|  |     struct usb_string_descriptor* dev_prod_desc = furi_alloc(len * 2 + 2); | ||||||
|  |     dev_prod_desc->bLength = len * 2 + 2; | ||||||
|  |     dev_prod_desc->bDescriptorType = USB_DTYPE_STRING; | ||||||
|  |     for (uint8_t i = 0; i < len; i++) | ||||||
|  |         dev_prod_desc->wString[i] = name[i]; | ||||||
|  | 
 | ||||||
|  |     name = (char*)furi_hal_version_get_name_ptr(); | ||||||
|  |     len = (name == NULL) ? (0) : (strlen(name)); | ||||||
|  |     struct usb_string_descriptor* dev_serial_desc = furi_alloc((len + 5) * 2 + 2); | ||||||
|  |     dev_serial_desc->bLength = (len + 5) * 2 + 2; | ||||||
|  |     dev_serial_desc->bDescriptorType = USB_DTYPE_STRING; | ||||||
|  |     memcpy(dev_serial_desc->wString, "f\0l\0i\0p\0_\0", 5*2); | ||||||
|  |     for (uint8_t i = 0; i < len; i++) | ||||||
|  |         dev_serial_desc->wString[i+5] = name[i]; | ||||||
|  | 
 | ||||||
|  |     cdc_if_cur->str_prod_descr = dev_prod_desc; | ||||||
|  |     cdc_if_cur->str_serial_descr = dev_serial_desc; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, cdc_ep_config); | ||||||
|  |     usbd_reg_control(dev, cdc_control);     | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_deinit(usbd_device *dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | 
 | ||||||
|  |     free(cdc_if_cur->str_prod_descr); | ||||||
|  |     free(cdc_if_cur->str_serial_descr); | ||||||
|  | 
 | ||||||
|  |     cdc_if_cur = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) { | ||||||
|  |     if (if_num == 0) | ||||||
|  |         usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len); | ||||||
|  |     else | ||||||
|  |         usbd_ep_write(usb_dev, CDC1_TXD_EP, buf, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) { | ||||||
|  |     if (if_num == 0) | ||||||
|  |         return usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); | ||||||
|  |     else | ||||||
|  |         return usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_on_wakeup(usbd_device *dev) { | ||||||
|  |     furi_hal_vcp_on_usb_resume(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_on_suspend(usbd_device *dev) { | ||||||
|  |     furi_hal_vcp_on_usb_suspend(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (ep == CDC0_RXD_EP) | ||||||
|  |         furi_hal_vcp_on_cdc_rx(0); | ||||||
|  |     else | ||||||
|  |         furi_hal_vcp_on_cdc_rx(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (ep == CDC0_TXD_EP) | ||||||
|  |         furi_hal_vcp_on_cdc_tx_complete(0); | ||||||
|  |     else | ||||||
|  |         furi_hal_vcp_on_cdc_tx_complete(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdc_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (event == usbd_evt_eptx) { | ||||||
|  |         cdc_tx_ep_callback(dev, event, ep); | ||||||
|  |     } else { | ||||||
|  |         cdc_rx_ep_callback(dev, event, ep); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) { | ||||||
|  |     uint8_t if_cnt = ((struct usb_config_descriptor*)(cdc_if_cur->cfg_descr))->bNumInterfaces; | ||||||
|  |     switch (cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_NTF_EP); | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_TXD_EP); | ||||||
|  |         usbd_ep_deconfig(dev, CDC0_RXD_EP); | ||||||
|  |         usbd_reg_endpoint(dev, CDC0_RXD_EP, 0); | ||||||
|  |         usbd_reg_endpoint(dev, CDC0_TXD_EP, 0); | ||||||
|  |         if (if_cnt == 4) { | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_NTF_EP); | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_TXD_EP); | ||||||
|  |             usbd_ep_deconfig(dev, CDC1_RXD_EP); | ||||||
|  |             usbd_reg_endpoint(dev, CDC1_RXD_EP, 0); | ||||||
|  |             usbd_reg_endpoint(dev, CDC1_TXD_EP, 0); | ||||||
|  |         } | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) { | ||||||
|  |             usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_rx_ep_callback); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_tx_ep_callback); | ||||||
|  |         } else { | ||||||
|  |             usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |             usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_txrx_ep_callback); | ||||||
|  |             usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_txrx_ep_callback); | ||||||
|  |         } | ||||||
|  |         usbd_ep_write(dev, CDC0_TXD_EP, 0, 0); | ||||||
|  | 
 | ||||||
|  |         if (if_cnt == 4) { | ||||||
|  |             if ((CDC1_TXD_EP & 0x7F) != (CDC1_RXD_EP & 0x7F)) { | ||||||
|  |                 usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_rx_ep_callback); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_tx_ep_callback); | ||||||
|  |             } else { | ||||||
|  |                 usbd_ep_config(dev, CDC1_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ); | ||||||
|  |                 usbd_ep_config(dev, CDC1_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_RXD_EP, cdc_txrx_ep_callback); | ||||||
|  |                 usbd_reg_endpoint(dev, CDC1_TXD_EP, cdc_txrx_ep_callback); | ||||||
|  |             } | ||||||
|  |             usbd_ep_write(dev, CDC1_TXD_EP, 0, 0); | ||||||
|  |         } | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { | ||||||
|  |     /* CDC control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS) | ||||||
|  |         && req->wIndex == 0 ) { | ||||||
|  |         switch (req->bRequest) { | ||||||
|  |         case USB_CDC_SET_CONTROL_LINE_STATE: | ||||||
|  |             furi_hal_vcp_on_cdc_control_line(req->wValue); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_CDC_SET_LINE_CODING: | ||||||
|  |             memcpy(&cdc_line, req->data, sizeof(cdc_line)); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_CDC_GET_LINE_CODING: | ||||||
|  |             dev->status.data_ptr = &cdc_line; | ||||||
|  |             dev->status.data_count = sizeof(cdc_line); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #define CDC_DATA_SZ     0x40 | ||||||
|  | 
 | ||||||
|  | void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len); | ||||||
|  | 
 | ||||||
|  | int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len); | ||||||
							
								
								
									
										264
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-hid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-hid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,264 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_hid.h" | ||||||
|  | #include "hid_usage_desktop.h" | ||||||
|  | #include "hid_usage_button.h" | ||||||
|  | 
 | ||||||
|  | #define HID_RIN_EP      0x81 | ||||||
|  | #define HID_RIN_SZ      0x10 | ||||||
|  | 
 | ||||||
|  | struct HidIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor           hid_iad; | ||||||
|  |     struct usb_interface_descriptor     hid; | ||||||
|  |     struct usb_hid_descriptor           hid_desc; | ||||||
|  |     struct usb_endpoint_descriptor      hid_ep;     | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HidConfigDescriptor { | ||||||
|  |     struct usb_config_descriptor        config; | ||||||
|  |     struct HidIadDescriptor             iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | /* HID mouse report desscriptor. 2 axis 5 buttons */ | ||||||
|  | static const uint8_t hid_report_desc[] = { | ||||||
|  |     HID_USAGE_PAGE(HID_PAGE_DESKTOP), | ||||||
|  |     HID_USAGE(HID_DESKTOP_MOUSE), | ||||||
|  |     HID_COLLECTION(HID_APPLICATION_COLLECTION), | ||||||
|  |         HID_USAGE(HID_DESKTOP_POINTER), | ||||||
|  |         HID_COLLECTION(HID_PHYSICAL_COLLECTION), | ||||||
|  |             HID_USAGE(HID_DESKTOP_X), | ||||||
|  |             HID_USAGE(HID_DESKTOP_Y), | ||||||
|  |             HID_LOGICAL_MINIMUM(-127), | ||||||
|  |             HID_LOGICAL_MAXIMUM(127), | ||||||
|  |             HID_REPORT_SIZE(8), | ||||||
|  |             HID_REPORT_COUNT(2), | ||||||
|  |             HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE ), | ||||||
|  |             HID_USAGE_PAGE(HID_PAGE_BUTTON), | ||||||
|  |             HID_USAGE_MINIMUM(1), | ||||||
|  |             HID_USAGE_MAXIMUM(5), | ||||||
|  |             HID_LOGICAL_MINIMUM(0), | ||||||
|  |             HID_LOGICAL_MAXIMUM(1), | ||||||
|  |             HID_REPORT_SIZE(1), | ||||||
|  |             HID_REPORT_COUNT(5), | ||||||
|  |             HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE ), | ||||||
|  |             HID_REPORT_SIZE(1), | ||||||
|  |             HID_REPORT_COUNT(3), | ||||||
|  |             HID_INPUT(HID_IOF_CONSTANT), | ||||||
|  |         HID_END_COLLECTION, | ||||||
|  |     HID_END_COLLECTION, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Logitech"); | ||||||
|  | static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("USB Receiver"); | ||||||
|  | static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("1234567890"); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor hid_device_desc = { | ||||||
|  |     .bLength            = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType    = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB             = VERSION_BCD(2,0,0), | ||||||
|  |     .bDeviceClass       = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass    = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol    = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0    = USB_EP0_SIZE, | ||||||
|  |     .idVendor           = 0x046d, | ||||||
|  |     .idProduct          = 0xc529, | ||||||
|  |     .bcdDevice          = VERSION_BCD(1,0,0), | ||||||
|  |     .iManufacturer      = UsbDevManuf, | ||||||
|  |     .iProduct           = UsbDevProduct, | ||||||
|  |     .iSerialNumber      = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor */ | ||||||
|  | static const struct HidConfigDescriptor hid_cfg_desc = { | ||||||
|  |     .config = { | ||||||
|  |         .bLength                = sizeof(struct usb_config_descriptor), | ||||||
|  |         .bDescriptorType        = USB_DTYPE_CONFIGURATION, | ||||||
|  |         .wTotalLength           = sizeof(struct HidConfigDescriptor), | ||||||
|  |         .bNumInterfaces         = 1, | ||||||
|  |         .bConfigurationValue    = 1, | ||||||
|  |         .iConfiguration         = NO_DESCRIPTOR, | ||||||
|  |         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |         .bMaxPower              = USB_CFG_POWER_MA(100), | ||||||
|  |     }, | ||||||
|  |     .iad_0 = { | ||||||
|  |         .hid_iad = { | ||||||
|  |             .bLength = sizeof(struct usb_iad_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |             .bFirstInterface        = 0, | ||||||
|  |             .bInterfaceCount        = 1, | ||||||
|  |             .bFunctionClass         = USB_CLASS_PER_INTERFACE, | ||||||
|  |             .bFunctionSubClass      = USB_SUBCLASS_NONE, | ||||||
|  |             .bFunctionProtocol      = USB_PROTO_NONE, | ||||||
|  |             .iFunction              = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .hid = { | ||||||
|  |             .bLength                = sizeof(struct usb_interface_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_INTERFACE, | ||||||
|  |             .bInterfaceNumber       = 0, | ||||||
|  |             .bAlternateSetting      = 0, | ||||||
|  |             .bNumEndpoints          = 1, | ||||||
|  |             .bInterfaceClass        = USB_CLASS_HID, | ||||||
|  |             .bInterfaceSubClass     = USB_HID_SUBCLASS_NONBOOT, | ||||||
|  |             .bInterfaceProtocol     = USB_HID_PROTO_NONBOOT, | ||||||
|  |             .iInterface             = NO_DESCRIPTOR, | ||||||
|  |         }, | ||||||
|  |         .hid_desc = { | ||||||
|  |             .bLength                = sizeof(struct usb_hid_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_HID, | ||||||
|  |             .bcdHID                 = VERSION_BCD(1,0,0), | ||||||
|  |             .bCountryCode           = USB_HID_COUNTRY_NONE, | ||||||
|  |             .bNumDescriptors        = 1, | ||||||
|  |             .bDescriptorType0       = USB_DTYPE_HID_REPORT, | ||||||
|  |             .wDescriptorLength0     = sizeof(hid_report_desc), | ||||||
|  |         }, | ||||||
|  |         .hid_ep = { | ||||||
|  |             .bLength                = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |             .bDescriptorType        = USB_DTYPE_ENDPOINT, | ||||||
|  |             .bEndpointAddress       = HID_RIN_EP, | ||||||
|  |             .bmAttributes           = USB_EPTYPE_INTERRUPT, | ||||||
|  |             .wMaxPacketSize         = HID_RIN_SZ, | ||||||
|  |             .bInterval              = 50, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct { | ||||||
|  |     int8_t      x; | ||||||
|  |     int8_t      y; | ||||||
|  |     uint8_t     buttons; | ||||||
|  | } __attribute__((packed)) hid_report_data; | ||||||
|  | 
 | ||||||
|  | static void hid_init(usbd_device* dev, struct UsbInterface* intf); | ||||||
|  | static void hid_deinit(usbd_device *dev); | ||||||
|  | static void hid_on_wakeup(usbd_device *dev); | ||||||
|  | static void hid_on_suspend(usbd_device *dev); | ||||||
|  | 
 | ||||||
|  | static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg); | ||||||
|  | static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface usb_hid = { | ||||||
|  |     .init = hid_init, | ||||||
|  |     .deinit = hid_deinit, | ||||||
|  |     .wakeup = hid_on_wakeup, | ||||||
|  |     .suspend = hid_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,     | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = (void*)&dev_prod_desc, | ||||||
|  |     .str_serial_descr = (void*)&dev_serial_desc, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&hid_cfg_desc, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_init(usbd_device* dev, struct UsbInterface* intf) { | ||||||
|  |     usb_dev = dev; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, hid_ep_config); | ||||||
|  |     usbd_reg_control(dev, hid_control);     | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_deinit(usbd_device *dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_on_wakeup(usbd_device *dev) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_on_suspend(usbd_device *dev) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* HID mouse IN endpoint callback */ | ||||||
|  | static void hid_mouse_move(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     static uint8_t t = 0; | ||||||
|  |     if (t < 0x10) { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = 0; | ||||||
|  |     } else if (t < 0x20) { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x30) { | ||||||
|  |         hid_report_data.x = 0; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x40) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = 1; | ||||||
|  |     } else if (t < 0x50) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = 0; | ||||||
|  |     } else if (t < 0x60) { | ||||||
|  |         hid_report_data.x = -1; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } else if (t < 0x70) { | ||||||
|  |         hid_report_data.x = 0; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } else  { | ||||||
|  |         hid_report_data.x = 1; | ||||||
|  |         hid_report_data.y = -1; | ||||||
|  |     } | ||||||
|  |     t = (t + 1) & 0x7F; | ||||||
|  |     usbd_ep_write(dev, ep, &hid_report_data, sizeof(hid_report_data)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond hid_ep_config (usbd_device *dev, uint8_t cfg) { | ||||||
|  |     switch (cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, HID_RIN_EP); | ||||||
|  |         usbd_reg_endpoint(dev, HID_RIN_EP, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         usbd_ep_config(dev, HID_RIN_EP, USB_EPTYPE_INTERRUPT, HID_RIN_SZ); | ||||||
|  |         usbd_reg_endpoint(dev, HID_RIN_EP, hid_mouse_move); | ||||||
|  |         usbd_ep_write(dev, HID_RIN_EP, 0, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond hid_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { | ||||||
|  |     /* HID control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS) | ||||||
|  |         && req->wIndex == 0 ) { | ||||||
|  |         switch (req->bRequest) { | ||||||
|  |         case USB_HID_SETIDLE: | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_HID_GETREPORT: | ||||||
|  |             dev->status.data_ptr = &hid_report_data; | ||||||
|  |             dev->status.data_count = sizeof(hid_report_data); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_STANDARD) | ||||||
|  |         && req->wIndex == 0 | ||||||
|  |         && req->bRequest == USB_STD_GET_DESCRIPTOR) { | ||||||
|  |         switch (req->wValue >> 8) { | ||||||
|  |         case USB_DTYPE_HID: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.iad_0.hid_desc); | ||||||
|  |             dev->status.data_count = sizeof(hid_cfg_desc.iad_0.hid_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_DTYPE_HID_REPORT: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)hid_report_desc; | ||||||
|  |             dev->status.data_count = sizeof(hid_report_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
							
								
								
									
										164
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,164 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-usb.h" | ||||||
|  | #include "furi-hal-vcp_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | 
 | ||||||
|  | #define USB_RECONNECT_DELAY 500 | ||||||
|  | 
 | ||||||
|  | extern struct UsbInterface usb_cdc_single; | ||||||
|  | extern struct UsbInterface usb_cdc_dual; | ||||||
|  | extern struct UsbInterface usb_hid; | ||||||
|  | 
 | ||||||
|  | static struct UsbInterface* const usb_if_modes[UsbModesNum] = { | ||||||
|  |     NULL, | ||||||
|  |     &usb_cdc_single, | ||||||
|  |     &usb_cdc_dual, | ||||||
|  |     &usb_hid, | ||||||
|  |     NULL,//&usb_hid_u2f,
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); | ||||||
|  | 
 | ||||||
|  | static uint32_t ubuf[0x20]; | ||||||
|  | usbd_device udev; | ||||||
|  | 
 | ||||||
|  | static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length); | ||||||
|  | static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep); | ||||||
|  | static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep); | ||||||
|  | 
 | ||||||
|  | struct UsbCfg{ | ||||||
|  |     osTimerId_t reconnect_tmr; | ||||||
|  |     UsbMode mode_cur; | ||||||
|  |     UsbMode mode_next; | ||||||
|  |     bool enabled; | ||||||
|  | } usb_config; | ||||||
|  | 
 | ||||||
|  | static void furi_hal_usb_tmr_cb(void* context); | ||||||
|  | 
 | ||||||
|  | /* Low-level init */ | ||||||
|  | void furi_hal_usb_init(void) { | ||||||
|  |      | ||||||
|  |     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||||
|  |     LL_PWR_EnableVddUSB(); | ||||||
|  |      | ||||||
|  |     GPIO_InitStruct.Pin = LL_GPIO_PIN_11 | LL_GPIO_PIN_12; | ||||||
|  |     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||||
|  |     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; | ||||||
|  |     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||||
|  |     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||||
|  |     GPIO_InitStruct.Alternate = LL_GPIO_AF_10; | ||||||
|  |     LL_GPIO_Init(GPIOA, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |     usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); | ||||||
|  |     usbd_enable(&udev, true); | ||||||
|  | 
 | ||||||
|  |     usbd_reg_descr(&udev, usb_descriptor_get); | ||||||
|  |     usbd_reg_event(&udev, usbd_evt_susp, susp_evt); | ||||||
|  |     usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); | ||||||
|  | 
 | ||||||
|  |     usb_config.enabled = false; | ||||||
|  |     usb_config.reconnect_tmr = NULL; | ||||||
|  |     HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); | ||||||
|  |     NVIC_EnableIRQ(USB_LP_IRQn); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I("FuriHalUsb", "Init OK"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_set_config(UsbMode new_mode) { | ||||||
|  |     if (new_mode != usb_config.mode_cur) { | ||||||
|  |         if (usb_config.enabled) { | ||||||
|  |             usb_config.mode_next = new_mode; | ||||||
|  |             if (usb_config.reconnect_tmr == NULL) | ||||||
|  |                 usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); | ||||||
|  |             furi_hal_usb_disable(); | ||||||
|  |             osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |                 usb_if_modes[usb_config.mode_cur]->deinit(&udev); | ||||||
|  |             if (usb_if_modes[new_mode] != NULL) { | ||||||
|  |                 usb_if_modes[new_mode]->init(&udev, usb_if_modes[new_mode]); | ||||||
|  |                 FURI_LOG_I("FuriHalUsb", "USB mode change %u -> %u", usb_config.mode_cur, new_mode); | ||||||
|  |                 usb_config.enabled = true; | ||||||
|  |                 usb_config.mode_cur = new_mode; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_disable() { | ||||||
|  |     if (usb_config.enabled) { | ||||||
|  |         susp_evt(&udev, 0, 0); | ||||||
|  |         usbd_connect(&udev, false); | ||||||
|  |         usb_config.enabled = false; | ||||||
|  |         FURI_LOG_I("FuriHalUsb", "USB Disable"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_usb_enable() { | ||||||
|  |     if ((!usb_config.enabled) && (usb_if_modes[usb_config.mode_cur] != NULL)) { | ||||||
|  |         usbd_connect(&udev, true); | ||||||
|  |         usb_config.enabled = true; | ||||||
|  |         FURI_LOG_I("FuriHalUsb", "USB Enable"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_usb_tmr_cb(void* context) { | ||||||
|  |     furi_hal_usb_set_config(usb_config.mode_next); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Get device / configuration descriptors */ | ||||||
|  | static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length) { | ||||||
|  |     const uint8_t dtype = req->wValue >> 8; | ||||||
|  |     const uint8_t dnumber = req->wValue & 0xFF; | ||||||
|  |     const void* desc; | ||||||
|  |     uint16_t len = 0; | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] == NULL) | ||||||
|  |         return usbd_fail; | ||||||
|  | 
 | ||||||
|  |     switch (dtype) { | ||||||
|  |     case USB_DTYPE_DEVICE: | ||||||
|  |         desc = usb_if_modes[usb_config.mode_cur]->dev_descr; | ||||||
|  |         break; | ||||||
|  |     case USB_DTYPE_CONFIGURATION: | ||||||
|  |         desc = usb_if_modes[usb_config.mode_cur]->cfg_descr; | ||||||
|  |         len = ((struct usb_string_descriptor*)(usb_if_modes[usb_config.mode_cur]->cfg_descr))->wString[0]; | ||||||
|  |         break; | ||||||
|  |     case USB_DTYPE_STRING: | ||||||
|  |         if (dnumber == UsbDevLang) { | ||||||
|  |             desc = &dev_lang_desc; | ||||||
|  |         } else if (dnumber == UsbDevManuf) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_manuf_descr; | ||||||
|  |         } else if (dnumber == UsbDevProduct) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_prod_descr; | ||||||
|  |         } else if (dnumber == UsbDevSerial) { | ||||||
|  |             desc = usb_if_modes[usb_config.mode_cur]->str_serial_descr; | ||||||
|  |         } else  | ||||||
|  |             return usbd_fail; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  |     if (desc == NULL) | ||||||
|  |         return usbd_fail; | ||||||
|  | 
 | ||||||
|  |     if (len == 0) { | ||||||
|  |         len = ((struct usb_header_descriptor*)desc)->bLength; | ||||||
|  |     } | ||||||
|  |     *address = (void*)desc; | ||||||
|  |     *length = len; | ||||||
|  |     return usbd_ack; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |         usb_if_modes[usb_config.mode_cur]->suspend(&udev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (usb_if_modes[usb_config.mode_cur] != NULL) | ||||||
|  |         usb_if_modes[usb_config.mode_cur]->wakeup(&udev); | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "usb.h" | ||||||
|  | 
 | ||||||
|  | #define USB_EP0_SIZE 8 | ||||||
|  | 
 | ||||||
|  | /* String descriptors */ | ||||||
|  | enum UsbDevDescStr{ | ||||||
|  |     UsbDevLang      = 0, | ||||||
|  |     UsbDevManuf     = 1, | ||||||
|  |     UsbDevProduct   = 2, | ||||||
|  |     UsbDevSerial    = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct UsbInterface { | ||||||
|  |     void (*init)(usbd_device *dev, struct UsbInterface* intf); | ||||||
|  |     void (*deinit)(usbd_device *dev); | ||||||
|  |     void (*wakeup)(usbd_device *dev); | ||||||
|  |     void (*suspend)(usbd_device *dev);     | ||||||
|  | 
 | ||||||
|  |     struct usb_device_descriptor* dev_descr; | ||||||
|  | 
 | ||||||
|  |     void* str_manuf_descr; | ||||||
|  |     void* str_prod_descr; | ||||||
|  |     void* str_serial_descr; | ||||||
|  | 
 | ||||||
|  |     void* cfg_descr; | ||||||
|  | }; | ||||||
| @ -1,12 +1,12 @@ | |||||||
| #include <furi-hal-vcp_i.h> | #include <furi-hal-vcp_i.h> | ||||||
|  | #include <furi-hal-usb-cdc_i.h> | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <usbd_cdc_if.h> |  | ||||||
| #include <stream_buffer.h> | #include <stream_buffer.h> | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 5) | #define APP_RX_DATA_SIZE CDC_DATA_SZ | ||||||
| 
 | #define APP_TX_DATA_SIZE CDC_DATA_SZ | ||||||
| extern USBD_HandleTypeDef hUsbDeviceFS; | #define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16) | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     volatile bool connected; |     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_soh = 0x01; | ||||||
| static const uint8_t ascii_eot = 0x04; | static const uint8_t ascii_eot = 0x04; | ||||||
| 
 | 
 | ||||||
|  | static uint8_t* vcp_rx_buf; | ||||||
|  | 
 | ||||||
| void furi_hal_vcp_init() { | void furi_hal_vcp_init() { | ||||||
|     furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); |     furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); | ||||||
|  |     vcp_rx_buf = furi_alloc(APP_RX_DATA_SIZE); | ||||||
|     furi_hal_vcp->connected = false; |     furi_hal_vcp->connected = false; | ||||||
|      |      | ||||||
|     furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1); |     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); |     size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); | ||||||
| 
 | 
 | ||||||
|     if(furi_hal_vcp->rx_stream_full |     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; |         furi_hal_vcp->rx_stream_full = false; | ||||||
|         // data accepted, start waiting for next packet
 |  | ||||||
|         USBD_CDC_ReceivePacket(&hUsbDeviceFS); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return received; |     return received; | ||||||
| @ -67,13 +68,9 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { | |||||||
|             batch_size = APP_TX_DATA_SIZE; |             batch_size = APP_TX_DATA_SIZE; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) { |         furi_hal_cdc_send(0, (uint8_t*)buffer, batch_size); | ||||||
|         size -= batch_size; |         size -= batch_size; | ||||||
|         buffer += batch_size; |         buffer += batch_size; | ||||||
|         } else { |  | ||||||
|             FURI_LOG_E("FuriHalVcp", "CDC_Transmit_FS failed"); |  | ||||||
|             osDelay(50); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -89,6 +86,8 @@ void furi_hal_vcp_on_usb_suspend() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | ||||||
|  | 
 | ||||||
|  |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
|     // bit 0: DTR state, bit 1: RTS state
 |     // bit 0: DTR state, bit 1: RTS state
 | ||||||
|     // bool dtr = state & 0b01;
 |     // bool dtr = state & 0b01;
 | ||||||
|     bool dtr = state & 0b1; |     bool dtr = state & 0b1; | ||||||
| @ -96,33 +95,45 @@ void furi_hal_vcp_on_cdc_control_line(uint8_t state) { | |||||||
|     if (dtr) { |     if (dtr) { | ||||||
|         if (!furi_hal_vcp->connected) { |         if (!furi_hal_vcp->connected) { | ||||||
|             furi_hal_vcp->connected = true; |             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 { |     } else { | ||||||
|         if (furi_hal_vcp->connected) { |         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; |             furi_hal_vcp->connected = false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     osSemaphoreRelease(furi_hal_vcp->tx_semaphore); |     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; |     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) { |     if (if_num == 0) { | ||||||
|         USBD_CDC_ReceivePacket(&hUsbDeviceFS); |         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 { |         } else { | ||||||
|             furi_hal_vcp->rx_stream_full = true; |             furi_hal_vcp->rx_stream_full = true; | ||||||
|  |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_tx_complete(size_t size) { | void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num) { | ||||||
|  |     if (if_num == 0) | ||||||
|         osSemaphoreRelease(furi_hal_vcp->tx_semaphore); |         osSemaphoreRelease(furi_hal_vcp->tx_semaphore); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,6 +8,6 @@ void furi_hal_vcp_on_usb_suspend(); | |||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_control_line(uint8_t state); | void furi_hal_vcp_on_cdc_control_line(uint8_t state); | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size); | void furi_hal_vcp_on_cdc_rx(uint8_t if_num); | ||||||
| 
 | 
 | ||||||
| void furi_hal_vcp_on_cdc_tx_complete(size_t size); | void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num); | ||||||
|  | |||||||
| @ -8,10 +8,6 @@ | |||||||
| #include "ble.h" | #include "ble.h" | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | #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 | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
| 
 | 
 | ||||||
| /** OTP Versions enum */ | /** OTP Versions enum */ | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ | |||||||
| #include <comp.h> | #include <comp.h> | ||||||
| #include <rtc.h> | #include <rtc.h> | ||||||
| #include <tim.h> | #include <tim.h> | ||||||
| #include <usb_device.h> |  | ||||||
| #include <gpio.h> | #include <gpio.h> | ||||||
| 
 | 
 | ||||||
| void furi_hal_init() { | void furi_hal_init() { | ||||||
| @ -35,7 +34,8 @@ void furi_hal_init() { | |||||||
| 
 | 
 | ||||||
|     // VCP + USB
 |     // VCP + USB
 | ||||||
|     furi_hal_vcp_init(); |     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_LOG_I("HAL", "USB OK"); | ||||||
| 
 | 
 | ||||||
|     furi_hal_i2c_init(); |     furi_hal_i2c_init(); | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ CFLAGS += \ | |||||||
| CFLAGS += \
 | CFLAGS += \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 | 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
 | 	-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/Device/ST/STM32WBxx/Include \
 | ||||||
| 	-I$(CUBE_DIR)/Drivers/CMSIS/Include | 	-I$(CUBE_DIR)/Drivers/CMSIS/Include | ||||||
| C_SOURCES += \
 | 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_spi.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.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_usart.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
 |  | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | ||||||
| 
 | 
 | ||||||
| # FreeRTOS
 | # 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/tl/shci_tl_if.c \
 | ||||||
| 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c | 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c | ||||||
| 
 | 
 | ||||||
| # USB glue 
 | # USB stack
 | ||||||
| CFLAGS += \
 | CFLAGS += \
 | ||||||
| 	-I$(TARGET_DIR)/usb-glue \
 | 	-DSTM32WB \
 | ||||||
| 	-I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
 | 	-DUSB_PMASIZE=0x400 | ||||||
| 	-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 |  | ||||||
| 
 | 
 | ||||||
| # Furi HAL
 | # Furi HAL
 | ||||||
| FURI_HAL_OS_DEBUG ?= 0 | FURI_HAL_OS_DEBUG ?= 0 | ||||||
|  | |||||||
| @ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
|  extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| void MX_USB_Device_Init(); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @ -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; |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -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; |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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
									
								
								firmware/targets/furi-hal-include/furi-hal-usb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								firmware/targets/furi-hal-include/furi-hal-usb.h
									
									
									
									
									
										Normal file
									
								
							| @ -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(); | ||||||
| @ -14,6 +14,11 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #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 */ | /** Device Colors */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     FuriHalVersionColorUnknown=0x00, |     FuriHalVersionColorUnknown=0x00, | ||||||
|  | |||||||
| @ -33,6 +33,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {}; | |||||||
| #include "furi-hal-ibutton.h" | #include "furi-hal-ibutton.h" | ||||||
| #include "furi-hal-rfid.h" | #include "furi-hal-rfid.h" | ||||||
| #include "furi-hal-nfc.h" | #include "furi-hal-nfc.h" | ||||||
|  | #include "furi-hal-usb.h" | ||||||
| 
 | 
 | ||||||
| /** Init furi-hal */ | /** Init furi-hal */ | ||||||
| void furi_hal_init(); | void furi_hal_init(); | ||||||
|  | |||||||
| @ -108,3 +108,7 @@ CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp) | |||||||
| 
 | 
 | ||||||
| # Toolbox
 | # Toolbox
 | ||||||
| C_SOURCES		+= $(wildcard $(LIB_DIR)/toolbox/*.c) | 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
									
								
								lib/libusb_stm32
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								lib/libusb_stm32
									
									
									
									
									
										Submodule
									
								
							| @ -0,0 +1 @@ | |||||||
|  | Subproject commit fe3890e10e35a837184cb05f835ef6ab14bfd04f | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov