CMSIS DAP/DAP Link Debugger (#1897)
* Apps: DAP Link * API: furi_hal_console_init Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									42df7aa04a
								
							
						
					
					
						commit
						f56c94922d
					
				
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -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 | ||||
|  | ||||
							
								
								
									
										105
									
								
								applications/plugins/dap_link/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								applications/plugins/dap_link/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -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"` | ||||
|    | ||||
| <details> | ||||
|   <summary>BluePill configuration example</summary> | ||||
|    | ||||
|   ```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", | ||||
|     ], | ||||
| }, | ||||
|   ``` | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary>Flipper Zero configuration example</summary> | ||||
|    | ||||
|   ```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", | ||||
|     ], | ||||
| }, | ||||
|   ``` | ||||
| </details> | ||||
| 
 | ||||
| ### 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. | ||||
| 
 | ||||
| <details> | ||||
|   <summary>Flash BluePill</summary> | ||||
|    | ||||
|   ``` | ||||
| openocd -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c init -c "program build/firmware.bin reset exit 0x8000000" | ||||
|   ``` | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary>Flash Flipper Zero using DAP v2 protocol</summary> | ||||
|    | ||||
|   ``` | ||||
| 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" | ||||
|   ``` | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|   <summary>Reboot connected DAP-Link on Flipper named Oyevoxo</summary> | ||||
|    | ||||
|   ``` | ||||
| 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" | ||||
|   ``` | ||||
| </details> | ||||
| 
 | ||||
| ### 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. | ||||
| 
 | ||||
| <details> | ||||
|   <summary>BluePill platformio.ini example</summary> | ||||
|    | ||||
|   ``` | ||||
| [env:bluepill_f103c8] | ||||
| platform = ststm32 | ||||
| board = bluepill_f103c8 | ||||
| debug_tool = cmsis-dap | ||||
| upload_protocol = cmsis-dap | ||||
|   ``` | ||||
| </details> | ||||
							
								
								
									
										24
									
								
								applications/plugins/dap_link/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								applications/plugins/dap_link/application.fam
									
									
									
									
									
										Normal file
									
								
							| @ -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", | ||||
| ) | ||||
							
								
								
									
										234
									
								
								applications/plugins/dap_link/dap_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								applications/plugins/dap_link/dap_config.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,234 @@ | ||||
| // SPDX-License-Identifier: BSD-3-Clause
 | ||||
| // Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
 | ||||
| 
 | ||||
| #ifndef _DAP_CONFIG_H_ | ||||
| #define _DAP_CONFIG_H_ | ||||
| 
 | ||||
| /*- Includes ----------------------------------------------------------------*/ | ||||
| #include <furi_hal_gpio.h> | ||||
| 
 | ||||
| /*- 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_
 | ||||
							
								
								
									
										521
									
								
								applications/plugins/dap_link/dap_link.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								applications/plugins/dap_link/dap_link.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,521 @@ | ||||
| #include <dap.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal_version.h> | ||||
| #include <furi_hal_gpio.h> | ||||
| #include <furi_hal_uart.h> | ||||
| #include <furi_hal_console.h> | ||||
| #include <furi_hal_resources.h> | ||||
| #include <furi_hal_power.h> | ||||
| #include <stm32wbxx_ll_usart.h> | ||||
| #include <stm32wbxx_ll_lpuart.h> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
							
								
								
									
										55
									
								
								applications/plugins/dap_link/dap_link.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								applications/plugins/dap_link/dap_link.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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); | ||||
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/dap_link/dap_link.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/dap_link/dap_link.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 143 B | 
							
								
								
									
										92
									
								
								applications/plugins/dap_link/gui/dap_gui.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								applications/plugins/dap_link/gui/dap_gui.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										4
									
								
								applications/plugins/dap_link/gui/dap_gui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								applications/plugins/dap_link/gui/dap_gui.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| int32_t dap_gui_thread(void* arg); | ||||
							
								
								
									
										7
									
								
								applications/plugins/dap_link/gui/dap_gui_custom_event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								applications/plugins/dap_link/gui/dap_gui_custom_event.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| typedef enum { | ||||
|     DapAppCustomEventConfig, | ||||
|     DapAppCustomEventHelp, | ||||
|     DapAppCustomEventAbout, | ||||
| } DapAppCustomEvent; | ||||
							
								
								
									
										34
									
								
								applications/plugins/dap_link/gui/dap_gui_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								applications/plugins/dap_link/gui/dap_gui_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <notification/notification_messages.h> | ||||
| #include <gui/modules/variable_item_list.h> | ||||
| #include <gui/modules/widget.h> | ||||
| 
 | ||||
| #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; | ||||
							
								
								
									
										30
									
								
								applications/plugins/dap_link/gui/scenes/config/dap_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								applications/plugins/dap_link/gui/scenes/config/dap_scene.c
									
									
									
									
									
										Normal file
									
								
							| @ -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, | ||||
| }; | ||||
							
								
								
									
										29
									
								
								applications/plugins/dap_link/gui/scenes/config/dap_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								applications/plugins/dap_link/gui/scenes/config/dap_scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| // 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 | ||||
| @ -0,0 +1,4 @@ | ||||
| ADD_SCENE(dap, main, Main) | ||||
| ADD_SCENE(dap, config, Config) | ||||
| ADD_SCENE(dap, help, Help) | ||||
| ADD_SCENE(dap, about, About) | ||||
							
								
								
									
										68
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_about.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_about.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										107
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_config.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										102
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_help.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_help.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										154
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								applications/plugins/dap_link/gui/scenes/dap_scene_main.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										189
									
								
								applications/plugins/dap_link/gui/views/dap_main_view.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								applications/plugins/dap_link/gui/views/dap_main_view.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,189 @@ | ||||
| #include "dap_main_view.h" | ||||
| #include "dap_link_icons.h" | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| // 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); | ||||
| } | ||||
							
								
								
									
										45
									
								
								applications/plugins/dap_link/gui/views/dap_main_view.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								applications/plugins/dap_link/gui/views/dap_main_view.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| #pragma once | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| 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); | ||||
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowDownEmpty_12x18.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowDownEmpty_12x18.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 160 B | 
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowDownFilled_12x18.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowDownFilled_12x18.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 168 B | 
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowUpEmpty_12x18.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowUpEmpty_12x18.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 159 B | 
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowUpFilled_12x18.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/dap_link/icons/ArrowUpFilled_12x18.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 173 B | 
							
								
								
									
										1
									
								
								applications/plugins/dap_link/lib/free-dap
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								applications/plugins/dap_link/lib/free-dap
									
									
									
									
									
										Submodule
									
								
							| @ -0,0 +1 @@ | ||||
| Subproject commit e7752beb5e8a69119af67b70b9179cb3c90f3ac5 | ||||
							
								
								
									
										994
									
								
								applications/plugins/dap_link/usb/dap_v2_usb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										994
									
								
								applications/plugins/dap_link/usb/dap_v2_usb.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,994 @@ | ||||
| #include <furi.h> | ||||
| #include <usb.h> | ||||
| #include <usb_std.h> | ||||
| #include <usb_hid.h> | ||||
| #include <usb_cdc.h> | ||||
| #include <furi_hal_console.h> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
							
								
								
									
										55
									
								
								applications/plugins/dap_link/usb/dap_v2_usb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								applications/plugins/dap_link/usb/dap_v2_usb.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| #pragma once | ||||
| #include <furi_hal_usb.h> | ||||
| #include <usb_cdc.h> | ||||
| 
 | ||||
| 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(); | ||||
							
								
								
									
										143
									
								
								applications/plugins/dap_link/usb/usb_winusb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								applications/plugins/dap_link/usb/usb_winusb.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| /*- 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; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Sergey Gavrilov
						Sergey Gavrilov