Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/debugging_example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
10 changes: 10 additions & 0 deletions cpp/debugging_example/.oakappignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Build artifacts
build/

# Documentation
README.md

# VCS
.git/
.github/
.gitlab/
60 changes: 60 additions & 0 deletions cpp/debugging_example/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to OAK (gdbserver)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/main_device",
"cwd": "${workspaceFolder}",
"MIMode": "gdb",
"targetArchitecture": "arm64",
"miDebuggerArgs": "-ex \"shell mkdir -p ${workspaceFolder}/build && touch -a ${workspaceFolder}/build/main_device\"",
Comment thread
TamseSaso marked this conversation as resolved.
Outdated
"stopAtEntry": false,
"externalConsole": false,
"sourceFileMap": {
"/app": "${workspaceFolder}"
Comment thread
TamseSaso marked this conversation as resolved.
},
"customLaunchSetupCommands": [
{
"description": "Connect to gdbserver",
"text": "target remote ${input:boardIP}:5678",
"ignoreFailures": false
},
{
"description": "Pull binary from device",
"text": "remote get /app/build/main ${workspaceFolder}/build/main_device",
"ignoreFailures": false
},
{
"description": "Reload symbols from fresh binary",
"text": "exec-file ${workspaceFolder}/build/main_device",
"ignoreFailures": false
},
{
"description": "Enable pretty printing",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Map container sources to workspace",
"text": "set substitute-path /app ${workspaceFolder}",
"ignoreFailures": true
},
{
"description": "Disable pagination",
"text": "set pagination off",
"ignoreFailures": true
}
]
}
],
"inputs": [
{
"id": "boardIP",
"type": "promptString",
"description": "Enter OAK board IP address",
"default": "192.168.1.198"
}
]
}
19 changes: 19 additions & 0 deletions cpp/debugging_example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.20)

project(camera_stream VERSION 1.0 LANGUAGES CXX)

# Use C++17 standard
set(CMAKE_CXX_STANDARD 17)

# Depthai dependency
find_package(depthai REQUIRED)
message(STATUS "Found depthai: ${depthai_DIR}")

# Add source files
add_executable(main src/main.cpp)

# Link with libraries
target_link_libraries(main PUBLIC depthai::core)

# Suppress warnings about C++17 ABI in GCC 10.1+
target_compile_options(main PRIVATE -Wno-psabi)
48 changes: 48 additions & 0 deletions cpp/debugging_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Remote Debugging Setup for OAK C++ Apps

This example shows the steps to add VS Code remote debugging to any C++ OAK app.

## 1. Copy `.vscode/launch.json`

Copy the `.vscode/launch.json` from this project into your app's `.vscode/` folder. No changes needed — it uses `${workspaceFolder}` throughout so it works in any project location.

On launch it will prompt for:

- **Board IP** — IP address of your OAK device

## 2. Update `backend-run.sh`

Your `backend-run.sh` should start `gdbserver` wrapping your binary instead of running it directly:

```sh
#!/bin/sh
gdbserver 0.0.0.0:5678 /app/build/main
```

## 3. Update `oakapp.toml`

Add the following to your `build_steps`:

```toml
build_steps = [
# Install gdbserver
"apt-get install -y --no-install-recommends gdb gdbserver",

# Create and enable backend service startup.
"mkdir -p /etc/service/backend",
"cp /app/backend-run.sh /etc/service/backend/run",
"chmod +x /etc/service/backend/run",

# Build in Debug mode so the binary has symbols
"cmake -S /app -B /app/build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"cmake --build /app/build -- -j",
]
```

## 4. Deploy and Debug

```bash
oakctl app run .
```

Then set breakpoints and press **F5** in VS Code. GDB connects to `gdbserver` on port 5678, pulls the binary directly from the container, reloads symbols, and starts the debug session.
3 changes: 3 additions & 0 deletions cpp/debugging_example/backend-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Starting Backend"
gdbserver 0.0.0.0:5678 /app/build/main
23 changes: 23 additions & 0 deletions cpp/debugging_example/oakapp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
identifier = "com.example.cpp.camera_stream"
entrypoint = ["bash", "-c", "/usr/bin/runsvdir -P /etc/service"]
app_version = "1.0.0"

build_steps = [
"apt-get install -y --no-install-recommends gdb gdbserver",
"mkdir -p /etc/service/backend",
"cp /app/backend-run.sh /etc/service/backend/run",
"chmod +x /etc/service/backend/run",
"cmake -S /app -B /app/build -DCMAKE_BUILD_TYPE=Debug",
"cmake --build /app/build --parallel",
]

assign_frontend_port = true

[base_image]
api_url = "https://registry-1.docker.io"
service = "registry.docker.io"
oauth_url = "https://auth.docker.io/token"
auth_type = "repository"
auth_name = "luxonis/oakapp-base"
image_name = "luxonis/oakapp-base"
image_tag = "1.2.6-cpp"
26 changes: 26 additions & 0 deletions cpp/debugging_example/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <depthai/depthai.hpp>
#include <depthai/remote_connection/RemoteConnection.hpp>

int main(int argc, char** argv) {
dai::RemoteConnection remoteConnector;

dai::Pipeline pipeline;

// Create a camera and request a 800p output
auto cameraNode = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_A);
auto* cameraOutputVisualize = cameraNode->requestOutput(std::make_pair(1280, 800), dai::ImgFrame::Type::NV12);

// Register the output so it's visualized on the remote connection
remoteConnector.addTopic("stream", *cameraOutputVisualize);

// Start the pipeline
pipeline.start();
while(pipeline.isRunning()) {
int key = remoteConnector.waitKey(1);
if(key == 'q') {
std::cout << "Got 'q' key from the remote connection!" << std::endl;
break;
}
}
return 0;
}