Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
31437c3
initial commit of instance object
lia-viam Feb 18, 2025
932ebaa
wip: initial commit to get sdk building with instance
lia-viam Feb 18, 2025
04d0158
add missing implementation
lia-viam Feb 18, 2025
a105cef
update examples to use instance
lia-viam Feb 18, 2025
403f316
only instance can construct registry
lia-viam Feb 18, 2025
27eeb13
make tests work with registry member approach
lia-viam Feb 21, 2025
ce2aa8c
pimpl registry and update examples
lia-viam Feb 24, 2025
e5cf6d0
add instance management infra
lia-viam Feb 25, 2025
85194da
Merge branch 'main' of github.com:viamrobotics/viam-cpp-sdk into regi…
lia-viam Feb 25, 2025
5024d3a
update tflite module
lia-viam Feb 25, 2025
ef8ec8e
silence spurious const warning
lia-viam Feb 25, 2025
16113fd
make method static
lia-viam Feb 25, 2025
216e5e2
Merge branch 'main' of github.com:viamrobotics/viam-cpp-sdk into regi…
lia-viam Feb 26, 2025
4771390
use static current to populate registry member
lia-viam Feb 27, 2025
18d26c9
revert and adapt examples
lia-viam Feb 27, 2025
6018323
make instance more of a black box
lia-viam Feb 27, 2025
5535616
add impl instance to git
lia-viam Feb 27, 2025
eeac195
Add instance comment boilerplate
lia-viam Mar 3, 2025
7560f6d
Add instance comment boilerplate
lia-viam Mar 3, 2025
4e25d35
remove old ctor arg
lia-viam Mar 3, 2025
55baa6c
prohibit multi instance
lia-viam Mar 3, 2025
10cd711
remove initialized flag
lia-viam Mar 3, 2025
c745422
meyers singleton registry
lia-viam Mar 3, 2025
75ab450
remove registry member and fix member spacing/ordering
lia-viam Mar 3, 2025
fc21c35
remove unused include
lia-viam Mar 3, 2025
1758ee9
Merge branch 'main' of github.com:viamrobotics/viam-cpp-sdk into regi…
lia-viam Mar 3, 2025
cd1d8c5
Merge branch 'registry-member' of github.com:lia-viam/viam-cpp-sdk in…
lia-viam Mar 3, 2025
6e154ce
Merge branch 'main' of github.com:viamrobotics/viam-cpp-sdk into regi…
lia-viam Mar 12, 2025
f02ce0f
reorder includes
lia-viam Mar 12, 2025
e80bf80
conditionally find unit test framework and link it to tests
lia-viam Mar 12, 2025
185121a
registry get cannot create instance by default
lia-viam Mar 12, 2025
7a747ec
instance models fixture
lia-viam Mar 12, 2025
9c4dc97
create if needed instance in fixture
lia-viam Mar 12, 2025
30fe47e
Merge branch 'main' of github.com:viamrobotics/viam-cpp-sdk into regi…
lia-viam Mar 12, 2025
7409dc7
revert namespace ws
lia-viam Mar 12, 2025
c4aaadf
code review: update doc comment
lia-viam Mar 13, 2025
d2ae2d7
code review: include order
lia-viam Mar 13, 2025
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
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,11 @@ set(VIAMCPPSDK_XTL_VERSION_MINIMUM 0.7.2)
set(VIAMCPPSDK_XTENSOR_VERSION_MINIMUM 0.24.3)

# Time to find `BOOST`.
find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log program_options)
if (VIAMCPPSDK_BUILD_TESTS)
set(VIAMCPPSDK_BOOST_TEST "unit_test_framework")
endif()

find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log program_options ${VIAMCPPSDK_BOOST_TEST})

# Time to find `protobuf` and `gRPC[++]`. Normally this would just be
# something like `find_package(gRPC <version> CONFIG REQUIRED)`, and
Expand Down
6 changes: 6 additions & 0 deletions src/viam/examples/camera/example_camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <unistd.h>
#include <vector>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/components/camera.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/rpc/dial.hpp>
Expand All @@ -13,6 +14,11 @@ int main() {
using std::endl;
namespace vs = ::viam::sdk;
try {
// Every Viam C++ SDK program must have one and only one Instance object which is created
// before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
vs::Instance inst;

// If you want to connect to a remote robot, this should be the url of the robot
// Ex: xxx.xxx.viam.cloud
std::string robot_address("localhost:8080");
Expand Down
5 changes: 5 additions & 0 deletions src/viam/examples/dial/example_dial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@

#include <boost/optional.hpp>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/components/generic.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/rpc/dial.hpp>

using namespace viam::sdk;

int main() {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

const char* uri = "<your robot URI here>";
DialOptions dial_options;
std::string type = "<your authentication type>";
Expand Down
5 changes: 5 additions & 0 deletions src/viam/examples/dial_api_key/example_dial_api_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <boost/optional.hpp>
#include <boost/program_options.hpp>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/rpc/dial.hpp>

Expand All @@ -18,6 +19,10 @@ using namespace viam::sdk;
namespace po = boost::program_options;

int main(int argc, char* argv[]) {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

po::options_description desc("Allowed options");
desc.add_options()("help", "List options and exit")(
"uri", po::value<std::string>(), "URI of robot")(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <boost/program_options.hpp>
#include <boost/variant/get.hpp>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/services/mlmodel.hpp>

Expand Down Expand Up @@ -78,6 +79,10 @@ constexpr char kRobotConfigTemplate[] = R"(
} // namespace

int main(int argc, char* argv[]) try {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
viam::sdk::Instance inst;

// Build up our command line options. The example operates in two
// modes. In the "--generate" mode, it takes command line
// parameters needed to satisfy the interpolation points in the
Expand Down
9 changes: 7 additions & 2 deletions src/viam/examples/modules/complex/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <grpcpp/grpcpp.h>
#include <grpcpp/support/status.h>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/components/motor.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/rpc/dial.hpp>
Expand All @@ -21,6 +22,10 @@
using namespace viam::sdk;

int main() {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely
DialOptions dial_options;
dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely
Expand All @@ -37,8 +42,8 @@ int main() {

// Register custom gizmo and summation clients so robot client can access resources
// of that type from the server.
Registry::register_resource_client<GizmoClient>();
Registry::register_resource_client<SummationClient>();
Registry::get().register_resource_client<GizmoClient>();
Registry::get().register_resource_client<SummationClient>();

// Connect to robot.
std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options);
Expand Down
9 changes: 7 additions & 2 deletions src/viam/examples/modules/complex/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <grpcpp/grpcpp.h>
#include <grpcpp/server_context.h>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/components/base.hpp>
#include <viam/sdk/components/component.hpp>
#include <viam/sdk/config/resource.hpp>
Expand All @@ -24,11 +25,15 @@
using namespace viam::sdk;

int main(int argc, char** argv) {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

Model mybase_model("viam", "base", "mybase");

// Make sure to explicity register resources with custom APIs.
Registry::register_resource_server<GizmoServer>();
Registry::register_resource_server<SummationServer>();
Registry::get().register_resource_server<GizmoServer>();
Registry::get().register_resource_server<SummationServer>();

std::shared_ptr<ModelRegistration> mybase_mr = std::make_shared<ModelRegistration>(
API::get<Base>(),
Expand Down
5 changes: 3 additions & 2 deletions src/viam/examples/modules/complex/test_complex_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ using namespace viam::sdktests;

struct RegisterGizmoAndSummationFixture {
RegisterGizmoAndSummationFixture() {
Registry::register_resource<GizmoClient, GizmoServer>();
Registry::register_resource<SummationClient, SummationServer>();
auto& registry = Registry::get();
registry.register_resource<GizmoClient, GizmoServer>();
registry.register_resource<SummationClient, SummationServer>();
}

// Test teardown is a noop;
Expand Down
5 changes: 5 additions & 0 deletions src/viam/examples/modules/simple/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <memory>
#include <string>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/common/proto_value.hpp>
#include <viam/sdk/components/sensor.hpp>
#include <viam/sdk/robot/client.hpp>
Expand All @@ -10,6 +11,10 @@
using namespace viam::sdk;

int main() {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely
DialOptions dial_options;
dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely
Expand Down
5 changes: 5 additions & 0 deletions src/viam/examples/modules/simple/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <sstream>

#include <viam/sdk/common/exception.hpp>
#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/common/proto_value.hpp>
#include <viam/sdk/components/sensor.hpp>
#include <viam/sdk/config/resource.hpp>
Expand Down Expand Up @@ -75,6 +76,10 @@ ProtoStruct MySensor::get_readings(const ProtoStruct&) {
}

int main(int argc, char** argv) try {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
Instance inst;

Model mysensor_model("viam", "sensor", "mysensor");

std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>(
Expand Down
7 changes: 6 additions & 1 deletion src/viam/examples/modules/tflite/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <tensorflow/lite/c/c_api.h>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/common/proto_value.hpp>
#include <viam/sdk/components/component.hpp>
#include <viam/sdk/config/resource.hpp>
Expand Down Expand Up @@ -723,6 +724,10 @@ class MLModelServiceTFLite : public vsdk::MLModelService,
};

int serve(const std::string& socket_path) try {
// Every Viam C++ SDK program must have one and only one Instance object which is created before
// any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed.
vsdk::Instance inst;

// Create a new model registration for the service.
auto module_registration = std::make_shared<vsdk::ModelRegistration>(
// Identify that this resource offers the MLModelService API
Expand All @@ -737,7 +742,7 @@ int serve(const std::string& socket_path) try {
});

// Register the newly created registration with the Registry.
vsdk::Registry::register_model(module_registration);
Registry::get().register_model(module_registration);

// Construct the module service and tell it where to place the socket path.
auto module_service = std::make_shared<vsdk::ModuleService>(socket_path);
Expand Down
6 changes: 6 additions & 0 deletions src/viam/examples/motor/example_motor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>
#include <vector>

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/components/motor.hpp>
#include <viam/sdk/robot/client.hpp>
#include <viam/sdk/rpc/dial.hpp>
Expand All @@ -27,6 +28,11 @@ int main() {
namespace vs = ::viam::sdk;

try {
// Every Viam C++ SDK program must have one and only one Instance object which is created
// before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are
// destroyed.
vs::Instance inst;

// If you want to connect to a remote robot, this should be the url of the robot
// Ex: xxx.xxx.viam.cloud
std::string robot_address("localhost:8080");
Expand Down
2 changes: 2 additions & 0 deletions src/viam/sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ target_sources(viamsdk
PRIVATE
common/client_helper.cpp
common/exception.cpp
common/instance.cpp
common/linear_algebra.cpp
common/pose.cpp
common/proto_value.cpp
Expand Down Expand Up @@ -145,6 +146,7 @@ target_sources(viamsdk
FILES
../../viam/sdk/common/client_helper.hpp
../../viam/sdk/common/exception.hpp
../../viam/sdk/common/instance.hpp
../../viam/sdk/common/linear_algebra.hpp
../../viam/sdk/common/pose.hpp
../../viam/sdk/common/proto_convert.hpp
Expand Down
57 changes: 57 additions & 0 deletions src/viam/sdk/common/instance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <viam/sdk/common/instance.hpp>

#include <viam/sdk/common/exception.hpp>
#include <viam/sdk/common/private/instance.hpp>
#include <viam/sdk/registry/registry.hpp>

#include <atomic>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) can we put this include block above the viam/sdk include block?


namespace viam {
namespace sdk {

namespace {

// Memory region sentinel to check if object is being destroyed.
std::aligned_storage_t<sizeof(Instance), alignof(Instance)> sentinel;

std::atomic<Instance*> current_instance{nullptr};

} // namespace

Instance::Instance() {
Instance* expected = nullptr;

if (!current_instance.compare_exchange_strong(expected, this)) {
throw Exception("tried to create duplicate instance");
}

impl_ = std::make_unique<Instance::Impl>();
impl_->registry.initialize();
}

Instance::~Instance() {
current_instance.store(reinterpret_cast<Instance*>(&sentinel));
impl_.reset();
}

Instance& Instance::current(Instance::Creation creation) {
if (!current_instance.load()) {
if (creation == Creation::if_needed) {
// This variable declaration calls the default ctor, storing a current instance.
static Instance inst; // NOLINT (misc-const-correctness)
} else {
throw Exception("Instance has not yet been created");
}
}

Instance* current = current_instance.load();

if (current == reinterpret_cast<Instance*>(&sentinel)) {
throw Exception("instance was destroyed");
}
Comment on lines +49 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(q) pardon my ignorance, I don't think I fully understand this. Under what conditions will this exception throw?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait actually this gets to your comment above about making it an error to have multiple instances even if non-overlapping, so it already is an error to have multiple of them


return *current;
}

} // namespace sdk
} // namespace viam
37 changes: 37 additions & 0 deletions src/viam/sdk/common/instance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <memory>

namespace viam {
namespace sdk {

/// @brief Instance management for Viam C++ SDK applications.
/// This is a single instance class which is responsible for global setup and teardown related to
/// the SDK. An Instance must be constructed before doing anything else in a program, and it must
/// remain alive in a valid state for the duration of the program. Creating multiple Instance
/// objects in the same program is an error.
class Instance {
public:
/// @brief Enumeration for creation behavior of @ref current
enum class Creation {
open_existing, ///< Instance must already exist
if_needed ///< Use existing instance if present, else create one.
};

Instance();
~Instance();

/// @brief Get the current Instance according to the Creation behavior.
/// Calling current(Creation::open_existing) when an instance has not yet been constructed is an
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) I'd put the error case in a @throws line for clearer doxygen docs.

/// error.
static Instance& current(Creation);

private:
friend class Registry;

struct Impl;
std::unique_ptr<Impl> impl_;
};

} // namespace sdk
} // namespace viam
14 changes: 14 additions & 0 deletions src/viam/sdk/common/private/instance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <viam/sdk/common/instance.hpp>
#include <viam/sdk/registry/registry.hpp>

namespace viam {
namespace sdk {

struct Instance::Impl {
Registry registry;
};

} // namespace sdk
} // namespace viam
Loading