Skip to content

Commit

Permalink
Merge pull request #33 from klonyyy/devel
Browse files Browse the repository at this point in the history
Variable import window
  • Loading branch information
klonyyy committed Feb 11, 2024
2 parents dd2d895 + f554745 commit 4d22bcd
Show file tree
Hide file tree
Showing 51 changed files with 1,104 additions and 335 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,30 @@ jobs:
build:
runs-on: ubuntu-20.04
container:
image: klonyyy/mingw-w64-x86-64
image: klonyyy/mingw-w64-x86-64:2
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
token: ${{ secrets.PAT }}

- name: build_step
shell: bash
run: git config --global --add safe.directory /__w/STMViewer/ && ./launch/release.sh
- uses: actions/upload-artifact@v3
with:
name: STMViewer_installer
path: /__w/STMViewer/STMViewer/build/packages
test:
runs-on: ubuntu-20.04
container:
image: klonyyy/mingw-w64-x86-64:2
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
token: ${{ secrets.PAT }}

- name: test_step
shell: bash
run: git config --global --add safe.directory /__w/STMViewer/ && ./launch/run_tests.sh
54 changes: 35 additions & 19 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ endif()

project(STMViewer)

set(STMVIEWER_VERSION 0.3.0)
set(STMVIEWER_VERSION 0.4.0)

set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_STANDARD 20)
Expand All @@ -44,25 +44,33 @@ add_compile_options(-Wall
-Wno-missing-field-initializers)

if(UNIX)
add_custom_target(addGitVersion COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/launch/addGitVersion.sh)

include(FetchContent)
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.13.0)

FetchContent_GetProperties(spdlog)
if (NOT spdlog_POPULATED)
FetchContent_Populate(spdlog)
add_subdirectory(${spdlog_SOURCE_DIR} ${spdlog_BINARY_DIR})
endif()

