Skip to main content

C++

Connect directly to Foxglove or play back local data recorded with the C++ SDK.

Install the SDK

The C++ SDK is a wrapper around a C library. To build it, you will need to link that library and compile the SDK source as part of your build process. The SDK assumes C++17 or newer.

Download the library, source, and header files for your platform from the SDK release assets.

If you're using CMake, you can use the following as a starting point. For more detail, see the quickstart example.

cmake_minimum_required(VERSION 3.20)

# TODO: replace "my_program" throughout with the name of your project
project(my_program LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)

# Fetch Foxglove SDK
include(FetchContent)
FetchContent_Declare(
foxglove
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
# TODO: Copy the URL and SHA for the appropriate .zip file from here:
# https://github.com/foxglove/foxglove-sdk/releases?q=sdk%2F&expanded=true
URL <download URL from the GitHub release>
URL_HASH SHA256=<sha from the GitHub release>
)
FetchContent_MakeAvailable(foxglove)

# Assuming the project consists of a single source file, main.cpp
add_executable(my_program main.cpp)

# Add include directory for Foxglove SDK
target_include_directories(my_program PRIVATE ${foxglove_SOURCE_DIR}/include)
target_include_directories(my_program PRIVATE ${foxglove_SOURCE_DIR}/include/foxglove)

# Find all Foxglove SDK source files
file(GLOB FOXGLOVE_SOURCES CONFIGURE_DEPENDS
"${foxglove_SOURCE_DIR}/src/*.cpp"
"${foxglove_SOURCE_DIR}/src/server/*.cpp"
)

# Add Foxglove SDK source files
target_sources(my_program PRIVATE ${FOXGLOVE_SOURCES})

# Link against libfoxglove.a
target_link_libraries(my_program PRIVATE ${foxglove_SOURCE_DIR}/lib/libfoxglove.a)

Live data

Log messages from C++

#include <foxglove/foxglove.hpp>
#include <foxglove/server.hpp>

#include <chrono>
#include <csignal>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

int main(int argc, const char *argv[]) {
foxglove::WebSocketServerOptions options;
auto serverResult = foxglove::WebSocketServer::create(std::move(options));
if (!serverResult.has_value()) {
std::cerr << foxglove::strerror(serverResult.error()) << '\n';
return 1;
}

auto server = std::move(serverResult.value());
auto channel = foxglove::RawChannel::create("/hello", "json").value();
auto start = std::chrono::steady_clock::now();

// Log until interrupted
static std::function<void()> sigint_handler;
std::atomic_bool done = false;
sigint_handler = [&] { done = true; };
std::signal(SIGINT, [](int) {
if (sigint_handler) {
sigint_handler();
}
});

while (!done) {
auto dur = std::chrono::steady_clock::now() - start;
float elapsed_seconds = std::chrono::duration<float>(dur).count();
std::string msg = "{\"elapsed\": " + std::to_string(elapsed_seconds) + "}";
channel.log(reinterpret_cast<const std::byte *>(msg.data()), msg.size());

std::this_thread::sleep_for(33ms);
}

return 0;
}

Run the example

If you're using something like the CMake configuration above, you can create a build directory and run the following.

cd build
cmake ..
cmake --build .
./my_program

Connect

In Foxglove, select "Open connection" from the dashboard or left-hand menu.

Select open connection

Select "Foxglove WebSocket" in the "Open a new connection" dialog, then click "Open" to accept the default connection string:

Foxglove WebSocket dialog

Local data

Recording data to a file

The SDK can also log data to disk. Let's augment the example above to also produce an MCAP file which can later be opened in Foxglove:

#include <foxglove/foxglove.hpp>
#include <foxglove/mcap.hpp>
#include <foxglove/server.hpp>

#include <chrono>
#include <csignal>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

int main(int argc, const char *argv[]) {
foxglove::WebSocketServerOptions options;
auto serverResult = foxglove::WebSocketServer::create(std::move(options));
if (!serverResult.has_value()) {
std::cerr << foxglove::strerror(serverResult.error()) << '\n';
return 1;
}

auto server = std::move(serverResult.value());
auto channel = foxglove::RawChannel::create("/hello", "json").value();
auto start = std::chrono::steady_clock::now();

foxglove::McapWriterOptions mcap_options;
mcap_options.path = "example.mcap";
auto writerResult = foxglove::McapWriter::create(mcap_options);
if (!writerResult.has_value()) {
std::cerr << foxglove::strerror(writerResult.error()) << '\n';
return 1;
}
// Keep a reference to the writer. It will be closed when the writer is
// destroyed, or we could call `.close()` to close it manually.
auto writer = std::move(writerResult.value());

// Log until interrupted
static std::function<void()> sigint_handler;
std::atomic_bool done = false;
sigint_handler = [&] { done = true; };
std::signal(SIGINT, [](int) {
if (sigint_handler) {
sigint_handler();
}
});

while (!done) {
auto dur = std::chrono::steady_clock::now() - start;
float elapsed_seconds = std::chrono::duration<float>(dur).count();
std::string msg = "{\"elapsed\": " + std::to_string(elapsed_seconds) + "}";
channel.log(reinterpret_cast<const std::byte *>(msg.data()), msg.size());

std::this_thread::sleep_for(33ms);
}

return 0;
}

Viewing data from a file

To load local files for visualization, you can:

  • Click "Open local file(s)…" in the dashboard or left-hand menu
  • Open or drag-and-drop the files from your OS file manager (desktop only)

Local file dialog

note

When opening multiple files, Foxglove will merge the data into a single playback timeline.

You can only merge multiple files of the same format.

Imported data

After importing data to Foxglove, select individual resources to visualize on the Recordings or Events pages:

Visualize on Recordings page

Select a custom time range of data (can span multiple recordings or events) to visualize on the Timeline page: