From 05e53cac2647236da455952c643917609c56a1a6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 14 Mar 2023 20:25:33 +0300 Subject: [PATCH] Fix merge issues --- .ci_files/anims_ofw.txt | 4 +- ReadMe.md | 4 +- applications/debug/usb_mouse/application.fam | 2 +- applications/external/dap_link/README.md | 105 ++++ applications/external/dap_link/dap_config.h | 234 ++++++++ applications/external/dap_link/dap_link.c | 527 ++++++++++++++++++ applications/external/dap_link/dap_link.h | 55 ++ applications/external/dap_link/gui/dap_gui.c | 92 +++ applications/external/dap_link/gui/dap_gui.h | 4 + .../dap_link/gui/dap_gui_custom_event.h | 7 + .../external/dap_link/gui/dap_gui_i.h | 34 ++ .../gui/scenes/config/dap_scene_config.h | 4 + .../dap_link/gui/scenes/dap_scene_config.c | 107 ++++ .../dap_link/gui/scenes/dap_scene_help.c | 102 ++++ .../dap_link/gui/scenes/dap_scene_main.c | 154 +++++ .../dap_link/gui/views/dap_main_view.c | 189 +++++++ .../dap_link/gui/views/dap_main_view.h | 45 ++ .../dap_link/icons/ActiveConnection_50x64.png | Bin 0 -> 3842 bytes .../dap_link/icons/ArrowUpFilled_12x18.png | Bin 0 -> 173 bytes applications/external/hid_app/application.fam | 8 +- .../external/music_player/application.fam | 2 +- .../external/signal_generator/application.fam | 2 +- 22 files changed, 1670 insertions(+), 11 deletions(-) create mode 100644 applications/external/dap_link/README.md create mode 100644 applications/external/dap_link/dap_config.h create mode 100644 applications/external/dap_link/dap_link.c create mode 100644 applications/external/dap_link/dap_link.h create mode 100644 applications/external/dap_link/gui/dap_gui.c create mode 100644 applications/external/dap_link/gui/dap_gui.h create mode 100644 applications/external/dap_link/gui/dap_gui_custom_event.h create mode 100644 applications/external/dap_link/gui/dap_gui_i.h create mode 100644 applications/external/dap_link/gui/scenes/config/dap_scene_config.h create mode 100644 applications/external/dap_link/gui/scenes/dap_scene_config.c create mode 100644 applications/external/dap_link/gui/scenes/dap_scene_help.c create mode 100644 applications/external/dap_link/gui/scenes/dap_scene_main.c create mode 100644 applications/external/dap_link/gui/views/dap_main_view.c create mode 100644 applications/external/dap_link/gui/views/dap_main_view.h create mode 100644 applications/external/dap_link/icons/ActiveConnection_50x64.png create mode 100644 applications/external/dap_link/icons/ArrowUpFilled_12x18.png diff --git a/.ci_files/anims_ofw.txt b/.ci_files/anims_ofw.txt index 94c61e0ff..a9a6fd241 100644 --- a/.ci_files/anims_ofw.txt +++ b/.ci_files/anims_ofw.txt @@ -134,9 +134,9 @@ Min level: 3 Max level: 3 Weight: 3 -Name: L1_Sleigh_ride_128x64 +Name: L1_Senpai_128x64 Min butthurt: 0 -Max butthurt: 14 +Max butthurt: 5 Min level: 1 Max level: 3 Weight: 4 diff --git a/ReadMe.md b/ReadMe.md index ed31961fa..84b80a1e8 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -211,9 +211,9 @@ Games: ## [- How to use: Unitemp - Temperature sensors reader](https://github.com/quen0n/unitemp-flipperzero#readme) -## [- How to use: [NMEA] GPS](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/plugins/gps_nmea_uart/README.md) +## [- How to use: [NMEA] GPS](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/gps_nmea_uart/README.md) -## [- How to use: i2c Tools](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/plugins/flipper_i2ctools/README.md) +## [- How to use: i2c Tools](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/flipper_i2ctools/README.md) ## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md) diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam index bf555c671..38ba55425 100644 --- a/applications/debug/usb_mouse/application.fam +++ b/applications/debug/usb_mouse/application.fam @@ -7,6 +7,6 @@ App( requires=["gui"], stack_size=1 * 1024, order=60, - fap_icon="../../plugins/mousejacker/mouse_10px.png", + fap_icon="../../external/mousejacker/mouse_10px.png", fap_category="Debug", ) diff --git a/applications/external/dap_link/README.md b/applications/external/dap_link/README.md new file mode 100644 index 000000000..aead0a60a --- /dev/null +++ b/applications/external/dap_link/README.md @@ -0,0 +1,105 @@ +# Flipper Zero as CMSIS DAP/DAP Link +Flipper Zero as a [Free-DAP](https://github.com/ataradov/free-dap) based SWD\JTAG debugger. Free-DAP is a free and open source firmware implementation of the [CMSIS-DAP](https://www.keil.com/pack/doc/CMSIS_Dev/DAP/html/index.html) debugger. + +## Protocols +SWD, JTAG , CMSIS-DAP v1 (18 KiB/s), CMSIS-DAP v2 (46 KiB/s), VCP (USB-UART). + +WinUSB for driverless installation for Windows 8 and above. + +## Usage + +### VSCode + Cortex-Debug + Set `"device": "cmsis-dap"` + +
+ BluePill configuration example + + ```json +{ + "name": "Attach (DAP)", + "cwd": "${workspaceFolder}", + "executable": "./build/firmware.elf", + "request": "attach", + "type": "cortex-debug", + "servertype": "openocd", + "device": "cmsis-dap", + "configFiles": [ + "interface/cmsis-dap.cfg", + "target/stm32f1x.cfg", + ], +}, + ``` +
+ +
+ Flipper Zero configuration example + + ```json +{ + "name": "Attach (DAP)", + "cwd": "${workspaceFolder}", + "executable": "./build/latest/firmware.elf", + "request": "attach", + "type": "cortex-debug", + "servertype": "openocd", + "device": "cmsis-dap", + "svdFile": "./debug/STM32WB55_CM4.svd", + "rtos": "FreeRTOS", + "configFiles": [ + "interface/cmsis-dap.cfg", + "./debug/stm32wbx.cfg", + ], + "postAttachCommands": [ + "source debug/flipperapps.py", + ], +}, + ``` +
+ +### OpenOCD +Use `interface/cmsis-dap.cfg`. You will need OpenOCD v0.11.0. + +Additional commands: +* `cmsis_dap_backend hid` for CMSIS-DAP v1 protocol. +* `cmsis_dap_backend usb_bulk` for CMSIS-DAP v2 protocol. +* `cmsis_dap_serial DAP_Oyevoxo` use DAP-Link running on Flipper named `Oyevoxo`. +* `cmsis-dap cmd 81` - reboot connected DAP-Link. + +
+ Flash BluePill + + ``` +openocd -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c init -c "program build/firmware.bin reset exit 0x8000000" + ``` +
+ +
+ Flash Flipper Zero using DAP v2 protocol + + ``` +openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_backend usb_bulk" -f debug/stm32wbx.cfg -c init -c "program build/latest/firmware.bin reset exit 0x8000000" + ``` +
+ +
+ Reboot connected DAP-Link on Flipper named Oyevoxo + + ``` +openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_serial DAP_Oyevoxo" -c "transport select swd" -c "adapter speed 4000000" -c init -c "cmsis-dap cmd 81" -c "exit" + ``` +
+ +### PlatformIO +Use `debug_tool = cmsis-dap` and `upload_protocol = cmsis-dap`. [Documentation](https://docs.platformio.org/en/latest/plus/debug-tools/cmsis-dap.html#debugging-tool-cmsis-dap). Remember that Windows 8 and above do not require drivers. + +
+ BluePill platformio.ini example + + ``` +[env:bluepill_f103c8] +platform = ststm32 +board = bluepill_f103c8 +debug_tool = cmsis-dap +upload_protocol = cmsis-dap + ``` +
diff --git a/applications/external/dap_link/dap_config.h b/applications/external/dap_link/dap_config.h new file mode 100644 index 000000000..88b90bd34 --- /dev/null +++ b/applications/external/dap_link/dap_config.h @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2022, Alex Taradov . All rights reserved. + +#ifndef _DAP_CONFIG_H_ +#define _DAP_CONFIG_H_ + +/*- Includes ----------------------------------------------------------------*/ +#include + +/*- Definitions -------------------------------------------------------------*/ +#define DAP_CONFIG_ENABLE_JTAG + +#define DAP_CONFIG_DEFAULT_PORT DAP_PORT_SWD +#define DAP_CONFIG_DEFAULT_CLOCK 4200000 // Hz + +#define DAP_CONFIG_PACKET_SIZE 64 +#define DAP_CONFIG_PACKET_COUNT 1 + +#define DAP_CONFIG_JTAG_DEV_COUNT 8 + +// DAP_CONFIG_PRODUCT_STR must contain "CMSIS-DAP" to be compatible with the standard +#define DAP_CONFIG_VENDOR_STR "Flipper Zero" +#define DAP_CONFIG_PRODUCT_STR "Generic CMSIS-DAP Adapter" +#define DAP_CONFIG_SER_NUM_STR usb_serial_number +#define DAP_CONFIG_CMSIS_DAP_VER_STR "2.0.0" + +#define DAP_CONFIG_RESET_TARGET_FN dap_app_target_reset +#define DAP_CONFIG_VENDOR_FN dap_app_vendor_cmd + +// Attribute to use for performance-critical functions +#define DAP_CONFIG_PERFORMANCE_ATTR + +// A value at which dap_clock_test() produces 1 kHz output on the SWCLK pin +// #define DAP_CONFIG_DELAY_CONSTANT 19000 +#define DAP_CONFIG_DELAY_CONSTANT 6290 + +// A threshold for switching to fast clock (no added delays) +// This is the frequency produced by dap_clock_test(1) on the SWCLK pin +#define DAP_CONFIG_FAST_CLOCK 2400000 // Hz + +/*- Prototypes --------------------------------------------------------------*/ +extern char usb_serial_number[16]; + +/*- Implementations ---------------------------------------------------------*/ +extern GpioPin flipper_dap_swclk_pin; +extern GpioPin flipper_dap_swdio_pin; +extern GpioPin flipper_dap_reset_pin; +extern GpioPin flipper_dap_tdo_pin; +extern GpioPin flipper_dap_tdi_pin; + +extern void dap_app_vendor_cmd(uint8_t cmd); +extern void dap_app_target_reset(); +extern void dap_app_disconnect(); +extern void dap_app_connect_swd(); +extern void dap_app_connect_jtag(); + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWCLK_TCK_write(int value) { + furi_hal_gpio_write(&flipper_dap_swclk_pin, value); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWDIO_TMS_write(int value) { + furi_hal_gpio_write(&flipper_dap_swdio_pin, value); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_TDI_write(int value) { +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_write(&flipper_dap_tdi_pin, value); +#else + (void)value; +#endif +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_TDO_write(int value) { +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_write(&flipper_dap_tdo_pin, value); +#else + (void)value; +#endif +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_nTRST_write(int value) { + (void)value; +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_nRESET_write(int value) { + furi_hal_gpio_write(&flipper_dap_reset_pin, value); +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_SWCLK_TCK_read(void) { + return furi_hal_gpio_read(&flipper_dap_swclk_pin); +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_SWDIO_TMS_read(void) { + return furi_hal_gpio_read(&flipper_dap_swdio_pin); +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_TDO_read(void) { +#ifdef DAP_CONFIG_ENABLE_JTAG + return furi_hal_gpio_read(&flipper_dap_tdo_pin); +#else + return 0; +#endif +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_TDI_read(void) { +#ifdef DAP_CONFIG_ENABLE_JTAG + return furi_hal_gpio_read(&flipper_dap_tdi_pin); +#else + return 0; +#endif +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_nTRST_read(void) { + return 0; +} + +//----------------------------------------------------------------------------- +static inline int DAP_CONFIG_nRESET_read(void) { + return furi_hal_gpio_read(&flipper_dap_reset_pin); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWCLK_TCK_set(void) { + LL_GPIO_SetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWCLK_TCK_clr(void) { + LL_GPIO_ResetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWDIO_TMS_in(void) { + LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_INPUT); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SWDIO_TMS_out(void) { + LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_OUTPUT); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_SETUP(void) { + furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); +#endif +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_DISCONNECT(void) { + furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); +#endif + dap_app_disconnect(); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_CONNECT_SWD(void) { + furi_hal_gpio_init( + &flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_swdio_pin, true); + + furi_hal_gpio_init( + &flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_swclk_pin, true); + + furi_hal_gpio_init( + &flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_reset_pin, true); + +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); +#endif + dap_app_connect_swd(); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_CONNECT_JTAG(void) { + furi_hal_gpio_init( + &flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_swdio_pin, true); + + furi_hal_gpio_init( + &flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_swclk_pin, true); + + furi_hal_gpio_init( + &flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_reset_pin, true); + +#ifdef DAP_CONFIG_ENABLE_JTAG + furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); + + furi_hal_gpio_init( + &flipper_dap_tdi_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&flipper_dap_tdi_pin, true); +#endif + dap_app_connect_jtag(); +} + +//----------------------------------------------------------------------------- +static inline void DAP_CONFIG_LED(int index, int state) { + (void)index; + (void)state; +} + +//----------------------------------------------------------------------------- +__attribute__((always_inline)) static inline void DAP_CONFIG_DELAY(uint32_t cycles) { + asm volatile("1: subs %[cycles], %[cycles], #1 \n" + " bne 1b \n" + : [cycles] "+l"(cycles)); +} + +#endif // _DAP_CONFIG_H_ diff --git a/applications/external/dap_link/dap_link.c b/applications/external/dap_link/dap_link.c new file mode 100644 index 000000000..eafb435e7 --- /dev/null +++ b/applications/external/dap_link/dap_link.c @@ -0,0 +1,527 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dap_link.h" +#include "dap_config.h" +#include "gui/dap_gui.h" +#include "usb/dap_v2_usb.h" +#include +#include "dap_link_icons.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_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 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); + + if(furi_hal_usb_is_locked()) { + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Connection\nis active!", 3, 2, AlignLeft, AlignTop); + dialog_message_set_text( + message, + "Disconnect from\nPC or phone to\nuse this function.", + 3, + 30, + AlignLeft, + AlignTop); + dialog_message_set_icon(message, &I_ActiveConnection_50x64, 78, 0); + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + return -1; + } + + // alloc app + DapApp* app = dap_app_alloc(); + app_handle = app; + + furi_thread_start(app->dap_thread); + furi_thread_start(app->cdc_thread); + furi_thread_start(app->gui_thread); + + // wait until gui thread is finished + furi_thread_join(app->gui_thread); + + // send stop event to threads + dap_thread_send_stop(app->dap_thread); + dap_thread_send_stop(app->cdc_thread); + + // wait for threads to stop + furi_thread_join(app->dap_thread); + furi_thread_join(app->cdc_thread); + + // free app + dap_app_free(app); + + return 0; +} \ No newline at end of file diff --git a/applications/external/dap_link/dap_link.h b/applications/external/dap_link/dap_link.h new file mode 100644 index 000000000..d51726c45 --- /dev/null +++ b/applications/external/dap_link/dap_link.h @@ -0,0 +1,55 @@ +#pragma once +#include + +typedef enum { + DapModeDisconnected, + DapModeSWD, + DapModeJTAG, +} DapMode; + +typedef enum { + DapVersionUnknown, + DapVersionV1, + DapVersionV2, +} DapVersion; + +typedef struct { + bool usb_connected; + DapMode dap_mode; + DapVersion dap_version; + uint32_t dap_counter; + uint32_t cdc_baudrate; + uint32_t cdc_tx_counter; + uint32_t cdc_rx_counter; +} DapState; + +typedef enum { + DapSwdPinsPA7PA6, // Pins 2, 3 + DapSwdPinsPA14PA13, // Pins 10, 12 +} DapSwdPins; + +typedef enum { + DapUartTypeUSART1, // Pins 13, 14 + DapUartTypeLPUART1, // Pins 15, 16 +} DapUartType; + +typedef enum { + DapUartTXRXNormal, + DapUartTXRXSwap, +} DapUartTXRX; + +typedef struct { + DapSwdPins swd_pins; + DapUartType uart_pins; + DapUartTXRX uart_swap; +} DapConfig; + +typedef struct DapApp DapApp; + +void dap_app_get_state(DapApp* app, DapState* state); + +const char* dap_app_get_serial(DapApp* app); + +void dap_app_set_config(DapApp* app, DapConfig* config); + +DapConfig* dap_app_get_config(DapApp* app); \ No newline at end of file diff --git a/applications/external/dap_link/gui/dap_gui.c b/applications/external/dap_link/gui/dap_gui.c new file mode 100644 index 000000000..4dd986153 --- /dev/null +++ b/applications/external/dap_link/gui/dap_gui.c @@ -0,0 +1,92 @@ +#include "dap_gui.h" +#include "dap_gui_i.h" + +#define DAP_GUI_TICK 250 + +static bool dap_gui_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + DapGuiApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool dap_gui_back_event_callback(void* context) { + furi_assert(context); + DapGuiApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void dap_gui_tick_event_callback(void* context) { + furi_assert(context); + DapGuiApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +DapGuiApp* dap_gui_alloc() { + DapGuiApp* app = malloc(sizeof(DapGuiApp)); + app->gui = furi_record_open(RECORD_GUI); + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&dap_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + view_dispatcher_set_custom_event_callback(app->view_dispatcher, dap_gui_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, dap_gui_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, dap_gui_tick_event_callback, DAP_GUI_TICK); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + app->var_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + DapGuiAppViewVarItemList, + variable_item_list_get_view(app->var_item_list)); + + app->main_view = dap_main_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, DapGuiAppViewMainView, dap_main_view_get_view(app->main_view)); + + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, DapGuiAppViewWidget, widget_get_view(app->widget)); + + scene_manager_next_scene(app->scene_manager, DapSceneMain); + + return app; +} + +void dap_gui_free(DapGuiApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewVarItemList); + variable_item_list_free(app->var_item_list); + + view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewMainView); + dap_main_view_free(app->main_view); + + view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewWidget); + widget_free(app->widget); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // Close records + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + + free(app); +} + +int32_t dap_gui_thread(void* arg) { + DapGuiApp* app = dap_gui_alloc(); + app->dap_app = arg; + + notification_message_block(app->notifications, &sequence_display_backlight_enforce_on); + view_dispatcher_run(app->view_dispatcher); + notification_message_block(app->notifications, &sequence_display_backlight_enforce_auto); + + dap_gui_free(app); + return 0; +} \ No newline at end of file diff --git a/applications/external/dap_link/gui/dap_gui.h b/applications/external/dap_link/gui/dap_gui.h new file mode 100644 index 000000000..3d8e6bdf9 --- /dev/null +++ b/applications/external/dap_link/gui/dap_gui.h @@ -0,0 +1,4 @@ +#pragma once +#include + +int32_t dap_gui_thread(void* arg); \ No newline at end of file diff --git a/applications/external/dap_link/gui/dap_gui_custom_event.h b/applications/external/dap_link/gui/dap_gui_custom_event.h new file mode 100644 index 000000000..8b127c9d4 --- /dev/null +++ b/applications/external/dap_link/gui/dap_gui_custom_event.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + DapAppCustomEventConfig, + DapAppCustomEventHelp, + DapAppCustomEventAbout, +} DapAppCustomEvent; diff --git a/applications/external/dap_link/gui/dap_gui_i.h b/applications/external/dap_link/gui/dap_gui_i.h new file mode 100644 index 000000000..59411e78c --- /dev/null +++ b/applications/external/dap_link/gui/dap_gui_i.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "dap_gui.h" +#include "../dap_link.h" +#include "scenes/config/dap_scene.h" +#include "dap_gui_custom_event.h" +#include "views/dap_main_view.h" + +typedef struct { + DapApp* dap_app; + + Gui* gui; + NotificationApp* notifications; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + + VariableItemList* var_item_list; + DapMainView* main_view; + Widget* widget; +} DapGuiApp; + +typedef enum { + DapGuiAppViewVarItemList, + DapGuiAppViewMainView, + DapGuiAppViewWidget, +} DapGuiAppView; diff --git a/applications/external/dap_link/gui/scenes/config/dap_scene_config.h b/applications/external/dap_link/gui/scenes/config/dap_scene_config.h new file mode 100644 index 000000000..8957aca06 --- /dev/null +++ b/applications/external/dap_link/gui/scenes/config/dap_scene_config.h @@ -0,0 +1,4 @@ +ADD_SCENE(dap, main, Main) +ADD_SCENE(dap, config, Config) +ADD_SCENE(dap, help, Help) +ADD_SCENE(dap, about, About) \ No newline at end of file diff --git a/applications/external/dap_link/gui/scenes/dap_scene_config.c b/applications/external/dap_link/gui/scenes/dap_scene_config.c new file mode 100644 index 000000000..48d5fedcd --- /dev/null +++ b/applications/external/dap_link/gui/scenes/dap_scene_config.c @@ -0,0 +1,107 @@ +#include "../dap_gui_i.h" + +static const char* swd_pins[] = {[DapSwdPinsPA7PA6] = "2,3", [DapSwdPinsPA14PA13] = "10,12"}; +static const char* uart_pins[] = {[DapUartTypeUSART1] = "13,14", [DapUartTypeLPUART1] = "15,16"}; +static const char* uart_swap[] = {[DapUartTXRXNormal] = "No", [DapUartTXRXSwap] = "Yes"}; + +static void swd_pins_cb(VariableItem* item) { + DapGuiApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, swd_pins[index]); + + DapConfig* config = dap_app_get_config(app->dap_app); + config->swd_pins = index; + dap_app_set_config(app->dap_app, config); +} + +static void uart_pins_cb(VariableItem* item) { + DapGuiApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, uart_pins[index]); + + DapConfig* config = dap_app_get_config(app->dap_app); + config->uart_pins = index; + dap_app_set_config(app->dap_app, config); +} + +static void uart_swap_cb(VariableItem* item) { + DapGuiApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, uart_swap[index]); + + DapConfig* config = dap_app_get_config(app->dap_app); + config->uart_swap = index; + dap_app_set_config(app->dap_app, config); +} + +static void ok_cb(void* context, uint32_t index) { + DapGuiApp* app = context; + switch(index) { + case 3: + view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventHelp); + break; + case 4: + view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventAbout); + break; + default: + break; + } +} + +void dap_scene_config_on_enter(void* context) { + DapGuiApp* app = context; + VariableItemList* var_item_list = app->var_item_list; + VariableItem* item; + DapConfig* config = dap_app_get_config(app->dap_app); + + item = variable_item_list_add( + var_item_list, "SWC SWD Pins", COUNT_OF(swd_pins), swd_pins_cb, app); + variable_item_set_current_value_index(item, config->swd_pins); + variable_item_set_current_value_text(item, swd_pins[config->swd_pins]); + + item = + variable_item_list_add(var_item_list, "UART Pins", COUNT_OF(uart_pins), uart_pins_cb, app); + variable_item_set_current_value_index(item, config->uart_pins); + variable_item_set_current_value_text(item, uart_pins[config->uart_pins]); + + item = variable_item_list_add( + var_item_list, "Swap TX RX", COUNT_OF(uart_swap), uart_swap_cb, app); + variable_item_set_current_value_index(item, config->uart_swap); + variable_item_set_current_value_text(item, uart_swap[config->uart_swap]); + + variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL); + variable_item_list_add(var_item_list, "About", 0, NULL, NULL); + + variable_item_list_set_selected_item( + var_item_list, scene_manager_get_scene_state(app->scene_manager, DapSceneConfig)); + + variable_item_list_set_enter_callback(var_item_list, ok_cb, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewVarItemList); +} + +bool dap_scene_config_on_event(void* context, SceneManagerEvent event) { + DapGuiApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DapAppCustomEventHelp) { + scene_manager_next_scene(app->scene_manager, DapSceneHelp); + return true; + } else if(event.event == DapAppCustomEventAbout) { + scene_manager_next_scene(app->scene_manager, DapSceneAbout); + return true; + } + } + return false; +} + +void dap_scene_config_on_exit(void* context) { + DapGuiApp* app = context; + scene_manager_set_scene_state( + app->scene_manager, + DapSceneConfig, + variable_item_list_get_selected_item_index(app->var_item_list)); + variable_item_list_reset(app->var_item_list); +} \ No newline at end of file diff --git a/applications/external/dap_link/gui/scenes/dap_scene_help.c b/applications/external/dap_link/gui/scenes/dap_scene_help.c new file mode 100644 index 000000000..d8d70e7ff --- /dev/null +++ b/applications/external/dap_link/gui/scenes/dap_scene_help.c @@ -0,0 +1,102 @@ +#include "../dap_gui_i.h" + +void dap_scene_help_on_enter(void* context) { + DapGuiApp* app = context; + DapConfig* config = dap_app_get_config(app->dap_app); + FuriString* string = furi_string_alloc(); + + furi_string_cat(string, "CMSIS DAP/DAP Link v2\r\n"); + furi_string_cat_printf(string, "Serial: %s\r\n", dap_app_get_serial(app->dap_app)); + furi_string_cat( + string, + "Pinout:\r\n" + "\e#SWD:\r\n"); + + switch(config->swd_pins) { + case DapSwdPinsPA7PA6: + furi_string_cat( + string, + " SWC: 2 [A7]\r\n" + " SWD: 3 [A6]\r\n"); + break; + case DapSwdPinsPA14PA13: + furi_string_cat( + string, + " SWC: 10 [SWC]\r\n" + " SWD: 12 [SIO]\r\n"); + break; + default: + break; + } + + furi_string_cat(string, "\e#JTAG:\r\n"); + switch(config->swd_pins) { + case DapSwdPinsPA7PA6: + furi_string_cat( + string, + " TCK: 2 [A7]\r\n" + " TMS: 3 [A6]\r\n" + " RST: 4 [A4]\r\n" + " TDO: 5 [B3]\r\n" + " TDI: 6 [B2]\r\n"); + break; + case DapSwdPinsPA14PA13: + furi_string_cat( + string, + " RST: 4 [A4]\r\n" + " TDO: 5 [B3]\r\n" + " TDI: 6 [B2]\r\n" + " TCK: 10 [SWC]\r\n" + " TMS: 12 [SIO]\r\n"); + break; + default: + break; + } + + furi_string_cat(string, "\e#UART:\r\n"); + switch(config->uart_pins) { + case DapUartTypeUSART1: + if(config->uart_swap == DapUartTXRXNormal) { + furi_string_cat( + string, + " TX: 13 [TX]\r\n" + " RX: 14 [RX]\r\n"); + } else { + furi_string_cat( + string, + " RX: 13 [TX]\r\n" + " TX: 14 [RX]\r\n"); + } + break; + case DapUartTypeLPUART1: + if(config->uart_swap == DapUartTXRXNormal) { + furi_string_cat( + string, + " TX: 15 [C1]\r\n" + " RX: 16 [C0]\r\n"); + } else { + furi_string_cat( + string, + " RX: 15 [C1]\r\n" + " TX: 16 [C0]\r\n"); + } + break; + default: + break; + } + + widget_add_text_scroll_element(app->widget, 0, 0, 128, 64, furi_string_get_cstr(string)); + furi_string_free(string); + view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewWidget); +} + +bool dap_scene_help_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void dap_scene_help_on_exit(void* context) { + DapGuiApp* app = context; + widget_reset(app->widget); +} \ No newline at end of file diff --git a/applications/external/dap_link/gui/scenes/dap_scene_main.c b/applications/external/dap_link/gui/scenes/dap_scene_main.c new file mode 100644 index 000000000..8c19bd6a5 --- /dev/null +++ b/applications/external/dap_link/gui/scenes/dap_scene_main.c @@ -0,0 +1,154 @@ +#include "../dap_gui_i.h" +#include "../../dap_link.h" + +typedef struct { + DapState dap_state; + bool dap_active; + bool tx_active; + bool rx_active; +} DapSceneMainState; + +static bool process_dap_state(DapGuiApp* app) { + DapSceneMainState* state = + (DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain); + if(state == NULL) return true; + + DapState* prev_state = &state->dap_state; + DapState next_state; + dap_app_get_state(app->dap_app, &next_state); + bool need_to_update = false; + + if(prev_state->dap_mode != next_state.dap_mode) { + switch(next_state.dap_mode) { + case DapModeDisconnected: + dap_main_view_set_mode(app->main_view, DapMainViewModeDisconnected); + notification_message(app->notifications, &sequence_blink_stop); + break; + case DapModeSWD: + dap_main_view_set_mode(app->main_view, DapMainViewModeSWD); + notification_message(app->notifications, &sequence_blink_start_blue); + break; + case DapModeJTAG: + dap_main_view_set_mode(app->main_view, DapMainViewModeJTAG); + notification_message(app->notifications, &sequence_blink_start_magenta); + break; + } + need_to_update = true; + } + + if(prev_state->dap_version != next_state.dap_version) { + switch(next_state.dap_version) { + case DapVersionUnknown: + dap_main_view_set_version(app->main_view, DapMainViewVersionUnknown); + break; + case DapVersionV1: + dap_main_view_set_version(app->main_view, DapMainViewVersionV1); + break; + case DapVersionV2: + dap_main_view_set_version(app->main_view, DapMainViewVersionV2); + break; + } + need_to_update = true; + } + + if(prev_state->usb_connected != next_state.usb_connected) { + dap_main_view_set_usb_connected(app->main_view, next_state.usb_connected); + need_to_update = true; + } + + if(prev_state->dap_counter != next_state.dap_counter) { + if(!state->dap_active) { + state->dap_active = true; + dap_main_view_set_dap(app->main_view, state->dap_active); + need_to_update = true; + } + } else { + if(state->dap_active) { + state->dap_active = false; + dap_main_view_set_dap(app->main_view, state->dap_active); + need_to_update = true; + } + } + + if(prev_state->cdc_baudrate != next_state.cdc_baudrate) { + dap_main_view_set_baudrate(app->main_view, next_state.cdc_baudrate); + need_to_update = true; + } + + if(prev_state->cdc_tx_counter != next_state.cdc_tx_counter) { + if(!state->tx_active) { + state->tx_active = true; + dap_main_view_set_tx(app->main_view, state->tx_active); + need_to_update = true; + notification_message(app->notifications, &sequence_blink_start_red); + } + } else { + if(state->tx_active) { + state->tx_active = false; + dap_main_view_set_tx(app->main_view, state->tx_active); + need_to_update = true; + notification_message(app->notifications, &sequence_blink_stop); + } + } + + if(prev_state->cdc_rx_counter != next_state.cdc_rx_counter) { + if(!state->rx_active) { + state->rx_active = true; + dap_main_view_set_rx(app->main_view, state->rx_active); + need_to_update = true; + notification_message(app->notifications, &sequence_blink_start_green); + } + } else { + if(state->rx_active) { + state->rx_active = false; + dap_main_view_set_rx(app->main_view, state->rx_active); + need_to_update = true; + notification_message(app->notifications, &sequence_blink_stop); + } + } + + if(need_to_update) { + dap_main_view_update(app->main_view); + } + + *prev_state = next_state; + return true; +} + +static void dap_scene_main_on_left(void* context) { + DapGuiApp* app = (DapGuiApp*)context; + view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventConfig); +} + +void dap_scene_main_on_enter(void* context) { + DapGuiApp* app = context; + DapSceneMainState* state = malloc(sizeof(DapSceneMainState)); + dap_main_view_set_left_callback(app->main_view, dap_scene_main_on_left, app); + view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewMainView); + scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)state); +} + +bool dap_scene_main_on_event(void* context, SceneManagerEvent event) { + DapGuiApp* app = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DapAppCustomEventConfig) { + scene_manager_next_scene(app->scene_manager, DapSceneConfig); + return true; + } + } else if(event.type == SceneManagerEventTypeTick) { + return process_dap_state(app); + } + + return false; +} + +void dap_scene_main_on_exit(void* context) { + DapGuiApp* app = context; + DapSceneMainState* state = + (DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain); + scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)NULL); + FURI_SW_MEMBARRIER(); + free(state); + notification_message(app->notifications, &sequence_blink_stop); +} \ No newline at end of file diff --git a/applications/external/dap_link/gui/views/dap_main_view.c b/applications/external/dap_link/gui/views/dap_main_view.c new file mode 100644 index 000000000..c5c8f9dff --- /dev/null +++ b/applications/external/dap_link/gui/views/dap_main_view.c @@ -0,0 +1,189 @@ +#include "dap_main_view.h" +#include "dap_link_icons.h" +#include + +// extern const Icon I_ArrowDownEmpty_12x18; +// extern const Icon I_ArrowDownFilled_12x18; +// extern const Icon I_ArrowUpEmpty_12x18; +// extern const Icon I_ArrowUpFilled_12x18; + +struct DapMainView { + View* view; + DapMainViewButtonCallback cb_left; + void* cb_context; +}; + +typedef struct { + DapMainViewMode mode; + DapMainViewVersion version; + bool usb_connected; + uint32_t baudrate; + bool dap_active; + bool tx_active; + bool rx_active; +} DapMainViewModel; + +static void dap_main_view_draw_callback(Canvas* canvas, void* _model) { + DapMainViewModel* model = _model; + UNUSED(model); + canvas_clear(canvas); + elements_button_left(canvas, "Config"); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 0, 0, 127, 11); + canvas_set_color(canvas, ColorWhite); + + const char* header_string; + if(model->usb_connected) { + if(model->version == DapMainViewVersionV1) { + header_string = "DAP Link V1 Connected"; + } else if(model->version == DapMainViewVersionV2) { + header_string = "DAP Link V2 Connected"; + } else { + header_string = "DAP Link Connected"; + } + } else { + header_string = "DAP Link"; + } + + canvas_draw_str_aligned(canvas, 64, 9, AlignCenter, AlignBottom, header_string); + + canvas_set_color(canvas, ColorBlack); + if(model->dap_active) { + canvas_draw_icon(canvas, 14, 16, &I_ArrowUpFilled_12x18); + canvas_draw_icon(canvas, 28, 16, &I_ArrowDownFilled_12x18); + } else { + canvas_draw_icon(canvas, 14, 16, &I_ArrowUpEmpty_12x18); + canvas_draw_icon(canvas, 28, 16, &I_ArrowDownEmpty_12x18); + } + + switch(model->mode) { + case DapMainViewModeDisconnected: + canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "----"); + break; + case DapMainViewModeSWD: + canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "SWD"); + break; + case DapMainViewModeJTAG: + canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "JTAG"); + break; + } + + if(model->tx_active) { + canvas_draw_icon(canvas, 87, 16, &I_ArrowUpFilled_12x18); + } else { + canvas_draw_icon(canvas, 87, 16, &I_ArrowUpEmpty_12x18); + } + + if(model->rx_active) { + canvas_draw_icon(canvas, 101, 16, &I_ArrowDownFilled_12x18); + } else { + canvas_draw_icon(canvas, 101, 16, &I_ArrowDownEmpty_12x18); + } + + canvas_draw_str_aligned(canvas, 100, 38, AlignCenter, AlignTop, "UART"); + + canvas_draw_line(canvas, 44, 52, 123, 52); + if(model->baudrate == 0) { + canvas_draw_str(canvas, 45, 62, "Baud: ????"); + } else { + char baudrate_str[18]; + snprintf(baudrate_str, 18, "Baud: %lu", model->baudrate); + canvas_draw_str(canvas, 45, 62, baudrate_str); + } +} + +static bool dap_main_view_input_callback(InputEvent* event, void* context) { + furi_assert(context); + DapMainView* dap_main_view = context; + bool consumed = false; + + if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft) { + if(dap_main_view->cb_left) { + dap_main_view->cb_left(dap_main_view->cb_context); + } + consumed = true; + } + } + + return consumed; +} + +DapMainView* dap_main_view_alloc() { + DapMainView* dap_main_view = malloc(sizeof(DapMainView)); + + dap_main_view->view = view_alloc(); + view_allocate_model(dap_main_view->view, ViewModelTypeLocking, sizeof(DapMainViewModel)); + view_set_context(dap_main_view->view, dap_main_view); + view_set_draw_callback(dap_main_view->view, dap_main_view_draw_callback); + view_set_input_callback(dap_main_view->view, dap_main_view_input_callback); + return dap_main_view; +} + +void dap_main_view_free(DapMainView* dap_main_view) { + view_free(dap_main_view->view); + free(dap_main_view); +} + +View* dap_main_view_get_view(DapMainView* dap_main_view) { + return dap_main_view->view; +} + +void dap_main_view_set_left_callback( + DapMainView* dap_main_view, + DapMainViewButtonCallback callback, + void* context) { + with_view_model( + dap_main_view->view, + DapMainViewModel * model, + { + UNUSED(model); + dap_main_view->cb_left = callback; + dap_main_view->cb_context = context; + }, + true); +} + +void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->mode = mode; }, false); +} + +void dap_main_view_set_dap(DapMainView* dap_main_view, bool active) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->dap_active = active; }, false); +} + +void dap_main_view_set_tx(DapMainView* dap_main_view, bool active) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->tx_active = active; }, false); +} + +void dap_main_view_set_rx(DapMainView* dap_main_view, bool active) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->rx_active = active; }, false); +} + +void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->baudrate = baudrate; }, false); +} + +void dap_main_view_update(DapMainView* dap_main_view) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { UNUSED(model); }, true); +} + +void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version) { + with_view_model( + dap_main_view->view, DapMainViewModel * model, { model->version = version; }, false); +} + +void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected) { + with_view_model( + dap_main_view->view, + DapMainViewModel * model, + { model->usb_connected = connected; }, + false); +} \ No newline at end of file diff --git a/applications/external/dap_link/gui/views/dap_main_view.h b/applications/external/dap_link/gui/views/dap_main_view.h new file mode 100644 index 000000000..1fd900452 --- /dev/null +++ b/applications/external/dap_link/gui/views/dap_main_view.h @@ -0,0 +1,45 @@ +#pragma once +#include + +typedef struct DapMainView DapMainView; + +typedef void (*DapMainViewButtonCallback)(void* context); + +typedef enum { + DapMainViewVersionUnknown, + DapMainViewVersionV1, + DapMainViewVersionV2, +} DapMainViewVersion; + +typedef enum { + DapMainViewModeDisconnected, + DapMainViewModeSWD, + DapMainViewModeJTAG, +} DapMainViewMode; + +DapMainView* dap_main_view_alloc(); + +void dap_main_view_free(DapMainView* dap_main_view); + +View* dap_main_view_get_view(DapMainView* dap_main_view); + +void dap_main_view_set_left_callback( + DapMainView* dap_main_view, + DapMainViewButtonCallback callback, + void* context); + +void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode); + +void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version); + +void dap_main_view_set_dap(DapMainView* dap_main_view, bool active); + +void dap_main_view_set_tx(DapMainView* dap_main_view, bool active); + +void dap_main_view_set_rx(DapMainView* dap_main_view, bool active); + +void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected); + +void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate); + +void dap_main_view_update(DapMainView* dap_main_view); \ No newline at end of file diff --git a/applications/external/dap_link/icons/ActiveConnection_50x64.png b/applications/external/dap_link/icons/ActiveConnection_50x64.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7686dddf8a33b724c7528ed36435514b7518b2 GIT binary patch literal 3842 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 WwRe~lwXYaxC4;A{pUXO@geCw-ib4GV literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/application.fam b/applications/external/hid_app/application.fam index a9d8305dd..e96e956d8 100644 --- a/applications/external/hid_app/application.fam +++ b/applications/external/hid_app/application.fam @@ -1,10 +1,10 @@ App( appid="hid_usb", - name="Remote", + name="USB Keyboard & Mouse", apptype=FlipperAppType.EXTERNAL, entry_point="hid_usb_app", stack_size=1 * 1024, - fap_category="USB", + fap_category="Misc", fap_icon="hid_usb_10px.png", fap_icon_assets="assets", fap_icon_assets_symbol="hid", @@ -13,11 +13,11 @@ App( App( appid="hid_ble", - name="Remote", + name="Bluetooth Remote", apptype=FlipperAppType.EXTERNAL, entry_point="hid_ble_app", stack_size=1 * 1024, - fap_category="Bluetooth", + fap_category="Misc", fap_icon="hid_ble_10px.png", fap_icon_assets="assets", fap_icon_assets_symbol="hid", diff --git a/applications/external/music_player/application.fam b/applications/external/music_player/application.fam index 3414c0a48..e0254250e 100644 --- a/applications/external/music_player/application.fam +++ b/applications/external/music_player/application.fam @@ -1,5 +1,5 @@ App( - appid="music_player", + appid="Music_Player", name="Music Player", apptype=FlipperAppType.EXTERNAL, entry_point="music_player_app", diff --git a/applications/external/signal_generator/application.fam b/applications/external/signal_generator/application.fam index 094e784cc..bcf7d20b6 100644 --- a/applications/external/signal_generator/application.fam +++ b/applications/external/signal_generator/application.fam @@ -1,5 +1,5 @@ App( - appid="signal_generator", + appid="Signal_Generator", name="Signal Generator", apptype=FlipperAppType.EXTERNAL, entry_point="signal_gen_app",