# this is to avoid warnings from spdlog
get_target_property(SPDLOG_IID spdlog INTERFACE_INCLUDE_DIRECTORIES)
set_target_properties(spdlog PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${SPDLOG_IID}")

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
include(${CMAKE_MODULE_PATH}/Findlibusb.cmake)
find_package(libusb REQUIRED)
find_package(glfw3 REQUIRED)
set(STLINK_LINUX ${CMAKE_CURRENT_SOURCE_DIR}/third_party/stlink/lib/linux/libstlink.a)
set(SPDLOG_LINUX ${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog/lib/linux/libspdlog.so.1.11.0)
set(INSTALL_PATH /usr/local/STMViewer)
set(DESKTOP_FILE_PATH /usr/share/applications)
endif()

if(WIN32)
# use bat script only if not cross-compiling
if("${PLATFORM}" STREQUAL "native")
add_custom_target(addGitVersion COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/launch/addGitVersion.bat)
else()
add_custom_target(addGitVersion COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/launch/addGitVersion.sh)
endif()

enable_language("RC")
set(ICON_RC "${CMAKE_CURRENT_SOURCE_DIR}/launch/icon.rc")
set(GLFW3_WINDOWS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/GLFW/lib/windows/glfw3.dll)
Expand All @@ -75,12 +83,12 @@ endif()

set(PROJECT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ElfReader/ElfReader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/Gui.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/GuiPlots.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/GuiSwoPlots.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/GuiSwoControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/GuiAbout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui/GuiImportVariables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/TargetMemoryHandler/TargetMemoryHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/TargetMemoryHandler/StlinkHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Plot/Plot.cpp
Expand All @@ -93,7 +101,8 @@ set(PROJECT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/PlotHandler/PlotHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/PlotHandler/TracePlotHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/TraceReader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/StlinkTraceDevice.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/StlinkTraceDevice.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser/GdbParser.cpp)

set(IMGUI_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/third_party/imgui/imgui.cpp
Expand All @@ -110,9 +119,9 @@ set(IMPLOT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/third_party/implot/implot_items.cpp)

set_source_files_properties(
${IMPLOT_SOURCES}
PROPERTIES
COMPILE_FLAGS "-w"
${IMPLOT_SOURCES}
PROPERTIES
COMPILE_FLAGS "-w"
)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/nfd/)
Expand All @@ -121,6 +130,12 @@ set(EXECUTABLE ${CMAKE_PROJECT_NAME})

add_executable(${EXECUTABLE} ${PROJECT_SOURCES} ${IMGUI_SOURCES} ${IMPLOT_SOURCES} ${ICON_RC})

# GIT version
add_custom_target(addGitVersion COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} python3 ${CMAKE_CURRENT_SOURCE_DIR}/launch/addGitVersion.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating gitversion.hpp..."
VERBATIM)

add_dependencies(${EXECUTABLE} addGitVersion)

string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ "${STMVIEWER_VERSION}")
Expand All @@ -131,7 +146,6 @@ target_compile_definitions(${EXECUTABLE}
)

target_include_directories(${EXECUTABLE} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/ElfReader
${CMAKE_CURRENT_SOURCE_DIR}/src/Gui
${CMAKE_CURRENT_SOURCE_DIR}/src/TargetMemoryHandler
${CMAKE_CURRENT_SOURCE_DIR}/src/Plot
Expand All @@ -143,7 +157,8 @@ target_include_directories(${EXECUTABLE} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/PlotHandler
${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader
${CMAKE_CURRENT_SOURCE_DIR}/src/RingBuffer
${CMAKE_CURRENT_SOURCE_DIR}/src/Statistics)
${CMAKE_CURRENT_SOURCE_DIR}/src/Statistics
${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser)

target_include_directories(${EXECUTABLE} SYSTEM PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/third_party/stlink/inc/
Expand All @@ -158,7 +173,7 @@ target_include_directories(${EXECUTABLE} SYSTEM PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog/inc/)

if(UNIX)
target_link_libraries(${EXECUTABLE} ${STLINK_LINUX} ${LIBUSB_LIBRARY} ${SPDLOG_LINUX} pthread dl GL glfw nfd)
target_link_libraries(${EXECUTABLE} ${STLINK_LINUX} ${LIBUSB_LIBRARY} spdlog::spdlog pthread dl GL glfw nfd)
elseif(WIN32)
target_link_libraries(${EXECUTABLE} ${GLFW3_WINDOWS} ${STLINK_WINDOWS} ${LIBUSB_WINDOWS} ${SPDLOG_WINDOWS} -static ssp opengl32 nfd -static-libstdc++ -static-libgcc)
endif()
Expand Down Expand Up @@ -188,6 +203,7 @@ if(WIN32)
if(PRODUCTION)
set_target_properties(${EXECUTABLE} PROPERTIES WIN32_EXECUTABLE TRUE)
endif()

install(FILES ${LIBUSB_WINDOWS} ${STLINK_WINDOWS} ${GLFW3_WINDOWS} DESTINATION ${INSTALL_PATH})
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
SetOutPath \\\"$INSTDIR\\\\bin\\\"
Expand All @@ -203,7 +219,7 @@ if(UNIX)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/launch/STMViewer.desktop
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${DESKTOP_FILE_PATH})
set(CPACK_GENERATOR "DEB")
set(CPACK_GENERATOR "DEB;RPM")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libglfw3 | libglfw3-wayland, libgl1, libglib2.0-0, libgtk-3-0, libstdc++6, libusb-1.0-0, gdb")
endif()

Expand Down
36 changes: 23 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Variable Viewer is a great tool for debugging, but might be of little use with h
### Trace Viewer
![_](./docs/TraceViewer.gif)

Trace Viewer is a new module that lets you visualize SWO trace data. It can serve multiple purposes such as profiling a function execution time, confirming the timer's interrupt frequency, or displaying very fast signals. All this is possible thanks to hardware trace peripherals embedded into Cortex M3/M4/M7/M33 cores. For prerequisites and usage please see the Quick Start section.
Trace Viewer is a new module that lets you visualize SWO trace data. It can serve multiple purposes such as profiling a function execution time, confirming the timer's interrupt frequency, or displaying very high frequency signals. All this is possible thanks to hardware trace peripherals embedded into Cortex M3/M4/M7/M33 cores. For prerequisites and usage please see the Quick Start section.

TraceViewer is not influenced by optimizations, which means it is a great tool to use for profiling on release builds. Moreover it has a very low influence on the program execution as each datapoint is a single register write.

Expand All @@ -31,7 +31,7 @@ Linux:
1. Download the *.deb package and install it using:
`sudo apt install ./STMViewer-x.y.z-Linux.deb`
All dependencies should be installed and you should be ready to go.
Optional: make sure you have the rights to access usb port. When installing ST's software such as Cube Programmer it will most probably also install needed udev rules.
In case your stlink is not detected, please copty the `/launch/udevrules/` folder contents to your `/etc/udev/rules.d/` directory.

Windows:
1. Make sure you've got GDB installed and added to your PATH (the easiest way is to install using [MinGW](https://www.mingw-w64.org))
Expand All @@ -42,14 +42,14 @@ You can assign the external GPU to STMViewer for improved performance.
## Quick Start

### Variable Viewer
1. Open Options->Acqusition Settings window in the top menu.
1. Open `Options -> Acqusition` Settings window in the top menu.
2. Select your project's elf file. Make sure the project is compiled in debug mode. Click done.
3. Click the 'add variable' button to add a new variable. Double-click to change its name to one of your global variables. If you're using structs or classes in C++ make sure to add its name before the variable, exactly like you'd refer to it in the code (for example myClass.var, or namespace::myClass.var).
4. After adding all variables click 'update variable addresses'. The type and address of the variables you've added should change from "NOT FOUND!" to a valid address based on the *.elf file you've provided.
3. Click the `Import variables form *.elf` button and click `Refresh`. Select variables and click `Import`. Note: the import feature is still in beta. If your variable is not automatically detected just click `Add variable` and input the name yourself. Please let me know if that happens by opening a new issue with *.elf file attached.
4. After adding all variables click `Update variable addresses`. The type and address of the variables you've added should change from "NOT FOUND!" to a valid address based on the *.elf file you've provided. Note: 64-bit variables (such as uint64_t and double) are not yet supported #13.
5. Drag and drop the variable to the plot area.
6. Make sure the ST-Link is connected. Download your executable to the microcontroller and press the "STOPPED" button.
6. Make sure the ST-Link is connected. Download your executable to the microcontroller and press the `STOPPED` button.

In case of any problems, please try the test/STMViewer_test CubeIDE project and the corresponding STMViewer_test.cfg project file. Please remember to build the project and update the elf file path in the Options -> Acquisition Settings.
In case of any problems, please try the test/STMViewer_test CubeIDE project and the corresponding STMViewer_test.cfg project file. Please remember to build the project and update the elf file path in the `Options -> Acqusition` Settings.

Example project with STMViewer config file is located in test/STMViewer_test directory.

Expand All @@ -63,31 +63,31 @@ ITM->PORT[x].u8 = 0xbb; //exit tag 0xbb - plot state low
```
And for tracing "analog" signals you can use:
```
float a = sin(10.0f * i); // some super fast signal to trace
float a = sin(10.0f * i); // some high frequency signal to trace
ITM->PORT[x].u32 = *(uint32_t*)&a; // type-punn to desired size: sizeof(float) = sizeof(uint32_t)
```
or

```
uint16_t a = getAdcSample(); // some super fast signal to trace
uint16_t a = getAdcSample(); // some high frequency signal to trace
ITM->PORT[x].u16 = a;
```

The ITM registers are defined in CMSIS headers so no additional includes should be necessary.
The ITM registers are defined in CMSIS headers (core_xxxx.h).

3. Compile and download the program to your STM32 target.
4. In the `Settings` window type in the correct System Core Clock value in kHz (very important as it affects the timebase)
5. Try different trace prescallers that result in a trace speed lower than the max trace speed of your programmer (for example STLINK V2 can read trace up to 2Mhz, whereas ST-Link V3 is theoretically able to do 24Mhz). Example:
- System Core Clock is 160 000 kHz (160 Mhz)
- We're using ST-link V2 so the prescaler should be at least 160 Mhz / 2 Mhz = 80
6. Configure "analog" channels types according to the type used in your code.
7. Press the "STOPPED" button to start recording.
6. Configure `analog` channels types according to the type used in your code.
7. Press the `STOPPED` button to start recording.

Example project with STMViewer config file is located in test/STMViewer_test directory.

FAQ and common issues:
1. Problem: My trace doesn't look like it's supposed to and I get a lot of error frames
Answer: Try lowering the trace prescaller and check the SWO pin connection - the SWO pin output is a fast signal and it shouldn't be too long.
Answer: Try lowering the trace prescaller and check the SWO pin connection - the SWO pin output is high frequency and it shouldn't be too long.

2. Problem: My trace looks like it's supposed to but I get the "delayed timestamp 3" indicator
Answer: Try logging fewer channels simultaneously. It could be that you've saturated the SWO pin bandwidth.
Expand All @@ -96,6 +96,16 @@ Answer: Try logging fewer channels simultaneously. It could be that you've satur
Answer: This is not a critical error, however, you should be cautious as some of the trace frames may be delayed. To fix try logging fewer channels simultaneously.


## Building

STMViewer is build like any other CMake project. On Windows you can use MinGW. If you're a Linux user be sure to install:
1. libusb-1.0-0-dev
2. libglfw3-dev
3. libgtk-3-dev

After a successful build, copy the ``./third_party/stlink/chips`` directory to where the binary is located. Otherwise the STlink will not detect your STM32 target.


## Why
I'm working in the motor control industry where it is crucial to visualize some of the process data in real-time. Since the beginning, I have been working with [STMStudio](https://www.st.com/en/development-tools/stm-studio-stm32.html), which is, or rather was a great tool. Unfortunately, ST stopped supporting it which means there are some annoying bugs, and it doesn't work well with mangled c++ object names. Also, it works only on Windows which is a big downside. If you've ever used it you probably see how big of an inspiration it was for creating STMViewer :) ST's other project in this area - [Cube Monitor](https://www.st.com/en/development-tools/stm32cubemonitor.html) - has, in my opinion, too much overhead on adding variables, plots and writing values. I think it's designed for creating dashboards, and thus it serves a very different purpose. On top of that, I think the plot manipulation is much worse compared to STMStudio or STMViewer.

Expand Down
4 changes: 2 additions & 2 deletions launch/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# this points to the lts version
FROM ubuntu:focal
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y wget make cmake git build-essential mingw-w64 libusb-1.0-0-dev libglfw3-dev libgtk-3-dev nsis
RUN git config --global --add safe.directory '*'
RUN apt-get update && apt-get install -y wget make cmake git build-essential mingw-w64 libusb-1.0-0-dev libglfw3-dev libgtk-3-dev libspdlog-dev nsis rpm
RUN git config --global --add safe.directory '*'
1 change: 0 additions & 1 deletion launch/addGitVersion.bat

This file was deleted.

17 changes: 17 additions & 0 deletions launch/addGitVersion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import subprocess

# Run git log command to get the hash and format it into a Python file
git_hash = subprocess.check_output(
[
"git",
"log",
'--pretty=format:#define GIT_INFO_PRESENT%n static constexpr const char* GIT_HASH = "%H";',
"-n",
"1",
]
).decode()

# Write the output to a Python file, creating it if it doesn't exist
file_path = "./src/gitversion.hpp"
with open(file_path, "w+") as file:
file.write(git_hash)
5 changes: 0 additions & 5 deletions launch/addGitVersion.sh

This file was deleted.

3 changes: 2 additions & 1 deletion launch/launch.bat
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
C:\\msys64\\mingw64\\bin\\gdbserver.exe localhost:2000 ./build/STMViewer.exe
::C:\\msys64\\mingw64\\bin\\gdbserver.exe localhost:2000 ./build/STMViewer.exe
C:\\msys64\\mingw64\\bin\\gdbserver.exe localhost:2000 ./build_test/test/STMViewer_test.exe
1 change: 1 addition & 0 deletions launch/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cd linux
cmake -DPRODUCTION=TRUE ../..
make package -j32
cp *.deb ../packages
cp *.rpm ../packages
cd -

mkdir -p windows
Expand Down
11 changes: 11 additions & 0 deletions launch/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
git config --global --add safe.directory /__w/STMViewer/STMViewer

rm -rf build_test
mkdir build_test
cd build_test
cmake .. -DMAKE_TESTS=1
make -j
cd ../build_test
./test/STMViewer_test

6 changes: 6 additions & 0 deletions launch/udevrules/49-stlinkv1.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# stm32 discovery boards, with onboard st/linkv1
# ie, STM32VL.

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv1_%n"
11 changes: 11 additions & 0 deletions launch/udevrules/49-stlinkv2-1.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# stm32 nucleo boards, with onboard st/linkv2-1
# ie, STM32F0, STM32F4.

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv2-1_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv2-1_%n"

6 changes: 6 additions & 0 deletions launch/udevrules/49-stlinkv2.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# stm32 discovery boards, with onboard st/linkv2
# ie, STM32L, STM32F4.

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv2_%n"
29 changes: 29 additions & 0 deletions launch/udevrules/49-stlinkv3.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# stlink-v3 boards (standalone and embedded) in usbloader mode and standard (debug) mode

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3loader_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3755", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3loader_%n"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3757", \
MODE="660", GROUP="plugdev", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1", \
SYMLINK+="stlinkv3_%n"

0 comments on commit 4d22bcd

Please sign in to comment.