diff --git a/.gitmodules b/.gitmodules
index ba764498..308d60fd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -31,3 +31,6 @@
 [submodule "lib/cxxheaderparser"]
 	path = lib/cxxheaderparser
 	url = https://github.com/robotpy/cxxheaderparser.git
+[submodule "applications/plugins/dap_link/lib/free-dap"]
+	path = applications/plugins/dap_link/lib/free-dap
+	url = https://github.com/ataradov/free-dap.git
diff --git a/applications/plugins/dap_link/README.md b/applications/plugins/dap_link/README.md
new file mode 100644
index 00000000..aead0a60
--- /dev/null
+++ b/applications/plugins/dap_link/README.md
@@ -0,0 +1,105 @@
+# Flipper Zero as CMSIS DAP/DAP Link
+Flipper Zero as a [Free-DAP](https://github.com/ataradov/free-dap) based SWD\JTAG debugger. Free-DAP is a free and open source firmware implementation of the [CMSIS-DAP](https://www.keil.com/pack/doc/CMSIS_Dev/DAP/html/index.html) debugger.
+
+## Protocols
+SWD, JTAG , CMSIS-DAP v1 (18 KiB/s), CMSIS-DAP v2 (46 KiB/s), VCP (USB-UART).
+
+WinUSB for driverless installation for Windows 8 and above.
+
+## Usage
+
+### VSCode + Cortex-Debug
+  Set `"device": "cmsis-dap"`
+  
+
+  BluePill configuration example
+  
+  ```json
+{
+    "name": "Attach (DAP)",
+    "cwd": "${workspaceFolder}",
+    "executable": "./build/firmware.elf",
+    "request": "attach",
+    "type": "cortex-debug",
+    "servertype": "openocd",
+    "device": "cmsis-dap",
+    "configFiles": [
+        "interface/cmsis-dap.cfg",
+        "target/stm32f1x.cfg",
+    ],
+},
+  ```
+ 
+
+
+  Flipper Zero configuration example
+  
+  ```json
+{
+    "name": "Attach (DAP)",
+    "cwd": "${workspaceFolder}",
+    "executable": "./build/latest/firmware.elf",
+    "request": "attach",
+    "type": "cortex-debug",
+    "servertype": "openocd",
+    "device": "cmsis-dap",
+    "svdFile": "./debug/STM32WB55_CM4.svd",
+    "rtos": "FreeRTOS",
+    "configFiles": [
+        "interface/cmsis-dap.cfg",
+        "./debug/stm32wbx.cfg",
+    ],
+    "postAttachCommands": [
+        "source debug/flipperapps.py",
+    ],
+},
+  ```
+ 
+
+### OpenOCD
+Use `interface/cmsis-dap.cfg`. You will need OpenOCD v0.11.0.
+
+Additional commands: 
+* `cmsis_dap_backend hid` for CMSIS-DAP v1 protocol.
+* `cmsis_dap_backend usb_bulk` for CMSIS-DAP v2 protocol.
+* `cmsis_dap_serial DAP_Oyevoxo` use DAP-Link running on Flipper named `Oyevoxo`.
+* `cmsis-dap cmd 81` - reboot connected DAP-Link.
+
+
+  Flash BluePill
+  
+  ```
+openocd -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c init -c "program build/firmware.bin reset exit 0x8000000"
+  ```
+ 
+
+
+  Flash Flipper Zero using DAP v2 protocol
+  
+  ```
+openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_backend usb_bulk" -f debug/stm32wbx.cfg -c init -c "program build/latest/firmware.bin reset exit 0x8000000"
+  ```
+ 
+
+
+  Reboot connected DAP-Link on Flipper named Oyevoxo
+  
+  ```
+openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_serial DAP_Oyevoxo" -c "transport select swd" -c "adapter speed 4000000" -c init -c "cmsis-dap cmd 81" -c "exit"
+  ```
+ 
+
+### PlatformIO
+Use `debug_tool = cmsis-dap` and `upload_protocol = cmsis-dap`. [Documentation](https://docs.platformio.org/en/latest/plus/debug-tools/cmsis-dap.html#debugging-tool-cmsis-dap). Remember that Windows 8 and above do not require drivers.
+
+
+  BluePill platformio.ini example
+  
+  ```
+[env:bluepill_f103c8]
+platform = ststm32
+board = bluepill_f103c8
+debug_tool = cmsis-dap
+upload_protocol = cmsis-dap
+  ```
+ 
diff --git a/applications/plugins/dap_link/application.fam b/applications/plugins/dap_link/application.fam
new file mode 100644
index 00000000..3b99d5ef
--- /dev/null
+++ b/applications/plugins/dap_link/application.fam
@@ -0,0 +1,24 @@
+App(
+    appid="dap_link",
+    name="DAP Link",
+    apptype=FlipperAppType.PLUGIN,
+    entry_point="dap_link_app",
+    requires=[
+        "gui",
+        "dialogs",
+    ],
+    stack_size=4 * 1024,
+    order=20,
+    fap_icon="dap_link.png",
+    fap_category="Tools",
+    fap_private_libs=[
+        Lib(
+            name="free-dap",
+            cincludes=["."],
+            sources=[
+                "dap.c",
+            ],
+        ),
+    ],
+    fap_icon_assets="icons",
+)
diff --git a/applications/plugins/dap_link/dap_config.h b/applications/plugins/dap_link/dap_config.h
new file mode 100644
index 00000000..88b90bd3
--- /dev/null
+++ b/applications/plugins/dap_link/dap_config.h
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2022, Alex Taradov . All rights reserved.
+
+#ifndef _DAP_CONFIG_H_
+#define _DAP_CONFIG_H_
+
+/*- Includes ----------------------------------------------------------------*/
+#include 
+
+/*- Definitions -------------------------------------------------------------*/
+#define DAP_CONFIG_ENABLE_JTAG
+
+#define DAP_CONFIG_DEFAULT_PORT DAP_PORT_SWD
+#define DAP_CONFIG_DEFAULT_CLOCK 4200000 // Hz
+
+#define DAP_CONFIG_PACKET_SIZE 64
+#define DAP_CONFIG_PACKET_COUNT 1
+
+#define DAP_CONFIG_JTAG_DEV_COUNT 8
+
+// DAP_CONFIG_PRODUCT_STR must contain "CMSIS-DAP" to be compatible with the standard
+#define DAP_CONFIG_VENDOR_STR "Flipper Zero"
+#define DAP_CONFIG_PRODUCT_STR "Generic CMSIS-DAP Adapter"
+#define DAP_CONFIG_SER_NUM_STR usb_serial_number
+#define DAP_CONFIG_CMSIS_DAP_VER_STR "2.0.0"
+
+#define DAP_CONFIG_RESET_TARGET_FN dap_app_target_reset
+#define DAP_CONFIG_VENDOR_FN dap_app_vendor_cmd
+
+// Attribute to use for performance-critical functions
+#define DAP_CONFIG_PERFORMANCE_ATTR
+
+// A value at which dap_clock_test() produces 1 kHz output on the SWCLK pin
+// #define DAP_CONFIG_DELAY_CONSTANT 19000
+#define DAP_CONFIG_DELAY_CONSTANT 6290
+
+// A threshold for switching to fast clock (no added delays)
+// This is the frequency produced by dap_clock_test(1) on the SWCLK pin
+#define DAP_CONFIG_FAST_CLOCK 2400000 // Hz
+
+/*- Prototypes --------------------------------------------------------------*/
+extern char usb_serial_number[16];
+
+/*- Implementations ---------------------------------------------------------*/
+extern GpioPin flipper_dap_swclk_pin;
+extern GpioPin flipper_dap_swdio_pin;
+extern GpioPin flipper_dap_reset_pin;
+extern GpioPin flipper_dap_tdo_pin;
+extern GpioPin flipper_dap_tdi_pin;
+
+extern void dap_app_vendor_cmd(uint8_t cmd);
+extern void dap_app_target_reset();
+extern void dap_app_disconnect();
+extern void dap_app_connect_swd();
+extern void dap_app_connect_jtag();
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWCLK_TCK_write(int value) {
+    furi_hal_gpio_write(&flipper_dap_swclk_pin, value);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWDIO_TMS_write(int value) {
+    furi_hal_gpio_write(&flipper_dap_swdio_pin, value);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_TDI_write(int value) {
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_write(&flipper_dap_tdi_pin, value);
+#else
+    (void)value;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_TDO_write(int value) {
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_write(&flipper_dap_tdo_pin, value);
+#else
+    (void)value;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_nTRST_write(int value) {
+    (void)value;
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_nRESET_write(int value) {
+    furi_hal_gpio_write(&flipper_dap_reset_pin, value);
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_SWCLK_TCK_read(void) {
+    return furi_hal_gpio_read(&flipper_dap_swclk_pin);
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_SWDIO_TMS_read(void) {
+    return furi_hal_gpio_read(&flipper_dap_swdio_pin);
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_TDO_read(void) {
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    return furi_hal_gpio_read(&flipper_dap_tdo_pin);
+#else
+    return 0;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_TDI_read(void) {
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    return furi_hal_gpio_read(&flipper_dap_tdi_pin);
+#else
+    return 0;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_nTRST_read(void) {
+    return 0;
+}
+
+//-----------------------------------------------------------------------------
+static inline int DAP_CONFIG_nRESET_read(void) {
+    return furi_hal_gpio_read(&flipper_dap_reset_pin);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWCLK_TCK_set(void) {
+    LL_GPIO_SetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWCLK_TCK_clr(void) {
+    LL_GPIO_ResetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWDIO_TMS_in(void) {
+    LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_INPUT);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SWDIO_TMS_out(void) {
+    LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_OUTPUT);
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_SETUP(void) {
+    furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_DISCONNECT(void) {
+    furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+#endif
+    dap_app_disconnect();
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_CONNECT_SWD(void) {
+    furi_hal_gpio_init(
+        &flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_swdio_pin, true);
+
+    furi_hal_gpio_init(
+        &flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_swclk_pin, true);
+
+    furi_hal_gpio_init(
+        &flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_reset_pin, true);
+
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+#endif
+    dap_app_connect_swd();
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_CONNECT_JTAG(void) {
+    furi_hal_gpio_init(
+        &flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_swdio_pin, true);
+
+    furi_hal_gpio_init(
+        &flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_swclk_pin, true);
+
+    furi_hal_gpio_init(
+        &flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_reset_pin, true);
+
+#ifdef DAP_CONFIG_ENABLE_JTAG
+    furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
+
+    furi_hal_gpio_init(
+        &flipper_dap_tdi_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(&flipper_dap_tdi_pin, true);
+#endif
+    dap_app_connect_jtag();
+}
+
+//-----------------------------------------------------------------------------
+static inline void DAP_CONFIG_LED(int index, int state) {
+    (void)index;
+    (void)state;
+}
+
+//-----------------------------------------------------------------------------
+__attribute__((always_inline)) static inline void DAP_CONFIG_DELAY(uint32_t cycles) {
+    asm volatile("1: subs %[cycles], %[cycles], #1 \n"
+                 "   bne 1b \n"
+                 : [cycles] "+l"(cycles));
+}
+
+#endif // _DAP_CONFIG_H_
diff --git a/applications/plugins/dap_link/dap_link.c b/applications/plugins/dap_link/dap_link.c
new file mode 100644
index 00000000..58d032b9
--- /dev/null
+++ b/applications/plugins/dap_link/dap_link.c
@@ -0,0 +1,521 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "dap_link.h"
+#include "dap_config.h"
+#include "gui/dap_gui.h"
+#include "usb/dap_v2_usb.h"
+
+/***************************************************************************/
+/****************************** DAP COMMON *********************************/
+/***************************************************************************/
+
+struct DapApp {
+    FuriThread* dap_thread;
+    FuriThread* cdc_thread;
+    FuriThread* gui_thread;
+
+    DapState state;
+    DapConfig config;
+};
+
+void dap_app_get_state(DapApp* app, DapState* state) {
+    *state = app->state;
+}
+
+#define DAP_PROCESS_THREAD_TICK 500
+
+typedef enum {
+    DapThreadEventStop = (1 << 0),
+} DapThreadEvent;
+
+void dap_thread_send_stop(FuriThread* thread) {
+    furi_thread_flags_set(furi_thread_get_id(thread), DapThreadEventStop);
+}
+
+GpioPin flipper_dap_swclk_pin;
+GpioPin flipper_dap_swdio_pin;
+GpioPin flipper_dap_reset_pin;
+GpioPin flipper_dap_tdo_pin;
+GpioPin flipper_dap_tdi_pin;
+
+/***************************************************************************/
+/****************************** DAP PROCESS ********************************/
+/***************************************************************************/
+
+typedef struct {
+    uint8_t data[DAP_CONFIG_PACKET_SIZE];
+    uint8_t size;
+} DapPacket;
+
+typedef enum {
+    DAPThreadEventStop = DapThreadEventStop,
+    DAPThreadEventRxV1 = (1 << 1),
+    DAPThreadEventRxV2 = (1 << 2),
+    DAPThreadEventUSBConnect = (1 << 3),
+    DAPThreadEventUSBDisconnect = (1 << 4),
+    DAPThreadEventApplyConfig = (1 << 5),
+    DAPThreadEventAll = DAPThreadEventStop | DAPThreadEventRxV1 | DAPThreadEventRxV2 |
+                        DAPThreadEventUSBConnect | DAPThreadEventUSBDisconnect |
+                        DAPThreadEventApplyConfig,
+} DAPThreadEvent;
+
+#define USB_SERIAL_NUMBER_LEN 16
+char usb_serial_number[USB_SERIAL_NUMBER_LEN] = {0};
+
+const char* dap_app_get_serial(DapApp* app) {
+    UNUSED(app);
+    return usb_serial_number;
+}
+
+static void dap_app_rx1_callback(void* context) {
+    furi_assert(context);
+    FuriThreadId thread_id = (FuriThreadId)context;
+    furi_thread_flags_set(thread_id, DAPThreadEventRxV1);
+}
+
+static void dap_app_rx2_callback(void* context) {
+    furi_assert(context);
+    FuriThreadId thread_id = (FuriThreadId)context;
+    furi_thread_flags_set(thread_id, DAPThreadEventRxV2);
+}
+
+static void dap_app_usb_state_callback(bool state, void* context) {
+    furi_assert(context);
+    FuriThreadId thread_id = (FuriThreadId)context;
+    if(state) {
+        furi_thread_flags_set(thread_id, DAPThreadEventUSBConnect);
+    } else {
+        furi_thread_flags_set(thread_id, DAPThreadEventUSBDisconnect);
+    }
+}
+
+static void dap_app_process_v1() {
+    DapPacket tx_packet;
+    DapPacket rx_packet;
+    memset(&tx_packet, 0, sizeof(DapPacket));
+    rx_packet.size = dap_v1_usb_rx(rx_packet.data, DAP_CONFIG_PACKET_SIZE);
+    dap_process_request(rx_packet.data, rx_packet.size, tx_packet.data, DAP_CONFIG_PACKET_SIZE);
+    dap_v1_usb_tx(tx_packet.data, DAP_CONFIG_PACKET_SIZE);
+}
+
+static void dap_app_process_v2() {
+    DapPacket tx_packet;
+    DapPacket rx_packet;
+    memset(&tx_packet, 0, sizeof(DapPacket));
+    rx_packet.size = dap_v2_usb_rx(rx_packet.data, DAP_CONFIG_PACKET_SIZE);
+    size_t len = dap_process_request(
+        rx_packet.data, rx_packet.size, tx_packet.data, DAP_CONFIG_PACKET_SIZE);
+    dap_v2_usb_tx(tx_packet.data, len);
+}
+
+void dap_app_vendor_cmd(uint8_t cmd) {
+    // openocd -c "cmsis-dap cmd 81"
+    if(cmd == 0x01) {
+        furi_hal_power_reset();
+    }
+}
+
+void dap_app_target_reset() {
+    FURI_LOG_I("DAP", "Target reset");
+}
+
+static void dap_init_gpio(DapSwdPins swd_pins) {
+    switch(swd_pins) {
+    case DapSwdPinsPA7PA6:
+        flipper_dap_swclk_pin = gpio_ext_pa7;
+        flipper_dap_swdio_pin = gpio_ext_pa6;
+        break;
+    case DapSwdPinsPA14PA13:
+        flipper_dap_swclk_pin = (GpioPin){.port = GPIOA, .pin = LL_GPIO_PIN_14};
+        flipper_dap_swdio_pin = (GpioPin){.port = GPIOA, .pin = LL_GPIO_PIN_13};
+        break;
+    }
+
+    flipper_dap_reset_pin = gpio_ext_pa4;
+    flipper_dap_tdo_pin = gpio_ext_pb3;
+    flipper_dap_tdi_pin = gpio_ext_pb2;
+}
+
+static void dap_deinit_gpio(DapSwdPins swd_pins) {
+    // setup gpio pins to default state
+    furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+
+    if(DapSwdPinsPA14PA13 == swd_pins) {
+        // PA14 and PA13 are used by SWD
+        furi_hal_gpio_init_ex(
+            &flipper_dap_swclk_pin,
+            GpioModeAltFunctionPushPull,
+            GpioPullDown,
+            GpioSpeedLow,
+            GpioAltFn0JTCK_SWCLK);
+        furi_hal_gpio_init_ex(
+            &flipper_dap_swdio_pin,
+            GpioModeAltFunctionPushPull,
+            GpioPullUp,
+            GpioSpeedVeryHigh,
+            GpioAltFn0JTMS_SWDIO);
+    } else {
+        furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    }
+}
+
+static int32_t dap_process(void* p) {
+    DapApp* app = p;
+    DapState* dap_state = &(app->state);
+
+    // allocate resources
+    FuriHalUsbInterface* usb_config_prev;
+    app->config.swd_pins = DapSwdPinsPA7PA6;
+    DapSwdPins swd_pins_prev = app->config.swd_pins;
+
+    // init pins
+    dap_init_gpio(swd_pins_prev);
+
+    // init dap
+    dap_init();
+
+    // get name
+    const char* name = furi_hal_version_get_name_ptr();
+    if(!name) {
+        name = "Flipper";
+    }
+    snprintf(usb_serial_number, USB_SERIAL_NUMBER_LEN, "DAP_%s", name);
+
+    // init usb
+    usb_config_prev = furi_hal_usb_get_config();
+    dap_common_usb_alloc_name(usb_serial_number);
+    dap_common_usb_set_context(furi_thread_get_id(furi_thread_get_current()));
+    dap_v1_usb_set_rx_callback(dap_app_rx1_callback);
+    dap_v2_usb_set_rx_callback(dap_app_rx2_callback);
+    dap_common_usb_set_state_callback(dap_app_usb_state_callback);
+    furi_hal_usb_set_config(&dap_v2_usb_hid, NULL);
+
+    // work
+    uint32_t events;
+    while(1) {
+        events = furi_thread_flags_wait(DAPThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
+
+        if(!(events & FuriFlagError)) {
+            if(events & DAPThreadEventRxV1) {
+                dap_app_process_v1();
+                dap_state->dap_counter++;
+                dap_state->dap_version = DapVersionV1;
+            }
+
+            if(events & DAPThreadEventRxV2) {
+                dap_app_process_v2();
+                dap_state->dap_counter++;
+                dap_state->dap_version = DapVersionV2;
+            }
+
+            if(events & DAPThreadEventUSBConnect) {
+                dap_state->usb_connected = true;
+            }
+
+            if(events & DAPThreadEventUSBDisconnect) {
+                dap_state->usb_connected = false;
+                dap_state->dap_version = DapVersionUnknown;
+            }
+
+            if(events & DAPThreadEventApplyConfig) {
+                if(swd_pins_prev != app->config.swd_pins) {
+                    dap_deinit_gpio(swd_pins_prev);
+                    swd_pins_prev = app->config.swd_pins;
+                    dap_init_gpio(swd_pins_prev);
+                }
+            }
+
+            if(events & DAPThreadEventStop) {
+                break;
+            }
+        }
+    }
+
+    // deinit usb
+    furi_hal_usb_set_config(usb_config_prev, NULL);
+    dap_common_wait_for_deinit();
+    dap_common_usb_free_name();
+    dap_deinit_gpio(swd_pins_prev);
+    return 0;
+}
+
+/***************************************************************************/
+/****************************** CDC PROCESS ********************************/
+/***************************************************************************/
+
+typedef enum {
+    CDCThreadEventStop = DapThreadEventStop,
+    CDCThreadEventUARTRx = (1 << 1),
+    CDCThreadEventCDCRx = (1 << 2),
+    CDCThreadEventCDCConfig = (1 << 3),
+    CDCThreadEventApplyConfig = (1 << 4),
+    CDCThreadEventAll = CDCThreadEventStop | CDCThreadEventUARTRx | CDCThreadEventCDCRx |
+                        CDCThreadEventCDCConfig | CDCThreadEventApplyConfig,
+} CDCThreadEvent;
+
+typedef struct {
+    FuriStreamBuffer* rx_stream;
+    FuriThreadId thread_id;
+    FuriHalUartId uart_id;
+    struct usb_cdc_line_coding line_coding;
+} CDCProcess;
+
+static void cdc_uart_irq_cb(UartIrqEvent ev, uint8_t data, void* ctx) {
+    CDCProcess* app = ctx;
+
+    if(ev == UartIrqEventRXNE) {
+        furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
+        furi_thread_flags_set(app->thread_id, CDCThreadEventUARTRx);
+    }
+}
+
+static void cdc_usb_rx_callback(void* context) {
+    CDCProcess* app = context;
+    furi_thread_flags_set(app->thread_id, CDCThreadEventCDCRx);
+}
+
+static void cdc_usb_control_line_callback(uint8_t state, void* context) {
+    UNUSED(context);
+    UNUSED(state);
+}
+
+static void cdc_usb_config_callback(struct usb_cdc_line_coding* config, void* context) {
+    CDCProcess* app = context;
+    app->line_coding = *config;
+    furi_thread_flags_set(app->thread_id, CDCThreadEventCDCConfig);
+}
+
+static FuriHalUartId cdc_init_uart(
+    DapUartType type,
+    DapUartTXRX swap,
+    uint32_t baudrate,
+    void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx),
+    void* ctx) {
+    FuriHalUartId uart_id = FuriHalUartIdUSART1;
+    if(baudrate == 0) baudrate = 115200;
+
+    switch(type) {
+    case DapUartTypeUSART1:
+        uart_id = FuriHalUartIdUSART1;
+        furi_hal_console_disable();
+        furi_hal_uart_deinit(uart_id);
+        if(swap == DapUartTXRXSwap) {
+            LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_SWAPPED);
+        } else {
+            LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_STANDARD);
+        }
+        furi_hal_uart_init(uart_id, baudrate);
+        furi_hal_uart_set_irq_cb(uart_id, cb, ctx);
+        break;
+    case DapUartTypeLPUART1:
+        uart_id = FuriHalUartIdLPUART1;
+        furi_hal_uart_deinit(uart_id);
+        if(swap == DapUartTXRXSwap) {
+            LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_SWAPPED);
+        } else {
+            LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_STANDARD);
+        }
+        furi_hal_uart_init(uart_id, baudrate);
+        furi_hal_uart_set_irq_cb(uart_id, cb, ctx);
+        break;
+    }
+
+    return uart_id;
+}
+
+static void cdc_deinit_uart(DapUartType type) {
+    switch(type) {
+    case DapUartTypeUSART1:
+        furi_hal_uart_deinit(FuriHalUartIdUSART1);
+        LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_STANDARD);
+        furi_hal_console_init();
+        break;
+    case DapUartTypeLPUART1:
+        furi_hal_uart_deinit(FuriHalUartIdLPUART1);
+        LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_STANDARD);
+        break;
+    }
+}
+
+static int32_t cdc_process(void* p) {
+    DapApp* dap_app = p;
+    DapState* dap_state = &(dap_app->state);
+
+    dap_app->config.uart_pins = DapUartTypeLPUART1;
+    dap_app->config.uart_swap = DapUartTXRXNormal;
+
+    DapUartType uart_pins_prev = dap_app->config.uart_pins;
+    DapUartTXRX uart_swap_prev = dap_app->config.uart_swap;
+
+    CDCProcess* app = malloc(sizeof(CDCProcess));
+    app->thread_id = furi_thread_get_id(furi_thread_get_current());
+    app->rx_stream = furi_stream_buffer_alloc(512, 1);
+
+    const uint8_t rx_buffer_size = 64;
+    uint8_t* rx_buffer = malloc(rx_buffer_size);
+
+    app->uart_id = cdc_init_uart(
+        uart_pins_prev, uart_swap_prev, dap_state->cdc_baudrate, cdc_uart_irq_cb, app);
+
+    dap_cdc_usb_set_context(app);
+    dap_cdc_usb_set_rx_callback(cdc_usb_rx_callback);
+    dap_cdc_usb_set_control_line_callback(cdc_usb_control_line_callback);
+    dap_cdc_usb_set_config_callback(cdc_usb_config_callback);
+
+    uint32_t events;
+    while(1) {
+        events = furi_thread_flags_wait(CDCThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
+
+        if(!(events & FuriFlagError)) {
+            if(events & CDCThreadEventCDCConfig) {
+                if(dap_state->cdc_baudrate != app->line_coding.dwDTERate) {
+                    dap_state->cdc_baudrate = app->line_coding.dwDTERate;
+                    if(dap_state->cdc_baudrate > 0) {
+                        furi_hal_uart_set_br(app->uart_id, dap_state->cdc_baudrate);
+                    }
+                }
+            }
+
+            if(events & CDCThreadEventUARTRx) {
+                size_t len =
+                    furi_stream_buffer_receive(app->rx_stream, rx_buffer, rx_buffer_size, 0);
+
+                if(len > 0) {
+                    dap_cdc_usb_tx(rx_buffer, len);
+                }
+                dap_state->cdc_rx_counter += len;
+            }
+
+            if(events & CDCThreadEventCDCRx) {
+                size_t len = dap_cdc_usb_rx(rx_buffer, rx_buffer_size);
+                if(len > 0) {
+                    furi_hal_uart_tx(app->uart_id, rx_buffer, len);
+                }
+                dap_state->cdc_tx_counter += len;
+            }
+
+            if(events & CDCThreadEventApplyConfig) {
+                if(uart_pins_prev != dap_app->config.uart_pins ||
+                   uart_swap_prev != dap_app->config.uart_swap) {
+                    cdc_deinit_uart(uart_pins_prev);
+                    uart_pins_prev = dap_app->config.uart_pins;
+                    uart_swap_prev = dap_app->config.uart_swap;
+                    app->uart_id = cdc_init_uart(
+                        uart_pins_prev,
+                        uart_swap_prev,
+                        dap_state->cdc_baudrate,
+                        cdc_uart_irq_cb,
+                        app);
+                }
+            }
+
+            if(events & CDCThreadEventStop) {
+                break;
+            }
+        }
+    }
+
+    cdc_deinit_uart(uart_pins_prev);
+    free(rx_buffer);
+    furi_stream_buffer_free(app->rx_stream);
+    free(app);
+
+    return 0;
+}
+
+/***************************************************************************/
+/******************************* MAIN APP **********************************/
+/***************************************************************************/
+
+static FuriThread* furi_thread_alloc_ex(
+    const char* name,
+    uint32_t stack_size,
+    FuriThreadCallback callback,
+    void* context) {
+    FuriThread* thread = furi_thread_alloc();
+    furi_thread_set_name(thread, name);
+    furi_thread_set_stack_size(thread, stack_size);
+    furi_thread_set_callback(thread, callback);
+    furi_thread_set_context(thread, context);
+    return thread;
+}
+
+static DapApp* dap_app_alloc() {
+    DapApp* dap_app = malloc(sizeof(DapApp));
+    dap_app->dap_thread = furi_thread_alloc_ex("DAP Process", 1024, dap_process, dap_app);
+    dap_app->cdc_thread = furi_thread_alloc_ex("DAP CDC", 1024, cdc_process, dap_app);
+    dap_app->gui_thread = furi_thread_alloc_ex("DAP GUI", 1024, dap_gui_thread, dap_app);
+    return dap_app;
+}
+
+static void dap_app_free(DapApp* dap_app) {
+    furi_assert(dap_app);
+    furi_thread_free(dap_app->dap_thread);
+    furi_thread_free(dap_app->cdc_thread);
+    furi_thread_free(dap_app->gui_thread);
+    free(dap_app);
+}
+
+static DapApp* app_handle = NULL;
+
+void dap_app_disconnect() {
+    app_handle->state.dap_mode = DapModeDisconnected;
+}
+
+void dap_app_connect_swd() {
+    app_handle->state.dap_mode = DapModeSWD;
+}
+
+void dap_app_connect_jtag() {
+    app_handle->state.dap_mode = DapModeJTAG;
+}
+
+void dap_app_set_config(DapApp* app, DapConfig* config) {
+    app->config = *config;
+    furi_thread_flags_set(furi_thread_get_id(app->dap_thread), DAPThreadEventApplyConfig);
+    furi_thread_flags_set(furi_thread_get_id(app->cdc_thread), CDCThreadEventApplyConfig);
+}
+
+DapConfig* dap_app_get_config(DapApp* app) {
+    return &app->config;
+}
+
+int32_t dap_link_app(void* p) {
+    UNUSED(p);
+
+    // alloc app
+    DapApp* app = dap_app_alloc();
+    app_handle = app;
+
+    furi_thread_start(app->dap_thread);
+    furi_thread_start(app->cdc_thread);
+    furi_thread_start(app->gui_thread);
+
+    // wait until gui thread is finished
+    furi_thread_join(app->gui_thread);
+
+    // send stop event to threads
+    dap_thread_send_stop(app->dap_thread);
+    dap_thread_send_stop(app->cdc_thread);
+
+    // wait for threads to stop
+    furi_thread_join(app->dap_thread);
+    furi_thread_join(app->cdc_thread);
+
+    // free app
+    dap_app_free(app);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/dap_link.h b/applications/plugins/dap_link/dap_link.h
new file mode 100644
index 00000000..d51726c4
--- /dev/null
+++ b/applications/plugins/dap_link/dap_link.h
@@ -0,0 +1,55 @@
+#pragma once
+#include 
+
+typedef enum {
+    DapModeDisconnected,
+    DapModeSWD,
+    DapModeJTAG,
+} DapMode;
+
+typedef enum {
+    DapVersionUnknown,
+    DapVersionV1,
+    DapVersionV2,
+} DapVersion;
+
+typedef struct {
+    bool usb_connected;
+    DapMode dap_mode;
+    DapVersion dap_version;
+    uint32_t dap_counter;
+    uint32_t cdc_baudrate;
+    uint32_t cdc_tx_counter;
+    uint32_t cdc_rx_counter;
+} DapState;
+
+typedef enum {
+    DapSwdPinsPA7PA6, // Pins 2, 3
+    DapSwdPinsPA14PA13, // Pins 10, 12
+} DapSwdPins;
+
+typedef enum {
+    DapUartTypeUSART1, // Pins 13, 14
+    DapUartTypeLPUART1, // Pins 15, 16
+} DapUartType;
+
+typedef enum {
+    DapUartTXRXNormal,
+    DapUartTXRXSwap,
+} DapUartTXRX;
+
+typedef struct {
+    DapSwdPins swd_pins;
+    DapUartType uart_pins;
+    DapUartTXRX uart_swap;
+} DapConfig;
+
+typedef struct DapApp DapApp;
+
+void dap_app_get_state(DapApp* app, DapState* state);
+
+const char* dap_app_get_serial(DapApp* app);
+
+void dap_app_set_config(DapApp* app, DapConfig* config);
+
+DapConfig* dap_app_get_config(DapApp* app);
\ No newline at end of file
diff --git a/applications/plugins/dap_link/dap_link.png b/applications/plugins/dap_link/dap_link.png
new file mode 100644
index 00000000..2278ce2b
Binary files /dev/null and b/applications/plugins/dap_link/dap_link.png differ
diff --git a/applications/plugins/dap_link/gui/dap_gui.c b/applications/plugins/dap_link/gui/dap_gui.c
new file mode 100644
index 00000000..4dd98615
--- /dev/null
+++ b/applications/plugins/dap_link/gui/dap_gui.c
@@ -0,0 +1,92 @@
+#include "dap_gui.h"
+#include "dap_gui_i.h"
+
+#define DAP_GUI_TICK 250
+
+static bool dap_gui_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    DapGuiApp* app = context;
+    return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+static bool dap_gui_back_event_callback(void* context) {
+    furi_assert(context);
+    DapGuiApp* app = context;
+    return scene_manager_handle_back_event(app->scene_manager);
+}
+
+static void dap_gui_tick_event_callback(void* context) {
+    furi_assert(context);
+    DapGuiApp* app = context;
+    scene_manager_handle_tick_event(app->scene_manager);
+}
+
+DapGuiApp* dap_gui_alloc() {
+    DapGuiApp* app = malloc(sizeof(DapGuiApp));
+    app->gui = furi_record_open(RECORD_GUI);
+    app->view_dispatcher = view_dispatcher_alloc();
+    app->scene_manager = scene_manager_alloc(&dap_scene_handlers, app);
+    view_dispatcher_enable_queue(app->view_dispatcher);
+    view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
+
+    view_dispatcher_set_custom_event_callback(app->view_dispatcher, dap_gui_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(
+        app->view_dispatcher, dap_gui_back_event_callback);
+    view_dispatcher_set_tick_event_callback(
+        app->view_dispatcher, dap_gui_tick_event_callback, DAP_GUI_TICK);
+
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    app->notifications = furi_record_open(RECORD_NOTIFICATION);
+
+    app->var_item_list = variable_item_list_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        DapGuiAppViewVarItemList,
+        variable_item_list_get_view(app->var_item_list));
+
+    app->main_view = dap_main_view_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, DapGuiAppViewMainView, dap_main_view_get_view(app->main_view));
+
+    app->widget = widget_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, DapGuiAppViewWidget, widget_get_view(app->widget));
+
+    scene_manager_next_scene(app->scene_manager, DapSceneMain);
+
+    return app;
+}
+
+void dap_gui_free(DapGuiApp* app) {
+    view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewVarItemList);
+    variable_item_list_free(app->var_item_list);
+
+    view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewMainView);
+    dap_main_view_free(app->main_view);
+
+    view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewWidget);
+    widget_free(app->widget);
+
+    // View dispatcher
+    view_dispatcher_free(app->view_dispatcher);
+    scene_manager_free(app->scene_manager);
+
+    // Close records
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_NOTIFICATION);
+
+    free(app);
+}
+
+int32_t dap_gui_thread(void* arg) {
+    DapGuiApp* app = dap_gui_alloc();
+    app->dap_app = arg;
+
+    notification_message_block(app->notifications, &sequence_display_backlight_enforce_on);
+    view_dispatcher_run(app->view_dispatcher);
+    notification_message_block(app->notifications, &sequence_display_backlight_enforce_auto);
+
+    dap_gui_free(app);
+    return 0;
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/dap_gui.h b/applications/plugins/dap_link/gui/dap_gui.h
new file mode 100644
index 00000000..3d8e6bdf
--- /dev/null
+++ b/applications/plugins/dap_link/gui/dap_gui.h
@@ -0,0 +1,4 @@
+#pragma once
+#include 
+
+int32_t dap_gui_thread(void* arg);
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/dap_gui_custom_event.h b/applications/plugins/dap_link/gui/dap_gui_custom_event.h
new file mode 100644
index 00000000..8b127c9d
--- /dev/null
+++ b/applications/plugins/dap_link/gui/dap_gui_custom_event.h
@@ -0,0 +1,7 @@
+#pragma once
+
+typedef enum {
+    DapAppCustomEventConfig,
+    DapAppCustomEventHelp,
+    DapAppCustomEventAbout,
+} DapAppCustomEvent;
diff --git a/applications/plugins/dap_link/gui/dap_gui_i.h b/applications/plugins/dap_link/gui/dap_gui_i.h
new file mode 100644
index 00000000..59411e78
--- /dev/null
+++ b/applications/plugins/dap_link/gui/dap_gui_i.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "dap_gui.h"
+#include "../dap_link.h"
+#include "scenes/config/dap_scene.h"
+#include "dap_gui_custom_event.h"
+#include "views/dap_main_view.h"
+
+typedef struct {
+    DapApp* dap_app;
+
+    Gui* gui;
+    NotificationApp* notifications;
+    ViewDispatcher* view_dispatcher;
+    SceneManager* scene_manager;
+
+    VariableItemList* var_item_list;
+    DapMainView* main_view;
+    Widget* widget;
+} DapGuiApp;
+
+typedef enum {
+    DapGuiAppViewVarItemList,
+    DapGuiAppViewMainView,
+    DapGuiAppViewWidget,
+} DapGuiAppView;
diff --git a/applications/plugins/dap_link/gui/scenes/config/dap_scene.c b/applications/plugins/dap_link/gui/scenes/config/dap_scene.c
new file mode 100644
index 00000000..37e23554
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/config/dap_scene.c
@@ -0,0 +1,30 @@
+#include "dap_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const dap_scene_on_enter_handlers[])(void*) = {
+#include "dap_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_event handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
+bool (*const dap_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "dap_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
+void (*const dap_scene_on_exit_handlers[])(void* context) = {
+#include "dap_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers dap_scene_handlers = {
+    .on_enter_handlers = dap_scene_on_enter_handlers,
+    .on_event_handlers = dap_scene_on_event_handlers,
+    .on_exit_handlers = dap_scene_on_exit_handlers,
+    .scene_num = DapSceneNum,
+};
diff --git a/applications/plugins/dap_link/gui/scenes/config/dap_scene.h b/applications/plugins/dap_link/gui/scenes/config/dap_scene.h
new file mode 100644
index 00000000..6fb38da4
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/config/dap_scene.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include 
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) DapScene##id,
+typedef enum {
+#include "dap_scene_config.h"
+    DapSceneNum,
+} DapScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers dap_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "dap_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_event handlers declaration
+#define ADD_SCENE(prefix, name, id) \
+    bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
+#include "dap_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
+#include "dap_scene_config.h"
+#undef ADD_SCENE
diff --git a/applications/plugins/dap_link/gui/scenes/config/dap_scene_config.h b/applications/plugins/dap_link/gui/scenes/config/dap_scene_config.h
new file mode 100644
index 00000000..8957aca0
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/config/dap_scene_config.h
@@ -0,0 +1,4 @@
+ADD_SCENE(dap, main, Main)
+ADD_SCENE(dap, config, Config)
+ADD_SCENE(dap, help, Help)
+ADD_SCENE(dap, about, About)
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/scenes/dap_scene_about.c b/applications/plugins/dap_link/gui/scenes/dap_scene_about.c
new file mode 100644
index 00000000..0974e60a
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/dap_scene_about.c
@@ -0,0 +1,68 @@
+#include "../dap_gui_i.h"
+
+#define DAP_VERSION_APP "0.1.0"
+#define DAP_DEVELOPED "Dr_Zlo"
+#define DAP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
+
+void dap_scene_about_on_enter(void* context) {
+    DapGuiApp* app = context;
+
+    FuriString* temp_str;
+    temp_str = furi_string_alloc();
+    furi_string_printf(temp_str, "\e#%s\n", "Information");
+
+    furi_string_cat_printf(temp_str, "Version: %s\n", DAP_VERSION_APP);
+    furi_string_cat_printf(temp_str, "Developed by: %s\n", DAP_DEVELOPED);
+    furi_string_cat_printf(temp_str, "Github: %s\n\n", DAP_GITHUB);
+
+    furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
+    furi_string_cat_printf(
+        temp_str, "CMSIS-DAP debugger\nbased on Free-DAP\nThanks to Alex Taradov\n\n");
+
+    furi_string_cat_printf(
+        temp_str,
+        "Supported protocols:\n"
+        "SWD, JTAG, UART\n"
+        "DAP v1 (cmsis_backend hid), DAP v2 (cmsis_backend usb_bulk), VCP\n");
+
+    widget_add_text_box_element(
+        app->widget,
+        0,
+        0,
+        128,
+        14,
+        AlignCenter,
+        AlignBottom,
+        "\e#\e!                                                      \e!\n",
+        false);
+    widget_add_text_box_element(
+        app->widget,
+        0,
+        2,
+        128,
+        14,
+        AlignCenter,
+        AlignBottom,
+        "\e#\e!              DAP Link              \e!\n",
+        false);
+    widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
+    furi_string_free(temp_str);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewWidget);
+}
+
+bool dap_scene_about_on_event(void* context, SceneManagerEvent event) {
+    DapGuiApp* app = context;
+    bool consumed = false;
+    UNUSED(app);
+    UNUSED(event);
+
+    return consumed;
+}
+
+void dap_scene_about_on_exit(void* context) {
+    DapGuiApp* app = context;
+
+    // Clear views
+    widget_reset(app->widget);
+}
diff --git a/applications/plugins/dap_link/gui/scenes/dap_scene_config.c b/applications/plugins/dap_link/gui/scenes/dap_scene_config.c
new file mode 100644
index 00000000..56b06411
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/dap_scene_config.c
@@ -0,0 +1,107 @@
+#include "../dap_gui_i.h"
+
+static const char* swd_pins[] = {[DapSwdPinsPA7PA6] = "2,3", [DapSwdPinsPA14PA13] = "10,12"};
+static const char* uart_pins[] = {[DapUartTypeUSART1] = "13,14", [DapUartTypeLPUART1] = "15,16"};
+static const char* uart_swap[] = {[DapUartTXRXNormal] = "No", [DapUartTXRXSwap] = "Yes"};
+
+static void swd_pins_cb(VariableItem* item) {
+    DapGuiApp* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    variable_item_set_current_value_text(item, swd_pins[index]);
+
+    DapConfig* config = dap_app_get_config(app->dap_app);
+    config->swd_pins = index;
+    dap_app_set_config(app->dap_app, config);
+}
+
+static void uart_pins_cb(VariableItem* item) {
+    DapGuiApp* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    variable_item_set_current_value_text(item, uart_pins[index]);
+
+    DapConfig* config = dap_app_get_config(app->dap_app);
+    config->uart_pins = index;
+    dap_app_set_config(app->dap_app, config);
+}
+
+static void uart_swap_cb(VariableItem* item) {
+    DapGuiApp* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    variable_item_set_current_value_text(item, uart_swap[index]);
+
+    DapConfig* config = dap_app_get_config(app->dap_app);
+    config->uart_swap = index;
+    dap_app_set_config(app->dap_app, config);
+}
+
+static void ok_cb(void* context, uint32_t index) {
+    DapGuiApp* app = context;
+    switch(index) {
+    case 3:
+        view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventHelp);
+        break;
+    case 4:
+        view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventAbout);
+        break;
+    default:
+        break;
+    }
+}
+
+void dap_scene_config_on_enter(void* context) {
+    DapGuiApp* app = context;
+    VariableItemList* var_item_list = app->var_item_list;
+    VariableItem* item;
+    DapConfig* config = dap_app_get_config(app->dap_app);
+
+    item = variable_item_list_add(
+        var_item_list, "SWC SWD Pins", COUNT_OF(swd_pins), swd_pins_cb, app);
+    variable_item_set_current_value_index(item, config->swd_pins);
+    variable_item_set_current_value_text(item, swd_pins[config->swd_pins]);
+
+    item =
+        variable_item_list_add(var_item_list, "UART Pins", COUNT_OF(uart_pins), uart_pins_cb, app);
+    variable_item_set_current_value_index(item, config->uart_pins);
+    variable_item_set_current_value_text(item, uart_pins[config->uart_pins]);
+
+    item = variable_item_list_add(
+        var_item_list, "Swap TX RX", COUNT_OF(uart_swap), uart_swap_cb, app);
+    variable_item_set_current_value_index(item, config->uart_swap);
+    variable_item_set_current_value_text(item, uart_swap[config->uart_swap]);
+
+    item = variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL);
+    item = variable_item_list_add(var_item_list, "About", 0, NULL, NULL);
+
+    variable_item_list_set_selected_item(
+        var_item_list, scene_manager_get_scene_state(app->scene_manager, DapSceneConfig));
+
+    variable_item_list_set_enter_callback(var_item_list, ok_cb, app);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewVarItemList);
+}
+
+bool dap_scene_config_on_event(void* context, SceneManagerEvent event) {
+    DapGuiApp* app = context;
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == DapAppCustomEventHelp) {
+            scene_manager_next_scene(app->scene_manager, DapSceneHelp);
+            return true;
+        } else if(event.event == DapAppCustomEventAbout) {
+            scene_manager_next_scene(app->scene_manager, DapSceneAbout);
+            return true;
+        }
+    }
+    return false;
+}
+
+void dap_scene_config_on_exit(void* context) {
+    DapGuiApp* app = context;
+    scene_manager_set_scene_state(
+        app->scene_manager,
+        DapSceneConfig,
+        variable_item_list_get_selected_item_index(app->var_item_list));
+    variable_item_list_reset(app->var_item_list);
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/scenes/dap_scene_help.c b/applications/plugins/dap_link/gui/scenes/dap_scene_help.c
new file mode 100644
index 00000000..7193f4f4
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/dap_scene_help.c
@@ -0,0 +1,102 @@
+#include "../dap_gui_i.h"
+
+void dap_scene_help_on_enter(void* context) {
+    DapGuiApp* app = context;
+    DapConfig* config = dap_app_get_config(app->dap_app);
+    FuriString* string = furi_string_alloc();
+
+    furi_string_cat(string, "CMSIS DAP/DAP Link v2\r\n");
+    furi_string_cat_printf(string, "Serial: %s\r\n", dap_app_get_serial(app->dap_app));
+    furi_string_cat(
+        string,
+        "Pinout:\r\n"
+        "\e#SWD:\r\n");
+
+    switch(config->swd_pins) {
+    case DapSwdPinsPA7PA6:
+        furi_string_cat(
+            string,
+            "    SWC: 2 [A7]\r\n"
+            "    SWD: 3 [A6]\r\n");
+        break;
+    case DapSwdPinsPA14PA13:
+        furi_string_cat(
+            string,
+            "    SWC: 10 [SWC]\r\n"
+            "    SWD: 12 [SIO]\r\n");
+        break;
+    default:
+        break;
+    }
+
+    furi_string_cat(string, "\e#JTAG:\r\n");
+    switch(config->swd_pins) {
+    case DapSwdPinsPA7PA6:
+        furi_string_cat(
+            string,
+            "    TCK: 2 [A7]\r\n"
+            "    TMS: 3 [A6]\r\n"
+            "    RST: 4 [A4]\r\n"
+            "    TDO: 5 [B3]\r\n"
+            "    TDI: 6 [B2]\r\n");
+        break;
+    case DapSwdPinsPA14PA13:
+        furi_string_cat(
+            string,
+            "    RST: 4 [A4]\r\n"
+            "    TDO: 5 [B3]\r\n"
+            "    TDI: 6 [B2]\r\n"
+            "    TCK: 10 [SWC]\r\n"
+            "    TMS: 12 [SIO]\r\n");
+        break;
+    default:
+        break;
+    }
+
+    furi_string_cat(string, "\e#UART:\r\n");
+    switch(config->uart_pins) {
+    case DapUartTypeUSART1:
+        if(config->uart_swap == DapUartTXRXNormal) {
+            furi_string_cat(
+                string,
+                "    TX: 13 [TX]\r\n"
+                "    RX: 14 [RX]\r\n");
+        } else {
+            furi_string_cat(
+                string,
+                "    RX: 13 [TX]\r\n"
+                "    TX: 14 [RX]\r\n");
+        }
+        break;
+    case DapUartTypeLPUART1:
+        if(config->uart_swap == DapUartTXRXNormal) {
+            furi_string_cat(
+                string,
+                "    TX: 15 [С1]\r\n"
+                "    RX: 16 [С0]\r\n");
+        } else {
+            furi_string_cat(
+                string,
+                "    RX: 15 [С1]\r\n"
+                "    TX: 16 [С0]\r\n");
+        }
+        break;
+    default:
+        break;
+    }
+
+    widget_add_text_scroll_element(app->widget, 0, 0, 128, 64, furi_string_get_cstr(string));
+    furi_string_free(string);
+    view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewWidget);
+}
+
+bool dap_scene_help_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    return false;
+}
+
+void dap_scene_help_on_exit(void* context) {
+    DapGuiApp* app = context;
+    widget_reset(app->widget);
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/scenes/dap_scene_main.c b/applications/plugins/dap_link/gui/scenes/dap_scene_main.c
new file mode 100644
index 00000000..8c19bd6a
--- /dev/null
+++ b/applications/plugins/dap_link/gui/scenes/dap_scene_main.c
@@ -0,0 +1,154 @@
+#include "../dap_gui_i.h"
+#include "../../dap_link.h"
+
+typedef struct {
+    DapState dap_state;
+    bool dap_active;
+    bool tx_active;
+    bool rx_active;
+} DapSceneMainState;
+
+static bool process_dap_state(DapGuiApp* app) {
+    DapSceneMainState* state =
+        (DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain);
+    if(state == NULL) return true;
+
+    DapState* prev_state = &state->dap_state;
+    DapState next_state;
+    dap_app_get_state(app->dap_app, &next_state);
+    bool need_to_update = false;
+
+    if(prev_state->dap_mode != next_state.dap_mode) {
+        switch(next_state.dap_mode) {
+        case DapModeDisconnected:
+            dap_main_view_set_mode(app->main_view, DapMainViewModeDisconnected);
+            notification_message(app->notifications, &sequence_blink_stop);
+            break;
+        case DapModeSWD:
+            dap_main_view_set_mode(app->main_view, DapMainViewModeSWD);
+            notification_message(app->notifications, &sequence_blink_start_blue);
+            break;
+        case DapModeJTAG:
+            dap_main_view_set_mode(app->main_view, DapMainViewModeJTAG);
+            notification_message(app->notifications, &sequence_blink_start_magenta);
+            break;
+        }
+        need_to_update = true;
+    }
+
+    if(prev_state->dap_version != next_state.dap_version) {
+        switch(next_state.dap_version) {
+        case DapVersionUnknown:
+            dap_main_view_set_version(app->main_view, DapMainViewVersionUnknown);
+            break;
+        case DapVersionV1:
+            dap_main_view_set_version(app->main_view, DapMainViewVersionV1);
+            break;
+        case DapVersionV2:
+            dap_main_view_set_version(app->main_view, DapMainViewVersionV2);
+            break;
+        }
+        need_to_update = true;
+    }
+
+    if(prev_state->usb_connected != next_state.usb_connected) {
+        dap_main_view_set_usb_connected(app->main_view, next_state.usb_connected);
+        need_to_update = true;
+    }
+
+    if(prev_state->dap_counter != next_state.dap_counter) {
+        if(!state->dap_active) {
+            state->dap_active = true;
+            dap_main_view_set_dap(app->main_view, state->dap_active);
+            need_to_update = true;
+        }
+    } else {
+        if(state->dap_active) {
+            state->dap_active = false;
+            dap_main_view_set_dap(app->main_view, state->dap_active);
+            need_to_update = true;
+        }
+    }
+
+    if(prev_state->cdc_baudrate != next_state.cdc_baudrate) {
+        dap_main_view_set_baudrate(app->main_view, next_state.cdc_baudrate);
+        need_to_update = true;
+    }
+
+    if(prev_state->cdc_tx_counter != next_state.cdc_tx_counter) {
+        if(!state->tx_active) {
+            state->tx_active = true;
+            dap_main_view_set_tx(app->main_view, state->tx_active);
+            need_to_update = true;
+            notification_message(app->notifications, &sequence_blink_start_red);
+        }
+    } else {
+        if(state->tx_active) {
+            state->tx_active = false;
+            dap_main_view_set_tx(app->main_view, state->tx_active);
+            need_to_update = true;
+            notification_message(app->notifications, &sequence_blink_stop);
+        }
+    }
+
+    if(prev_state->cdc_rx_counter != next_state.cdc_rx_counter) {
+        if(!state->rx_active) {
+            state->rx_active = true;
+            dap_main_view_set_rx(app->main_view, state->rx_active);
+            need_to_update = true;
+            notification_message(app->notifications, &sequence_blink_start_green);
+        }
+    } else {
+        if(state->rx_active) {
+            state->rx_active = false;
+            dap_main_view_set_rx(app->main_view, state->rx_active);
+            need_to_update = true;
+            notification_message(app->notifications, &sequence_blink_stop);
+        }
+    }
+
+    if(need_to_update) {
+        dap_main_view_update(app->main_view);
+    }
+
+    *prev_state = next_state;
+    return true;
+}
+
+static void dap_scene_main_on_left(void* context) {
+    DapGuiApp* app = (DapGuiApp*)context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventConfig);
+}
+
+void dap_scene_main_on_enter(void* context) {
+    DapGuiApp* app = context;
+    DapSceneMainState* state = malloc(sizeof(DapSceneMainState));
+    dap_main_view_set_left_callback(app->main_view, dap_scene_main_on_left, app);
+    view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewMainView);
+    scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)state);
+}
+
+bool dap_scene_main_on_event(void* context, SceneManagerEvent event) {
+    DapGuiApp* app = context;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == DapAppCustomEventConfig) {
+            scene_manager_next_scene(app->scene_manager, DapSceneConfig);
+            return true;
+        }
+    } else if(event.type == SceneManagerEventTypeTick) {
+        return process_dap_state(app);
+    }
+
+    return false;
+}
+
+void dap_scene_main_on_exit(void* context) {
+    DapGuiApp* app = context;
+    DapSceneMainState* state =
+        (DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain);
+    scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)NULL);
+    FURI_SW_MEMBARRIER();
+    free(state);
+    notification_message(app->notifications, &sequence_blink_stop);
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/views/dap_main_view.c b/applications/plugins/dap_link/gui/views/dap_main_view.c
new file mode 100644
index 00000000..c5c8f9df
--- /dev/null
+++ b/applications/plugins/dap_link/gui/views/dap_main_view.c
@@ -0,0 +1,189 @@
+#include "dap_main_view.h"
+#include "dap_link_icons.h"
+#include 
+
+// extern const Icon I_ArrowDownEmpty_12x18;
+// extern const Icon I_ArrowDownFilled_12x18;
+// extern const Icon I_ArrowUpEmpty_12x18;
+// extern const Icon I_ArrowUpFilled_12x18;
+
+struct DapMainView {
+    View* view;
+    DapMainViewButtonCallback cb_left;
+    void* cb_context;
+};
+
+typedef struct {
+    DapMainViewMode mode;
+    DapMainViewVersion version;
+    bool usb_connected;
+    uint32_t baudrate;
+    bool dap_active;
+    bool tx_active;
+    bool rx_active;
+} DapMainViewModel;
+
+static void dap_main_view_draw_callback(Canvas* canvas, void* _model) {
+    DapMainViewModel* model = _model;
+    UNUSED(model);
+    canvas_clear(canvas);
+    elements_button_left(canvas, "Config");
+
+    canvas_set_color(canvas, ColorBlack);
+    canvas_draw_box(canvas, 0, 0, 127, 11);
+    canvas_set_color(canvas, ColorWhite);
+
+    const char* header_string;
+    if(model->usb_connected) {
+        if(model->version == DapMainViewVersionV1) {
+            header_string = "DAP Link V1 Connected";
+        } else if(model->version == DapMainViewVersionV2) {
+            header_string = "DAP Link V2 Connected";
+        } else {
+            header_string = "DAP Link Connected";
+        }
+    } else {
+        header_string = "DAP Link";
+    }
+
+    canvas_draw_str_aligned(canvas, 64, 9, AlignCenter, AlignBottom, header_string);
+
+    canvas_set_color(canvas, ColorBlack);
+    if(model->dap_active) {
+        canvas_draw_icon(canvas, 14, 16, &I_ArrowUpFilled_12x18);
+        canvas_draw_icon(canvas, 28, 16, &I_ArrowDownFilled_12x18);
+    } else {
+        canvas_draw_icon(canvas, 14, 16, &I_ArrowUpEmpty_12x18);
+        canvas_draw_icon(canvas, 28, 16, &I_ArrowDownEmpty_12x18);
+    }
+
+    switch(model->mode) {
+    case DapMainViewModeDisconnected:
+        canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "----");
+        break;
+    case DapMainViewModeSWD:
+        canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "SWD");
+        break;
+    case DapMainViewModeJTAG:
+        canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "JTAG");
+        break;
+    }
+
+    if(model->tx_active) {
+        canvas_draw_icon(canvas, 87, 16, &I_ArrowUpFilled_12x18);
+    } else {
+        canvas_draw_icon(canvas, 87, 16, &I_ArrowUpEmpty_12x18);
+    }
+
+    if(model->rx_active) {
+        canvas_draw_icon(canvas, 101, 16, &I_ArrowDownFilled_12x18);
+    } else {
+        canvas_draw_icon(canvas, 101, 16, &I_ArrowDownEmpty_12x18);
+    }
+
+    canvas_draw_str_aligned(canvas, 100, 38, AlignCenter, AlignTop, "UART");
+
+    canvas_draw_line(canvas, 44, 52, 123, 52);
+    if(model->baudrate == 0) {
+        canvas_draw_str(canvas, 45, 62, "Baud: ????");
+    } else {
+        char baudrate_str[18];
+        snprintf(baudrate_str, 18, "Baud: %lu", model->baudrate);
+        canvas_draw_str(canvas, 45, 62, baudrate_str);
+    }
+}
+
+static bool dap_main_view_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    DapMainView* dap_main_view = context;
+    bool consumed = false;
+
+    if(event->type == InputTypeShort) {
+        if(event->key == InputKeyLeft) {
+            if(dap_main_view->cb_left) {
+                dap_main_view->cb_left(dap_main_view->cb_context);
+            }
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+DapMainView* dap_main_view_alloc() {
+    DapMainView* dap_main_view = malloc(sizeof(DapMainView));
+
+    dap_main_view->view = view_alloc();
+    view_allocate_model(dap_main_view->view, ViewModelTypeLocking, sizeof(DapMainViewModel));
+    view_set_context(dap_main_view->view, dap_main_view);
+    view_set_draw_callback(dap_main_view->view, dap_main_view_draw_callback);
+    view_set_input_callback(dap_main_view->view, dap_main_view_input_callback);
+    return dap_main_view;
+}
+
+void dap_main_view_free(DapMainView* dap_main_view) {
+    view_free(dap_main_view->view);
+    free(dap_main_view);
+}
+
+View* dap_main_view_get_view(DapMainView* dap_main_view) {
+    return dap_main_view->view;
+}
+
+void dap_main_view_set_left_callback(
+    DapMainView* dap_main_view,
+    DapMainViewButtonCallback callback,
+    void* context) {
+    with_view_model(
+        dap_main_view->view,
+        DapMainViewModel * model,
+        {
+            UNUSED(model);
+            dap_main_view->cb_left = callback;
+            dap_main_view->cb_context = context;
+        },
+        true);
+}
+
+void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->mode = mode; }, false);
+}
+
+void dap_main_view_set_dap(DapMainView* dap_main_view, bool active) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->dap_active = active; }, false);
+}
+
+void dap_main_view_set_tx(DapMainView* dap_main_view, bool active) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->tx_active = active; }, false);
+}
+
+void dap_main_view_set_rx(DapMainView* dap_main_view, bool active) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->rx_active = active; }, false);
+}
+
+void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->baudrate = baudrate; }, false);
+}
+
+void dap_main_view_update(DapMainView* dap_main_view) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { UNUSED(model); }, true);
+}
+
+void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version) {
+    with_view_model(
+        dap_main_view->view, DapMainViewModel * model, { model->version = version; }, false);
+}
+
+void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected) {
+    with_view_model(
+        dap_main_view->view,
+        DapMainViewModel * model,
+        { model->usb_connected = connected; },
+        false);
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/gui/views/dap_main_view.h b/applications/plugins/dap_link/gui/views/dap_main_view.h
new file mode 100644
index 00000000..1fd90045
--- /dev/null
+++ b/applications/plugins/dap_link/gui/views/dap_main_view.h
@@ -0,0 +1,45 @@
+#pragma once
+#include 
+
+typedef struct DapMainView DapMainView;
+
+typedef void (*DapMainViewButtonCallback)(void* context);
+
+typedef enum {
+    DapMainViewVersionUnknown,
+    DapMainViewVersionV1,
+    DapMainViewVersionV2,
+} DapMainViewVersion;
+
+typedef enum {
+    DapMainViewModeDisconnected,
+    DapMainViewModeSWD,
+    DapMainViewModeJTAG,
+} DapMainViewMode;
+
+DapMainView* dap_main_view_alloc();
+
+void dap_main_view_free(DapMainView* dap_main_view);
+
+View* dap_main_view_get_view(DapMainView* dap_main_view);
+
+void dap_main_view_set_left_callback(
+    DapMainView* dap_main_view,
+    DapMainViewButtonCallback callback,
+    void* context);
+
+void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode);
+
+void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version);
+
+void dap_main_view_set_dap(DapMainView* dap_main_view, bool active);
+
+void dap_main_view_set_tx(DapMainView* dap_main_view, bool active);
+
+void dap_main_view_set_rx(DapMainView* dap_main_view, bool active);
+
+void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected);
+
+void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate);
+
+void dap_main_view_update(DapMainView* dap_main_view);
\ No newline at end of file
diff --git a/applications/plugins/dap_link/icons/ArrowDownEmpty_12x18.png b/applications/plugins/dap_link/icons/ArrowDownEmpty_12x18.png
new file mode 100644
index 00000000..6007f74a
Binary files /dev/null and b/applications/plugins/dap_link/icons/ArrowDownEmpty_12x18.png differ
diff --git a/applications/plugins/dap_link/icons/ArrowDownFilled_12x18.png b/applications/plugins/dap_link/icons/ArrowDownFilled_12x18.png
new file mode 100644
index 00000000..5541e772
Binary files /dev/null and b/applications/plugins/dap_link/icons/ArrowDownFilled_12x18.png differ
diff --git a/applications/plugins/dap_link/icons/ArrowUpEmpty_12x18.png b/applications/plugins/dap_link/icons/ArrowUpEmpty_12x18.png
new file mode 100644
index 00000000..c9365a67
Binary files /dev/null and b/applications/plugins/dap_link/icons/ArrowUpEmpty_12x18.png differ
diff --git a/applications/plugins/dap_link/icons/ArrowUpFilled_12x18.png b/applications/plugins/dap_link/icons/ArrowUpFilled_12x18.png
new file mode 100644
index 00000000..dc481517
Binary files /dev/null and b/applications/plugins/dap_link/icons/ArrowUpFilled_12x18.png differ
diff --git a/applications/plugins/dap_link/lib/free-dap b/applications/plugins/dap_link/lib/free-dap
new file mode 160000
index 00000000..e7752beb
--- /dev/null
+++ b/applications/plugins/dap_link/lib/free-dap
@@ -0,0 +1 @@
+Subproject commit e7752beb5e8a69119af67b70b9179cb3c90f3ac5
diff --git a/applications/plugins/dap_link/usb/dap_v2_usb.c b/applications/plugins/dap_link/usb/dap_v2_usb.c
new file mode 100644
index 00000000..0c303a3b
--- /dev/null
+++ b/applications/plugins/dap_link/usb/dap_v2_usb.c
@@ -0,0 +1,994 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "dap_v2_usb.h"
+
+// #define DAP_USB_LOG
+
+#define HID_EP_IN 0x80
+#define HID_EP_OUT 0x00
+
+#define DAP_HID_EP_SEND 1
+#define DAP_HID_EP_RECV 2
+#define DAP_HID_EP_BULK_RECV 3
+#define DAP_HID_EP_BULK_SEND 4
+#define DAP_CDC_EP_COMM 5
+#define DAP_CDC_EP_SEND 6
+#define DAP_CDC_EP_RECV 7
+
+#define DAP_HID_EP_IN (HID_EP_IN | DAP_HID_EP_SEND)
+#define DAP_HID_EP_OUT (HID_EP_OUT | DAP_HID_EP_RECV)
+#define DAP_HID_EP_BULK_IN (HID_EP_IN | DAP_HID_EP_BULK_SEND)
+#define DAP_HID_EP_BULK_OUT (HID_EP_OUT | DAP_HID_EP_BULK_RECV)
+
+#define DAP_HID_EP_SIZE 64
+#define DAP_CDC_COMM_EP_SIZE 8
+#define DAP_CDC_EP_SIZE 64
+
+#define DAP_BULK_INTERVAL 0
+#define DAP_HID_INTERVAL 1
+#define DAP_CDC_INTERVAL 0
+#define DAP_CDC_COMM_INTERVAL 1
+
+#define DAP_HID_VID 0x0483
+#define DAP_HID_PID 0x5740
+
+#define DAP_USB_EP0_SIZE 8
+
+#define EP_CFG_DECONFIGURE 0
+#define EP_CFG_CONFIGURE 1
+
+enum {
+    USB_INTF_HID,
+    USB_INTF_BULK,
+    USB_INTF_CDC_COMM,
+    USB_INTF_CDC_DATA,
+    USB_INTF_COUNT,
+};
+
+enum {
+    USB_STR_ZERO,
+    USB_STR_MANUFACTURER,
+    USB_STR_PRODUCT,
+    USB_STR_SERIAL_NUMBER,
+    USB_STR_CMSIS_DAP_V1,
+    USB_STR_CMSIS_DAP_V2,
+    USB_STR_COM_PORT,
+    USB_STR_COUNT,
+};
+
+// static const char* usb_str[] = {
+//     [USB_STR_MANUFACTURER] = "Flipper Devices Inc.",
+//     [USB_STR_PRODUCT] = "Combined VCP and CMSIS-DAP Adapter",
+//     [USB_STR_COM_PORT] = "Virtual COM-Port",
+//     [USB_STR_CMSIS_DAP_V1] = "CMSIS-DAP v1 Adapter",
+//     [USB_STR_CMSIS_DAP_V2] = "CMSIS-DAP v2 Adapter",
+//     [USB_STR_SERIAL_NUMBER] = "01234567890ABCDEF",
+// };
+
+static const struct usb_string_descriptor dev_manuf_descr =
+    USB_STRING_DESC("Flipper Devices Inc.");
+
+static const struct usb_string_descriptor dev_prod_descr =
+    USB_STRING_DESC("Combined VCP and CMSIS-DAP Adapter");
+
+static struct usb_string_descriptor* dev_serial_descr = NULL;
+
+static const struct usb_string_descriptor dev_dap_v1_descr =
+    USB_STRING_DESC("CMSIS-DAP v1 Adapter");
+
+static const struct usb_string_descriptor dev_dap_v2_descr =
+    USB_STRING_DESC("CMSIS-DAP v2 Adapter");
+
+static const struct usb_string_descriptor dev_com_descr = USB_STRING_DESC("Virtual COM-Port");
+
+struct HidConfigDescriptor {
+    struct usb_config_descriptor configuration;
+
+    // CMSIS-DAP v1
+    struct usb_interface_descriptor hid_interface;
+    struct usb_hid_descriptor hid;
+    struct usb_endpoint_descriptor hid_ep_in;
+    struct usb_endpoint_descriptor hid_ep_out;
+
+    // CMSIS-DAP v2
+    struct usb_interface_descriptor bulk_interface;
+    struct usb_endpoint_descriptor bulk_ep_out;
+    struct usb_endpoint_descriptor bulk_ep_in;
+
+    // CDC
+    struct usb_iad_descriptor iad;
+    struct usb_interface_descriptor interface_comm;
+    struct usb_cdc_header_desc cdc_header;
+    struct usb_cdc_call_mgmt_desc cdc_acm;
+    struct usb_cdc_acm_desc cdc_call_mgmt;
+    struct usb_cdc_union_desc cdc_union;
+    struct usb_endpoint_descriptor ep_comm;
+    struct usb_interface_descriptor interface_data;
+    struct usb_endpoint_descriptor ep_in;
+    struct usb_endpoint_descriptor ep_out;
+
+} __attribute__((packed));
+
+static const struct usb_device_descriptor hid_device_desc = {
+    .bLength = sizeof(struct usb_device_descriptor),
+    .bDescriptorType = USB_DTYPE_DEVICE,
+    .bcdUSB = VERSION_BCD(2, 1, 0),
+    .bDeviceClass = USB_CLASS_MISC,
+    .bDeviceSubClass = USB_SUBCLASS_IAD,
+    .bDeviceProtocol = USB_PROTO_IAD,
+    .bMaxPacketSize0 = DAP_USB_EP0_SIZE,
+    .idVendor = DAP_HID_VID,
+    .idProduct = DAP_HID_PID,
+    .bcdDevice = VERSION_BCD(1, 0, 0),
+    .iManufacturer = USB_STR_MANUFACTURER,
+    .iProduct = USB_STR_PRODUCT,
+    .iSerialNumber = USB_STR_SERIAL_NUMBER,
+    .bNumConfigurations = 1,
+};
+
+static const uint8_t hid_report_desc[] = {
+    0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x00, // Usage (Undefined)
+    0xa1, 0x01, // Collection (Application)
+    0x15, 0x00, //   Logical Minimum (0)
+    0x26, 0xff, 0x00, //   Logical Maximum (255)
+    0x75, 0x08, //   Report Size (8)
+    0x95, 0x40, //   Report Count (64)
+    0x09, 0x00, //   Usage (Undefined)
+    0x81, 0x82, //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+    0x75, 0x08, //   Report Size (8)
+    0x95, 0x40, //   Report Count (64)
+    0x09, 0x00, //   Usage (Undefined)
+    0x91, 0x82, //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
+    0xc0, // End Collection
+};
+
+static const struct HidConfigDescriptor hid_cfg_desc = {
+    .configuration =
+        {
+            .bLength = sizeof(struct usb_config_descriptor),
+            .bDescriptorType = USB_DTYPE_CONFIGURATION,
+            .wTotalLength = sizeof(struct HidConfigDescriptor),
+            .bNumInterfaces = USB_INTF_COUNT,
+            .bConfigurationValue = 1,
+            .iConfiguration = NO_DESCRIPTOR,
+            .bmAttributes = USB_CFG_ATTR_RESERVED,
+            .bMaxPower = USB_CFG_POWER_MA(500),
+        },
+
+    // CMSIS-DAP v1
+    .hid_interface =
+        {
+            .bLength = sizeof(struct usb_interface_descriptor),
+            .bDescriptorType = USB_DTYPE_INTERFACE,
+            .bInterfaceNumber = USB_INTF_HID,
+            .bAlternateSetting = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = USB_CLASS_HID,
+            .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT,
+            .bInterfaceProtocol = USB_HID_PROTO_NONBOOT,
+            .iInterface = USB_STR_CMSIS_DAP_V1,
+        },
+
+    .hid =
+        {
+            .bLength = sizeof(struct usb_hid_descriptor),
+            .bDescriptorType = USB_DTYPE_HID,
+            .bcdHID = VERSION_BCD(1, 1, 1),
+            .bCountryCode = USB_HID_COUNTRY_NONE,
+            .bNumDescriptors = 1,
+            .bDescriptorType0 = USB_DTYPE_HID_REPORT,
+            .wDescriptorLength0 = sizeof(hid_report_desc),
+        },
+
+    .hid_ep_in =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = DAP_HID_EP_IN,
+            .bmAttributes = USB_EPTYPE_INTERRUPT,
+            .wMaxPacketSize = DAP_HID_EP_SIZE,
+            .bInterval = DAP_HID_INTERVAL,
+        },
+
+    .hid_ep_out =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = DAP_HID_EP_OUT,
+            .bmAttributes = USB_EPTYPE_INTERRUPT,
+            .wMaxPacketSize = DAP_HID_EP_SIZE,
+            .bInterval = DAP_HID_INTERVAL,
+        },
+
+    // CMSIS-DAP v2
+    .bulk_interface =
+        {
+            .bLength = sizeof(struct usb_interface_descriptor),
+            .bDescriptorType = USB_DTYPE_INTERFACE,
+            .bInterfaceNumber = USB_INTF_BULK,
+            .bAlternateSetting = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = USB_CLASS_VENDOR,
+            .bInterfaceSubClass = 0,
+            .bInterfaceProtocol = 0,
+            .iInterface = USB_STR_CMSIS_DAP_V2,
+        },
+
+    .bulk_ep_out =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = DAP_HID_EP_BULK_OUT,
+            .bmAttributes = USB_EPTYPE_BULK,
+            .wMaxPacketSize = DAP_HID_EP_SIZE,
+            .bInterval = DAP_BULK_INTERVAL,
+        },
+
+    .bulk_ep_in =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = DAP_HID_EP_BULK_IN,
+            .bmAttributes = USB_EPTYPE_BULK,
+            .wMaxPacketSize = DAP_HID_EP_SIZE,
+            .bInterval = DAP_BULK_INTERVAL,
+        },
+
+    // CDC
+    .iad =
+        {
+            .bLength = sizeof(struct usb_iad_descriptor),
+            .bDescriptorType = USB_DTYPE_INTERFASEASSOC,
+            .bFirstInterface = USB_INTF_CDC_COMM,
+            .bInterfaceCount = 2,
+            .bFunctionClass = USB_CLASS_CDC,
+            .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
+            .bFunctionProtocol = USB_PROTO_NONE,
+            .iFunction = USB_STR_COM_PORT,
+        },
+    .interface_comm =
+        {
+            .bLength = sizeof(struct usb_interface_descriptor),
+            .bDescriptorType = USB_DTYPE_INTERFACE,
+            .bInterfaceNumber = USB_INTF_CDC_COMM,
+            .bAlternateSetting = 0,
+            .bNumEndpoints = 1,
+            .bInterfaceClass = USB_CLASS_CDC,
+            .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+            .bInterfaceProtocol = USB_PROTO_NONE,
+            .iInterface = 0,
+        },
+
+    .cdc_header =
+        {
+            .bFunctionLength = sizeof(struct usb_cdc_header_desc),
+            .bDescriptorType = USB_DTYPE_CS_INTERFACE,
+            .bDescriptorSubType = USB_DTYPE_CDC_HEADER,
+            .bcdCDC = VERSION_BCD(1, 1, 0),
+        },
+
+    .cdc_acm =
+        {
+            .bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
+            .bDescriptorType = USB_DTYPE_CS_INTERFACE,
+            .bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
+            // .bmCapabilities = USB_CDC_CAP_LINE | USB_CDC_CAP_BRK,
+            .bmCapabilities = 0,
+        },
+
+    .cdc_call_mgmt =
+        {
+            .bFunctionLength = sizeof(struct usb_cdc_acm_desc),
+            .bDescriptorType = USB_DTYPE_CS_INTERFACE,
+            .bDescriptorSubType = USB_DTYPE_CDC_ACM,
+            .bmCapabilities = USB_CDC_CALL_MGMT_CAP_DATA_INTF,
+            // .bDataInterface = USB_INTF_CDC_DATA,
+        },
+
+    .cdc_union =
+        {
+            .bFunctionLength = sizeof(struct usb_cdc_union_desc),
+            .bDescriptorType = USB_DTYPE_CS_INTERFACE,
+            .bDescriptorSubType = USB_DTYPE_CDC_UNION,
+            .bMasterInterface0 = USB_INTF_CDC_COMM,
+            .bSlaveInterface0 = USB_INTF_CDC_DATA,
+        },
+
+    .ep_comm =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = HID_EP_IN | DAP_CDC_EP_COMM,
+            .bmAttributes = USB_EPTYPE_INTERRUPT,
+            .wMaxPacketSize = DAP_CDC_COMM_EP_SIZE,
+            .bInterval = DAP_CDC_COMM_INTERVAL,
+        },
+
+    .interface_data =
+        {
+            .bLength = sizeof(struct usb_interface_descriptor),
+            .bDescriptorType = USB_DTYPE_INTERFACE,
+            .bInterfaceNumber = USB_INTF_CDC_DATA,
+            .bAlternateSetting = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = USB_CLASS_CDC_DATA,
+            .bInterfaceSubClass = USB_SUBCLASS_NONE,
+            .bInterfaceProtocol = USB_PROTO_NONE,
+            .iInterface = NO_DESCRIPTOR,
+        },
+
+    .ep_in =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = HID_EP_IN | DAP_CDC_EP_SEND,
+            .bmAttributes = USB_EPTYPE_BULK,
+            .wMaxPacketSize = DAP_CDC_EP_SIZE,
+            .bInterval = DAP_CDC_INTERVAL,
+        },
+
+    .ep_out =
+        {
+            .bLength = sizeof(struct usb_endpoint_descriptor),
+            .bDescriptorType = USB_DTYPE_ENDPOINT,
+            .bEndpointAddress = HID_EP_OUT | DAP_CDC_EP_RECV,
+            .bmAttributes = USB_EPTYPE_BULK,
+            .wMaxPacketSize = DAP_CDC_EP_SIZE,
+            .bInterval = DAP_CDC_INTERVAL,
+        },
+};
+
+// WinUSB
+#include "usb_winusb.h"
+
+typedef struct USB_PACK {
+    usb_binary_object_store_descriptor_t bos;
+    usb_winusb_capability_descriptor_t winusb;
+} usb_bos_hierarchy_t;
+
+typedef struct USB_PACK {
+    usb_winusb_subset_header_function_t header;
+    usb_winusb_feature_compatble_id_t comp_id;
+    usb_winusb_feature_reg_property_guids_t property;
+} usb_msos_descriptor_subset_t;
+
+typedef struct USB_PACK {
+    usb_winusb_set_header_descriptor_t header;
+    usb_msos_descriptor_subset_t subset;
+} usb_msos_descriptor_set_t;
+
+#define USB_DTYPE_BINARY_OBJECT_STORE 15
+#define USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR 16
+#define USB_DC_TYPE_PLATFORM 5
+
+const usb_bos_hierarchy_t usb_bos_hierarchy = {
+    .bos =
+        {
+            .bLength = sizeof(usb_binary_object_store_descriptor_t),
+            .bDescriptorType = USB_DTYPE_BINARY_OBJECT_STORE,
+            .wTotalLength = sizeof(usb_bos_hierarchy_t),
+            .bNumDeviceCaps = 1,
+        },
+    .winusb =
+        {
+            .bLength = sizeof(usb_winusb_capability_descriptor_t),
+            .bDescriptorType = USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR,
+            .bDevCapabilityType = USB_DC_TYPE_PLATFORM,
+            .bReserved = 0,
+            .PlatformCapabilityUUID = USB_WINUSB_PLATFORM_CAPABILITY_ID,
+            .dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
+            .wMSOSDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
+            .bMS_VendorCode = USB_WINUSB_VENDOR_CODE,
+            .bAltEnumCode = 0,
+        },
+};
+
+const usb_msos_descriptor_set_t usb_msos_descriptor_set = {
+    .header =
+        {
+            .wLength = sizeof(usb_winusb_set_header_descriptor_t),
+            .wDescriptorType = USB_WINUSB_SET_HEADER_DESCRIPTOR,
+            .dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
+            .wDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
+        },
+
+    .subset =
+        {
+            .header =
+                {
+                    .wLength = sizeof(usb_winusb_subset_header_function_t),
+                    .wDescriptorType = USB_WINUSB_SUBSET_HEADER_FUNCTION,
+                    .bFirstInterface = USB_INTF_BULK,
+                    .bReserved = 0,
+                    .wSubsetLength = sizeof(usb_msos_descriptor_subset_t),
+                },
+
+            .comp_id =
+                {
+                    .wLength = sizeof(usb_winusb_feature_compatble_id_t),
+                    .wDescriptorType = USB_WINUSB_FEATURE_COMPATBLE_ID,
+                    .CompatibleID = "WINUSB\0\0",
+                    .SubCompatibleID = {0},
+                },
+
+            .property =
+                {
+                    .wLength = sizeof(usb_winusb_feature_reg_property_guids_t),
+                    .wDescriptorType = USB_WINUSB_FEATURE_REG_PROPERTY,
+                    .wPropertyDataType = USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ,
+                    .wPropertyNameLength =
+                        sizeof(usb_msos_descriptor_set.subset.property.PropertyName),
+                    .PropertyName = {'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0,
+                                     'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0,
+                                     'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0,   0},
+                    .wPropertyDataLength =
+                        sizeof(usb_msos_descriptor_set.subset.property.PropertyData),
+                    .PropertyData = {'{', 0, 'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0,
+                                     'A', 0, 'D', 0, '-', 0, '2', 0, '9', 0, '3', 0, 'B', 0,
+                                     '-', 0, '4', 0, '6', 0, '6', 0, '3', 0, '-', 0, 'A', 0,
+                                     'A', 0, '3', 0, '6', 0, '-', 0, '1', 0, 'A', 0, 'A', 0,
+                                     'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0,
+                                     '7', 0, '6', 0, '}', 0, 0,   0, 0,   0},
+                },
+        },
+};
+
+typedef struct {
+    FuriSemaphore* semaphore_v1;
+    FuriSemaphore* semaphore_v2;
+    FuriSemaphore* semaphore_cdc;
+    bool connected;
+    usbd_device* usb_dev;
+    DapStateCallback state_callback;
+    DapRxCallback rx_callback_v1;
+    DapRxCallback rx_callback_v2;
+    DapRxCallback rx_callback_cdc;
+    DapCDCControlLineCallback control_line_callback_cdc;
+    DapCDCConfigCallback config_callback_cdc;
+    void* context;
+    void* context_cdc;
+} DAPState;
+
+static DAPState dap_state = {
+    .semaphore_v1 = NULL,
+    .semaphore_v2 = NULL,
+    .semaphore_cdc = NULL,
+    .connected = false,
+    .usb_dev = NULL,
+    .state_callback = NULL,
+    .rx_callback_v1 = NULL,
+    .rx_callback_v2 = NULL,
+    .rx_callback_cdc = NULL,
+    .control_line_callback_cdc = NULL,
+    .config_callback_cdc = NULL,
+    .context = NULL,
+    .context_cdc = NULL,
+};
+
+static struct usb_cdc_line_coding cdc_config = {0};
+static uint8_t cdc_ctrl_line_state = 0;
+
+#ifdef DAP_USB_LOG
+void furi_console_log_printf(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
+
+void furi_console_log_printf(const char* format, ...) {
+    char buffer[256];
+    va_list args;
+    va_start(args, format);
+    vsnprintf(buffer, sizeof(buffer), format, args);
+    va_end(args);
+    furi_hal_console_puts(buffer);
+    furi_hal_console_puts("\r\n");
+    UNUSED(format);
+}
+#else
+#define furi_console_log_printf(...)
+#endif
+
+int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size) {
+    if((dap_state.semaphore_v1 == NULL) || (dap_state.connected == false)) return 0;
+
+    furi_check(furi_semaphore_acquire(dap_state.semaphore_v1, FuriWaitForever) == FuriStatusOk);
+
+    if(dap_state.connected) {
+        int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_IN, buffer, size);
+        furi_console_log_printf("v1 tx %ld", len);
+        return len;
+    } else {
+        return 0;
+    }
+}
+
+int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size) {
+    if((dap_state.semaphore_v2 == NULL) || (dap_state.connected == false)) return 0;
+
+    furi_check(furi_semaphore_acquire(dap_state.semaphore_v2, FuriWaitForever) == FuriStatusOk);
+
+    if(dap_state.connected) {
+        int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_BULK_IN, buffer, size);
+        furi_console_log_printf("v2 tx %ld", len);
+        return len;
+    } else {
+        return 0;
+    }
+}
+
+int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size) {
+    if((dap_state.semaphore_cdc == NULL) || (dap_state.connected == false)) return 0;
+
+    furi_check(furi_semaphore_acquire(dap_state.semaphore_cdc, FuriWaitForever) == FuriStatusOk);
+
+    if(dap_state.connected) {
+        int32_t len = usbd_ep_write(dap_state.usb_dev, HID_EP_IN | DAP_CDC_EP_SEND, buffer, size);
+        furi_console_log_printf("cdc tx %ld", len);
+        return len;
+    } else {
+        return 0;
+    }
+}
+
+void dap_v1_usb_set_rx_callback(DapRxCallback callback) {
+    dap_state.rx_callback_v1 = callback;
+}
+
+void dap_v2_usb_set_rx_callback(DapRxCallback callback) {
+    dap_state.rx_callback_v2 = callback;
+}
+
+void dap_cdc_usb_set_rx_callback(DapRxCallback callback) {
+    dap_state.rx_callback_cdc = callback;
+}
+
+void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback) {
+    dap_state.control_line_callback_cdc = callback;
+}
+
+void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback) {
+    dap_state.config_callback_cdc = callback;
+}
+
+void dap_cdc_usb_set_context(void* context) {
+    dap_state.context_cdc = context;
+}
+
+void dap_common_usb_set_context(void* context) {
+    dap_state.context = context;
+}
+
+void dap_common_usb_set_state_callback(DapStateCallback callback) {
+    dap_state.state_callback = callback;
+}
+
+static void* dap_usb_alloc_string_descr(const char* str) {
+    furi_assert(str);
+
+    uint8_t len = strlen(str);
+    uint8_t wlen = (len + 1) * sizeof(uint16_t);
+    struct usb_string_descriptor* dev_str_desc = malloc(wlen);
+    dev_str_desc->bLength = wlen;
+    dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
+    for(uint8_t i = 0; i < len; i++) {
+        dev_str_desc->wString[i] = str[i];
+    }
+
+    return dev_str_desc;
+}
+
+void dap_common_usb_alloc_name(const char* name) {
+    dev_serial_descr = dap_usb_alloc_string_descr(name);
+}
+
+void dap_common_usb_free_name() {
+    free(dev_serial_descr);
+}
+
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
+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);
+
+FuriHalUsbInterface dap_v2_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,
+    .cfg_descr = (void*)&hid_cfg_desc,
+};
+
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
+    UNUSED(intf);
+    UNUSED(ctx);
+
+    dap_v2_usb_hid.str_manuf_descr = (void*)&dev_manuf_descr;
+    dap_v2_usb_hid.str_prod_descr = (void*)&dev_prod_descr;
+    dap_v2_usb_hid.str_serial_descr = (void*)dev_serial_descr;
+
+    dap_state.usb_dev = dev;
+    if(dap_state.semaphore_v1 == NULL) dap_state.semaphore_v1 = furi_semaphore_alloc(1, 1);
+    if(dap_state.semaphore_v2 == NULL) dap_state.semaphore_v2 = furi_semaphore_alloc(1, 1);
+    if(dap_state.semaphore_cdc == NULL) dap_state.semaphore_cdc = furi_semaphore_alloc(1, 1);
+
+    usb_hid.dev_descr->idVendor = DAP_HID_VID;
+    usb_hid.dev_descr->idProduct = DAP_HID_PID;
+
+    usbd_reg_config(dev, hid_ep_config);
+    usbd_reg_control(dev, hid_control);
+
+    usbd_connect(dev, true);
+}
+
+static bool deinit_flag = false;
+
+void dap_common_wait_for_deinit() {
+    while(!deinit_flag) {
+        furi_delay_ms(50);
+    }
+}
+
+static void hid_deinit(usbd_device* dev) {
+    dap_state.usb_dev = NULL;
+
+    furi_semaphore_free(dap_state.semaphore_v1);
+    furi_semaphore_free(dap_state.semaphore_v2);
+    furi_semaphore_free(dap_state.semaphore_cdc);
+    dap_state.semaphore_v1 = NULL;
+    dap_state.semaphore_v2 = NULL;
+    dap_state.semaphore_cdc = NULL;
+
+    usbd_reg_config(dev, NULL);
+    usbd_reg_control(dev, NULL);
+
+    free(usb_hid.str_manuf_descr);
+    free(usb_hid.str_prod_descr);
+
+    FURI_SW_MEMBARRIER();
+    deinit_flag = true;
+}
+
+static void hid_on_wakeup(usbd_device* dev) {
+    UNUSED(dev);
+    if(!dap_state.connected) {
+        dap_state.connected = true;
+        if(dap_state.state_callback != NULL) {
+            dap_state.state_callback(dap_state.connected, dap_state.context);
+        }
+    }
+}
+
+static void hid_on_suspend(usbd_device* dev) {
+    UNUSED(dev);
+    if(dap_state.connected) {
+        dap_state.connected = false;
+        if(dap_state.state_callback != NULL) {
+            dap_state.state_callback(dap_state.connected, dap_state.context);
+        }
+    }
+}
+
+size_t dap_v1_usb_rx(uint8_t* buffer, size_t size) {
+    size_t len = 0;
+
+    if(dap_state.connected) {
+        len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_OUT, buffer, size);
+    }
+
+    return len;
+}
+
+size_t dap_v2_usb_rx(uint8_t* buffer, size_t size) {
+    size_t len = 0;
+
+    if(dap_state.connected) {
+        len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_BULK_OUT, buffer, size);
+    }
+
+    return len;
+}
+
+size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size) {
+    size_t len = 0;
+
+    if(dap_state.connected) {
+        len = usbd_ep_read(dap_state.usb_dev, HID_EP_OUT | DAP_CDC_EP_RECV, buffer, size);
+    }
+
+    return len;
+}
+
+static void hid_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
+    UNUSED(dev);
+    UNUSED(ep);
+
+    switch(event) {
+    case usbd_evt_eptx:
+        furi_semaphore_release(dap_state.semaphore_v1);
+        furi_console_log_printf("hid tx complete");
+        break;
+    case usbd_evt_eprx:
+        if(dap_state.rx_callback_v1 != NULL) {
+            dap_state.rx_callback_v1(dap_state.context);
+        }
+        break;
+    default:
+        furi_console_log_printf("hid %d, %d", event, ep);
+        break;
+    }
+}
+
+static void hid_txrx_ep_bulk_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
+    UNUSED(dev);
+    UNUSED(ep);
+
+    switch(event) {
+    case usbd_evt_eptx:
+        furi_semaphore_release(dap_state.semaphore_v2);
+        furi_console_log_printf("bulk tx complete");
+        break;
+    case usbd_evt_eprx:
+        if(dap_state.rx_callback_v2 != NULL) {
+            dap_state.rx_callback_v2(dap_state.context);
+        }
+        break;
+    default:
+        furi_console_log_printf("bulk %d, %d", event, ep);
+        break;
+    }
+}
+
+static void cdc_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
+    UNUSED(dev);
+    UNUSED(ep);
+
+    switch(event) {
+    case usbd_evt_eptx:
+        furi_semaphore_release(dap_state.semaphore_cdc);
+        furi_console_log_printf("cdc tx complete");
+        break;
+    case usbd_evt_eprx:
+        if(dap_state.rx_callback_cdc != NULL) {
+            dap_state.rx_callback_cdc(dap_state.context_cdc);
+        }
+        break;
+    default:
+        furi_console_log_printf("cdc %d, %d", event, ep);
+        break;
+    }
+}
+
+static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) {
+    switch(cfg) {
+    case EP_CFG_DECONFIGURE:
+        usbd_ep_deconfig(dev, DAP_HID_EP_OUT);
+        usbd_ep_deconfig(dev, DAP_HID_EP_IN);
+        usbd_ep_deconfig(dev, DAP_HID_EP_BULK_IN);
+        usbd_ep_deconfig(dev, DAP_HID_EP_BULK_OUT);
+        usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_COMM);
+        usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_SEND);
+        usbd_ep_deconfig(dev, HID_EP_OUT | DAP_CDC_EP_RECV);
+        usbd_reg_endpoint(dev, DAP_HID_EP_OUT, NULL);
+        usbd_reg_endpoint(dev, DAP_HID_EP_IN, NULL);
+        usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, NULL);
+        usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, NULL);
+        usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, 0);
+        usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, 0);
+        return usbd_ack;
+    case EP_CFG_CONFIGURE:
+        usbd_ep_config(dev, DAP_HID_EP_IN, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
+        usbd_ep_config(dev, DAP_HID_EP_OUT, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
+        usbd_ep_config(dev, DAP_HID_EP_BULK_OUT, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
+        usbd_ep_config(dev, DAP_HID_EP_BULK_IN, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
+        usbd_ep_config(dev, HID_EP_OUT | DAP_CDC_EP_RECV, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
+        usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_SEND, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
+        usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_COMM, USB_EPTYPE_INTERRUPT, DAP_CDC_EP_SIZE);
+        usbd_reg_endpoint(dev, DAP_HID_EP_IN, hid_txrx_ep_callback);
+        usbd_reg_endpoint(dev, DAP_HID_EP_OUT, hid_txrx_ep_callback);
+        usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, hid_txrx_ep_bulk_callback);
+        usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, hid_txrx_ep_bulk_callback);
+        usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, cdc_txrx_ep_callback);
+        usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, cdc_txrx_ep_callback);
+        // usbd_ep_write(dev, DAP_HID_EP_IN, NULL, 0);
+        // usbd_ep_write(dev, DAP_HID_EP_BULK_IN, NULL, 0);
+        // usbd_ep_write(dev, HID_EP_IN | DAP_CDC_EP_SEND, NULL, 0);
+        return usbd_ack;
+    default:
+        return usbd_fail;
+    }
+}
+
+#ifdef DAP_USB_LOG
+static void dump_request_type(uint8_t type) {
+    switch(type & USB_REQ_DIRECTION) {
+    case USB_REQ_HOSTTODEV:
+        furi_hal_console_puts("host to dev, ");
+        break;
+    case USB_REQ_DEVTOHOST:
+        furi_hal_console_puts("dev to host, ");
+        break;
+    }
+
+    switch(type & USB_REQ_TYPE) {
+    case USB_REQ_STANDARD:
+        furi_hal_console_puts("standard, ");
+        break;
+    case USB_REQ_CLASS:
+        furi_hal_console_puts("class, ");
+        break;
+    case USB_REQ_VENDOR:
+        furi_hal_console_puts("vendor, ");
+        break;
+    }
+
+    switch(type & USB_REQ_RECIPIENT) {
+    case USB_REQ_DEVICE:
+        furi_hal_console_puts("device");
+        break;
+    case USB_REQ_INTERFACE:
+        furi_hal_console_puts("interface");
+        break;
+    case USB_REQ_ENDPOINT:
+        furi_hal_console_puts("endpoint");
+        break;
+    case USB_REQ_OTHER:
+        furi_hal_console_puts("other");
+        break;
+    }
+
+    furi_hal_console_puts("\r\n");
+}
+#else
+#define dump_request_type(...)
+#endif
+
+static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
+    UNUSED(callback);
+
+    dump_request_type(req->bmRequestType);
+    furi_console_log_printf(
+        "control: RT %02x, R %02x, V %04x, I %04x, L %04x",
+        req->bmRequestType,
+        req->bRequest,
+        req->wValue,
+        req->wIndex,
+        req->wLength);
+
+    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE | USB_REQ_DIRECTION) & req->bmRequestType) ==
+       (USB_REQ_STANDARD | USB_REQ_VENDOR | USB_REQ_DEVTOHOST)) {
+        // vendor request, device to host
+        furi_console_log_printf("vendor request");
+        if(USB_WINUSB_VENDOR_CODE == req->bRequest) {
+            // WINUSB request
+            if(USB_WINUSB_DESCRIPTOR_INDEX == req->wIndex) {
+                furi_console_log_printf("WINUSB descriptor");
+                uint16_t length = req->wLength;
+                if(length > sizeof(usb_msos_descriptor_set_t)) {
+                    length = sizeof(usb_msos_descriptor_set_t);
+                }
+
+                dev->status.data_ptr = (uint8_t*)&usb_msos_descriptor_set;
+                dev->status.data_count = length;
+                return usbd_ack;
+            }
+        }
+    }
+
+    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
+       (USB_REQ_STANDARD | USB_REQ_DEVICE)) {
+        // device request
+        if(req->bRequest == USB_STD_GET_DESCRIPTOR) {
+            const uint8_t dtype = req->wValue >> 8;
+            const uint8_t dnumber = req->wValue & 0xFF;
+            // get string descriptor
+            if(USB_DTYPE_STRING == dtype) {
+                if(dnumber == USB_STR_CMSIS_DAP_V1) {
+                    furi_console_log_printf("str CMSIS-DAP v1");
+                    dev->status.data_ptr = (uint8_t*)&dev_dap_v1_descr;
+                    dev->status.data_count = dev_dap_v1_descr.bLength;
+                    return usbd_ack;
+                } else if(dnumber == USB_STR_CMSIS_DAP_V2) {
+                    furi_console_log_printf("str CMSIS-DAP v2");
+                    dev->status.data_ptr = (uint8_t*)&dev_dap_v2_descr;
+                    dev->status.data_count = dev_dap_v2_descr.bLength;
+                    return usbd_ack;
+                } else if(dnumber == USB_STR_COM_PORT) {
+                    furi_console_log_printf("str COM port");
+                    dev->status.data_ptr = (uint8_t*)&dev_com_descr;
+                    dev->status.data_count = dev_com_descr.bLength;
+                    return usbd_ack;
+                }
+            } else if(USB_DTYPE_BINARY_OBJECT_STORE == dtype) {
+                furi_console_log_printf("BOS descriptor");
+                uint16_t length = req->wLength;
+                if(length > sizeof(usb_bos_hierarchy_t)) {
+                    length = sizeof(usb_bos_hierarchy_t);
+                }
+                dev->status.data_ptr = (uint8_t*)&usb_bos_hierarchy;
+                dev->status.data_count = length;
+                return usbd_ack;
+            }
+        }
+    }
+
+    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
+           (USB_REQ_INTERFACE | USB_REQ_CLASS) &&
+       req->wIndex == 0) {
+        // class request
+        switch(req->bRequest) {
+        // get hid descriptor
+        case USB_HID_GETREPORT:
+            furi_console_log_printf("get report");
+            return usbd_fail;
+        // set hid idle
+        case USB_HID_SETIDLE:
+            furi_console_log_printf("set idle");
+            return usbd_ack;
+        default:
+            break;
+        }
+    }
+
+    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
+           (USB_REQ_INTERFACE | USB_REQ_CLASS) &&
+       req->wIndex == 2) {
+        // class request
+        switch(req->bRequest) {
+        // control line state
+        case USB_CDC_SET_CONTROL_LINE_STATE:
+            furi_console_log_printf("set control line state");
+            cdc_ctrl_line_state = req->wValue;
+            if(dap_state.control_line_callback_cdc != NULL) {
+                dap_state.control_line_callback_cdc(cdc_ctrl_line_state, dap_state.context_cdc);
+            }
+            return usbd_ack;
+        // set cdc line coding
+        case USB_CDC_SET_LINE_CODING:
+            furi_console_log_printf("set line coding");
+            memcpy(&cdc_config, req->data, sizeof(cdc_config));
+            if(dap_state.config_callback_cdc != NULL) {
+                dap_state.config_callback_cdc(&cdc_config, dap_state.context_cdc);
+            }
+            return usbd_ack;
+        // get cdc line coding
+        case USB_CDC_GET_LINE_CODING:
+            furi_console_log_printf("get line coding");
+            dev->status.data_ptr = &cdc_config;
+            dev->status.data_count = sizeof(cdc_config);
+            return usbd_ack;
+        default:
+            break;
+        }
+    }
+
+    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
+           (USB_REQ_INTERFACE | USB_REQ_STANDARD) &&
+       req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) {
+        // standard request
+        switch(req->wValue >> 8) {
+        // get hid descriptor
+        case USB_DTYPE_HID:
+            furi_console_log_printf("get hid descriptor");
+            dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.hid);
+            dev->status.data_count = sizeof(hid_cfg_desc.hid);
+            return usbd_ack;
+        // get hid report descriptor
+        case USB_DTYPE_HID_REPORT:
+            furi_console_log_printf("get hid report descriptor");
+            dev->status.data_ptr = (uint8_t*)hid_report_desc;
+            dev->status.data_count = sizeof(hid_report_desc);
+            return usbd_ack;
+        default:
+            break;
+        }
+    }
+
+    return usbd_fail;
+}
\ No newline at end of file
diff --git a/applications/plugins/dap_link/usb/dap_v2_usb.h b/applications/plugins/dap_link/usb/dap_v2_usb.h
new file mode 100644
index 00000000..2a0e8605
--- /dev/null
+++ b/applications/plugins/dap_link/usb/dap_v2_usb.h
@@ -0,0 +1,55 @@
+#pragma once
+#include 
+#include 
+
+extern FuriHalUsbInterface dap_v2_usb_hid;
+
+// receive callback type
+typedef void (*DapRxCallback)(void* context);
+
+typedef void (*DapStateCallback)(bool state, void* context);
+
+/************************************ V1 ***************************************/
+
+int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size);
+
+size_t dap_v1_usb_rx(uint8_t* buffer, size_t size);
+
+void dap_v1_usb_set_rx_callback(DapRxCallback callback);
+
+/************************************ V2 ***************************************/
+
+int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size);
+
+size_t dap_v2_usb_rx(uint8_t* buffer, size_t size);
+
+void dap_v2_usb_set_rx_callback(DapRxCallback callback);
+
+/************************************ CDC **************************************/
+
+typedef void (*DapCDCControlLineCallback)(uint8_t state, void* context);
+typedef void (*DapCDCConfigCallback)(struct usb_cdc_line_coding* config, void* context);
+
+int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size);
+
+size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size);
+
+void dap_cdc_usb_set_rx_callback(DapRxCallback callback);
+
+void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback);
+
+void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback);
+
+void dap_cdc_usb_set_context(void* context);
+
+/*********************************** Common ************************************/
+
+void dap_common_usb_set_context(void* context);
+
+void dap_common_usb_set_state_callback(DapStateCallback callback);
+
+void dap_common_usb_alloc_name(const char* name);
+
+void dap_common_usb_free_name();
+
+void dap_common_wait_for_deinit();
\ No newline at end of file
diff --git a/applications/plugins/dap_link/usb/usb_winusb.h b/applications/plugins/dap_link/usb/usb_winusb.h
new file mode 100644
index 00000000..9c3a172d
--- /dev/null
+++ b/applications/plugins/dap_link/usb/usb_winusb.h
@@ -0,0 +1,143 @@
+#pragma once
+#include 
+
+/*- Definitions -------------------------------------------------------------*/
+
+#define USB_PACK __attribute__((packed))
+
+#define USB_WINUSB_VENDOR_CODE 0x20
+
+#define USB_WINUSB_WINDOWS_VERSION 0x06030000 // Windows 8.1
+
+#define USB_WINUSB_PLATFORM_CAPABILITY_ID                                                         \
+    {                                                                                             \
+        0xdf, 0x60, 0xdd, 0xd8, 0x89, 0x45, 0xc7, 0x4c, 0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, \
+            0x9f                                                                                  \
+    }
+
+enum // WinUSB Microsoft OS 2.0 descriptor request codes
+{
+    USB_WINUSB_DESCRIPTOR_INDEX = 0x07,
+    USB_WINUSB_SET_ALT_ENUMERATION = 0x08,
+};
+
+enum // wDescriptorType
+{
+    USB_WINUSB_SET_HEADER_DESCRIPTOR = 0x00,
+    USB_WINUSB_SUBSET_HEADER_CONFIGURATION = 0x01,
+    USB_WINUSB_SUBSET_HEADER_FUNCTION = 0x02,
+    USB_WINUSB_FEATURE_COMPATBLE_ID = 0x03,
+    USB_WINUSB_FEATURE_REG_PROPERTY = 0x04,
+    USB_WINUSB_FEATURE_MIN_RESUME_TIME = 0x05,
+    USB_WINUSB_FEATURE_MODEL_ID = 0x06,
+    USB_WINUSB_FEATURE_CCGP_DEVICE = 0x07,
+    USB_WINUSB_FEATURE_VENDOR_REVISION = 0x08,
+};
+
+enum // wPropertyDataType
+{
+    USB_WINUSB_PROPERTY_DATA_TYPE_SZ = 1,
+    USB_WINUSB_PROPERTY_DATA_TYPE_EXPAND_SZ = 2,
+    USB_WINUSB_PROPERTY_DATA_TYPE_BINARY = 3,
+    USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_LITTLE_ENDIAN = 4,
+    USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_BIG_ENDIAN = 5,
+    USB_WINUSB_PROPERTY_DATA_TYPE_LINK = 6,
+    USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ = 7,
+};
+
+/*- Types BOS -------------------------------------------------------------------*/
+
+typedef struct USB_PACK {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t wTotalLength;
+    uint8_t bNumDeviceCaps;
+} usb_binary_object_store_descriptor_t;
+
+/*- Types WinUSB -------------------------------------------------------------------*/
+
+typedef struct USB_PACK {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDevCapabilityType;
+    uint8_t bReserved;
+    uint8_t PlatformCapabilityUUID[16];
+    uint32_t dwWindowsVersion;
+    uint16_t wMSOSDescriptorSetTotalLength;
+    uint8_t bMS_VendorCode;
+    uint8_t bAltEnumCode;
+} usb_winusb_capability_descriptor_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint32_t dwWindowsVersion;
+    uint16_t wDescriptorSetTotalLength;
+} usb_winusb_set_header_descriptor_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t bConfigurationValue;
+    uint8_t bReserved;
+    uint16_t wTotalLength;
+} usb_winusb_subset_header_configuration_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t bFirstInterface;
+    uint8_t bReserved;
+    uint16_t wSubsetLength;
+} usb_winusb_subset_header_function_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t CompatibleID[8];
+    uint8_t SubCompatibleID[8];
+} usb_winusb_feature_compatble_id_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint16_t wPropertyDataType;
+    //uint16_t  wPropertyNameLength;
+    //uint8_t   PropertyName[...];
+    //uint16_t  wPropertyDataLength
+    //uint8_t   PropertyData[...];
+} usb_winusb_feature_reg_property_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint16_t wPropertyDataType;
+    uint16_t wPropertyNameLength;
+    uint8_t PropertyName[42];
+    uint16_t wPropertyDataLength;
+    uint8_t PropertyData[80];
+} usb_winusb_feature_reg_property_guids_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t bResumeRecoveryTime;
+    uint8_t bResumeSignalingTime;
+} usb_winusb_feature_min_resume_time_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t ModelID[16];
+} usb_winusb_feature_model_id_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+} usb_winusb_feature_ccgp_device_t;
+
+typedef struct USB_PACK {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint16_t VendorRevision;
+} usb_winusb_feature_vendor_revision_t;
\ No newline at end of file