From 9f93d418da3907066c818a1b63b2f1e8dffc4eaf Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:22:33 -0400 Subject: [PATCH 1/2] claude switch + edits (wip: buf output) --- src/viam/api/CMakeLists.txt | 8 ++ src/viam/sdk/CMakeLists.txt | 4 + .../sdk/components/private/switch_client.cpp | 43 +++++++++++ .../sdk/components/private/switch_client.hpp | 43 +++++++++++ .../sdk/components/private/switch_server.cpp | 54 +++++++++++++ .../sdk/components/private/switch_server.hpp | 50 ++++++++++++ src/viam/sdk/components/switch.cpp | 19 +++++ src/viam/sdk/components/switch.hpp | 77 +++++++++++++++++++ src/viam/sdk/registry/registry.cpp | 3 + src/viam/sdk/tests/CMakeLists.txt | 2 + src/viam/sdk/tests/mocks/mock_switch.cpp | 31 ++++++++ src/viam/sdk/tests/mocks/mock_switch.hpp | 27 +++++++ src/viam/sdk/tests/test_switch.cpp | 62 +++++++++++++++ 13 files changed, 423 insertions(+) create mode 100644 src/viam/sdk/components/private/switch_client.cpp create mode 100644 src/viam/sdk/components/private/switch_client.hpp create mode 100644 src/viam/sdk/components/private/switch_server.cpp create mode 100644 src/viam/sdk/components/private/switch_server.hpp create mode 100644 src/viam/sdk/components/switch.cpp create mode 100644 src/viam/sdk/components/switch.hpp create mode 100644 src/viam/sdk/tests/mocks/mock_switch.cpp create mode 100644 src/viam/sdk/tests/mocks/mock_switch.hpp create mode 100644 src/viam/sdk/tests/test_switch.cpp diff --git a/src/viam/api/CMakeLists.txt b/src/viam/api/CMakeLists.txt index e846760bc..3b23ba8ad 100644 --- a/src/viam/api/CMakeLists.txt +++ b/src/viam/api/CMakeLists.txt @@ -197,6 +197,10 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS) ${PROTO_GEN_DIR}/component/servo/v1/servo.grpc.pb.h ${PROTO_GEN_DIR}/component/servo/v1/servo.pb.cc ${PROTO_GEN_DIR}/component/servo/v1/servo.pb.h + ${PROTO_GEN_DIR}/component/switch/v1/switch.grpc.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.grpc.pb.h + ${PROTO_GEN_DIR}/component/switch/v1/switch.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.pb.h ${PROTO_GEN_DIR}/google/api/annotations.pb.cc ${PROTO_GEN_DIR}/google/api/annotations.pb.h ${PROTO_GEN_DIR}/google/api/httpbody.pb.cc @@ -322,6 +326,8 @@ target_sources(viamapi ${PROTO_GEN_DIR}/component/sensor/v1/sensor.pb.cc ${PROTO_GEN_DIR}/component/servo/v1/servo.grpc.pb.cc ${PROTO_GEN_DIR}/component/servo/v1/servo.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.grpc.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.pb.cc ${PROTO_GEN_DIR}/google/api/annotations.pb.cc ${PROTO_GEN_DIR}/google/api/http.pb.cc ${PROTO_GEN_DIR}/google/api/httpbody.pb.cc @@ -382,6 +388,8 @@ target_sources(viamapi ${PROTO_GEN_DIR}/../../viam/api/component/sensor/v1/sensor.pb.h ${PROTO_GEN_DIR}/../../viam/api/component/servo/v1/servo.grpc.pb.h ${PROTO_GEN_DIR}/../../viam/api/component/servo/v1/servo.pb.h + ${PROTO_GEN_DIR}/../../viam/api/component/switch/v1/switch.grpc.pb.h + ${PROTO_GEN_DIR}/../../viam/api/component/switch/v1/switch.pb.h ${PROTO_GEN_DIR}/../../viam/api/google/api/annotations.pb.h ${PROTO_GEN_DIR}/../../viam/api/google/api/http.pb.h ${PROTO_GEN_DIR}/../../viam/api/google/api/httpbody.pb.h diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index b69b586f9..30ebaa5ff 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -100,8 +100,11 @@ target_sources(viamsdk components/private/sensor_server.cpp components/private/servo_client.cpp components/private/servo_server.cpp + components/private/switch_client.cpp + components/private/switch_server.cpp components/sensor.cpp components/servo.cpp + components/switch.cpp config/resource.cpp module/handler_map.cpp module/module.cpp @@ -169,6 +172,7 @@ target_sources(viamsdk ../../viam/sdk/components/power_sensor.hpp ../../viam/sdk/components/sensor.hpp ../../viam/sdk/components/servo.hpp + ../../viam/sdk/components/switch.hpp ../../viam/sdk/config/resource.hpp ../../viam/sdk/module/handler_map.hpp ../../viam/sdk/module/module.hpp diff --git a/src/viam/sdk/components/private/switch_client.cpp b/src/viam/sdk/components/private/switch_client.cpp new file mode 100644 index 000000000..081f54277 --- /dev/null +++ b/src/viam/sdk/components/private/switch_client.cpp @@ -0,0 +1,43 @@ +#include + +#include +#include + +#include + +namespace viam { +namespace sdk { +namespace impl { + +SwitchClient::SwitchClient(std::string name, std::shared_ptr channel) + : Switch(std::move(name)), + stub_(viam::component::switch_::v1::SwitchService::NewStub(channel)), + channel_(std::move(channel)) {} + +void SwitchClient::set_position(uint32_t position, const ProtoStruct& extra) { + make_client_helper(this, *stub_, &StubType::SetPosition) + .with(extra, [&](auto& request) { request.set_position(position); }) + .invoke(); +} + +uint32_t SwitchClient::get_position(const ProtoStruct& extra) { + return make_client_helper(this, *stub_, &StubType::GetPosition) + .with(extra) + .invoke([](auto& response) { return response.position(); }); +} + +uint32_t SwitchClient::get_number_of_positions(const ProtoStruct& extra) { + return make_client_helper(this, *stub_, &StubType::GetNumberOfPositions) + .with(extra) + .invoke([](auto& response) { return response.number_of_positions(); }); +} + +ProtoStruct SwitchClient::do_command(const ProtoStruct& command) { + return make_client_helper(this, *stub_, &StubType::DoCommand) + .with([&](auto& request) { *request.mutable_command() = to_proto(command); }) + .invoke([](auto& response) { return from_proto(response.result()); }); +} + +} // namespace impl +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/private/switch_client.hpp b/src/viam/sdk/components/private/switch_client.hpp new file mode 100644 index 000000000..ce93b1200 --- /dev/null +++ b/src/viam/sdk/components/private/switch_client.hpp @@ -0,0 +1,43 @@ +/// @file components/private/switch_client.hpp +/// +/// @brief Implements a gRPC client for the `Switch` component +#pragma once + +#include + +#include + +#include + +namespace viam { +namespace sdk { +namespace impl { + +/// @class SwitchClient +/// @brief gRPC client implementation of a `Switch` component. +/// @ingroup Switch +class SwitchClient : public Switch { + public: + using interface_type = Switch; + SwitchClient(std::string name, std::shared_ptr channel); + + void set_position(uint32_t position, const ProtoStruct& extra) override; + uint32_t get_position(const ProtoStruct& extra) override; + uint32_t get_number_of_positions(const ProtoStruct& extra) override; + ProtoStruct do_command(const ProtoStruct& command) override; + + // Using declarations to introduce convenience overloads of interface which do not need to be + // passed the ProtoStruct parameter. + using Switch::get_number_of_positions; + using Switch::get_position; + using Switch::set_position; + + private: + using StubType = viam::component::switch_::v1::SwitchService::StubInterface; + std::unique_ptr stub_; + std::shared_ptr channel_; +}; + +} // namespace impl +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/private/switch_server.cpp b/src/viam/sdk/components/private/switch_server.cpp new file mode 100644 index 000000000..cd8262ee8 --- /dev/null +++ b/src/viam/sdk/components/private/switch_server.cpp @@ -0,0 +1,54 @@ +#include + +#include + +namespace viam { +namespace sdk { +namespace impl { + +SwitchServer::SwitchServer(std::shared_ptr manager) + : ResourceServer(std::move(manager)) {} + +::grpc::Status SwitchServer::SetPosition( + ::grpc::ServerContext*, + const ::viam::component::switch_::v1::SetPositionRequest* request, + ::viam::component::switch_::v1::SetPositionResponse*) noexcept { + return make_service_helper( + "SwitchServer::SetPosition", this, request)([&](auto& helper, auto& switch_) { + switch_->set_position(request->position(), helper.getExtra()); + }); +} + +::grpc::Status SwitchServer::GetPosition( + ::grpc::ServerContext*, + const ::viam::component::switch_::v1::GetPositionRequest* request, + ::viam::component::switch_::v1::GetPositionResponse* response) noexcept { + return make_service_helper( + "SwitchServer::GetPosition", this, request)([&](auto& helper, auto& switch_) { + response->set_position(switch_->get_position(helper.getExtra())); + }); +} + +::grpc::Status SwitchServer::GetNumberOfPositions( + ::grpc::ServerContext*, + const ::viam::component::switch_::v1::GetNumberOfPositionsRequest* request, + ::viam::component::switch_::v1::GetNumberOfPositionsResponse* response) noexcept { + return make_service_helper( + "SwitchServer::GetNumberOfPositions", this, request)([&](auto& helper, auto& switch_) { + response->set_number_of_positions(switch_->get_number_of_positions(helper.getExtra())); + }); +} + +::grpc::Status SwitchServer::DoCommand(::grpc::ServerContext*, + const ::viam::common::v1::DoCommandRequest* request, + ::viam::common::v1::DoCommandResponse* response) noexcept { + return make_service_helper( + "SwitchServer::DoCommand", this, request)([&](auto&, auto& switch_) { + const ProtoStruct result = switch_->do_command(from_proto(request->command())); + *response->mutable_result() = to_proto(result); + }); +} + +} // namespace impl +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/private/switch_server.hpp b/src/viam/sdk/components/private/switch_server.hpp new file mode 100644 index 000000000..dbf9691d3 --- /dev/null +++ b/src/viam/sdk/components/private/switch_server.hpp @@ -0,0 +1,50 @@ +/// @file components/private/switch_server.hpp +/// +/// @brief Implements a gRPC server for the `Switch` component +#pragma once + +#include +#include + +#include +#include +#include + +namespace viam { +namespace sdk { +namespace impl { + +/// @class SwitchServer +/// @brief gRPC server implementation of a `Switch` component. +/// @ingroup Switch +class SwitchServer : public ResourceServer, + public viam::component::switch_::v1::SwitchService::Service { + public: + using interface_type = Switch; + using service_type = component::switch_::v1::SwitchService; + + explicit SwitchServer(std::shared_ptr manager); + + ::grpc::Status SetPosition( + ::grpc::ServerContext* context, + const ::viam::component::switch_::v1::SetPositionRequest* request, + ::viam::component::switch_::v1::SetPositionResponse* response) noexcept override; + + ::grpc::Status GetPosition( + ::grpc::ServerContext* context, + const ::viam::component::switch_::v1::GetPositionRequest* request, + ::viam::component::switch_::v1::GetPositionResponse* response) noexcept override; + + ::grpc::Status GetNumberOfPositions( + ::grpc::ServerContext* context, + const ::viam::component::switch_::v1::GetNumberOfPositionsRequest* request, + ::viam::component::switch_::v1::GetNumberOfPositionsResponse* response) noexcept override; + + ::grpc::Status DoCommand(::grpc::ServerContext* context, + const ::viam::common::v1::DoCommandRequest* request, + ::viam::common::v1::DoCommandResponse* response) noexcept override; +}; + +} // namespace impl +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/switch.cpp b/src/viam/sdk/components/switch.cpp new file mode 100644 index 000000000..4c0a199cb --- /dev/null +++ b/src/viam/sdk/components/switch.cpp @@ -0,0 +1,19 @@ +#include + +#include + +namespace viam { +namespace sdk { + +API Switch::api() const { + return API::get(); +} + +API API::traits::api() { + return {kRDK, kComponent, "switch"}; +} + +Switch::Switch(std::string name) : Component(std::move(name)) {} + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/switch.hpp b/src/viam/sdk/components/switch.hpp new file mode 100644 index 000000000..453e99446 --- /dev/null +++ b/src/viam/sdk/components/switch.hpp @@ -0,0 +1,77 @@ +/// @file components/switch.hpp +/// +/// @brief Defines a `Switch` component +#pragma once + +#include + +#include + +#include +#include +#include + +namespace viam { +namespace sdk { + +/// @defgroup Switch Classes related to the Switch component. + +/// @class Switch switch.hpp "components/switch.hpp" +/// @brief A `Switch` represents a physical switch with multiple positions. +/// @ingroup Switch +/// +/// This acts as an abstract parent class to be inherited from by any drivers representing +/// specific switch implementations. This class cannot be used on its own. +class Switch : public Component { + public: + /// @brief Set the position of the switch. + /// @param position The position to set the switch to. + inline void set_position(uint32_t position) { + set_position(position, {}); + } + + /// @brief Set the position of the switch. + /// @param position The position to set the switch to. + /// @param extra Any additional arguments to the method. + virtual void set_position(uint32_t position, const ProtoStruct& extra) = 0; + + /// @brief Get the current position of the switch. + /// @return The current position of the switch. + inline uint32_t get_position() { + return get_position({}); + } + + /// @brief Get the current position of the switch. + /// @param extra Any additional arguments to the method. + /// @return The current position of the switch. + virtual uint32_t get_position(const ProtoStruct& extra) = 0; + + /// @brief Get the number of positions that the switch supports. + /// @return The number of positions that the switch supports. + inline uint32_t get_number_of_positions() { + return get_number_of_positions({}); + } + + /// @brief Get the number of positions that the switch supports. + /// @param extra Any additional arguments to the method. + /// @return The number of positions that the switch supports. + virtual uint32_t get_number_of_positions(const ProtoStruct& extra) = 0; + + /// @brief Send/receive arbitrary commands to the resource. + /// @param command The command to execute. + /// @return The result of the executed command. + virtual ProtoStruct do_command(const ProtoStruct& command) = 0; + + API api() const override; + + protected: + explicit Switch(std::string name); +}; + +template <> +struct API::traits { + static API api(); +}; + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index de74d314d..808e10c14 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -211,6 +213,7 @@ void Registry::register_resources() { register_resource(); register_resource(); register_resource(); + register_resource(); // Register all services register_resource(); diff --git a/src/viam/sdk/tests/CMakeLists.txt b/src/viam/sdk/tests/CMakeLists.txt index fa2d1560d..10e54db4d 100644 --- a/src/viam/sdk/tests/CMakeLists.txt +++ b/src/viam/sdk/tests/CMakeLists.txt @@ -36,6 +36,7 @@ target_sources(viamsdk_test mocks/mock_power_sensor.cpp mocks/mock_sensor.cpp mocks/mock_servo.cpp + mocks/mock_switch.cpp mocks/mock_robot.cpp test_utils.cpp ) @@ -74,4 +75,5 @@ viamcppsdk_add_boost_test(test_proto_value_visit.cpp) viamcppsdk_add_boost_test(test_resource.cpp) viamcppsdk_add_boost_test(test_sensor.cpp) viamcppsdk_add_boost_test(test_servo.cpp) +viamcppsdk_add_boost_test(test_switch.cpp) viamcppsdk_add_boost_test(test_robot.cpp) diff --git a/src/viam/sdk/tests/mocks/mock_switch.cpp b/src/viam/sdk/tests/mocks/mock_switch.cpp new file mode 100644 index 000000000..fa3fb7934 --- /dev/null +++ b/src/viam/sdk/tests/mocks/mock_switch.cpp @@ -0,0 +1,31 @@ +#include + +#include + +namespace viam { +namespace sdktests { +namespace switch_ { + +std::shared_ptr MockSwitch::get_mock_switch() { + return std::make_shared("mock_switch"); +} + +void MockSwitch::set_position(uint32_t position, const sdk::ProtoStruct&) { + current_position = position; +} + +uint32_t MockSwitch::get_position(const sdk::ProtoStruct&) { + return current_position; +} + +uint32_t MockSwitch::get_number_of_positions(const sdk::ProtoStruct&) { + return number_of_positions; +} + +sdk::ProtoStruct MockSwitch::do_command(const sdk::ProtoStruct& command) { + return (peek_command = command); +} + +} // namespace switch_ +} // namespace sdktests +} // namespace viam diff --git a/src/viam/sdk/tests/mocks/mock_switch.hpp b/src/viam/sdk/tests/mocks/mock_switch.hpp new file mode 100644 index 000000000..124406ce4 --- /dev/null +++ b/src/viam/sdk/tests/mocks/mock_switch.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace viam { +namespace sdktests { +namespace switch_ { + +class MockSwitch : public sdk::Switch { + public: + MockSwitch(std::string name) : Switch(std::move(name)) {} + + static std::shared_ptr get_mock_switch(); + + void set_position(uint32_t position, const sdk::ProtoStruct&) override; + uint32_t get_position(const sdk::ProtoStruct&) override; + uint32_t get_number_of_positions(const sdk::ProtoStruct&) override; + sdk::ProtoStruct do_command(const sdk::ProtoStruct& command) override; + + uint32_t current_position; + uint32_t number_of_positions; + sdk::ProtoStruct peek_command; +}; + +} // namespace switch_ +} // namespace sdktests +} // namespace viam diff --git a/src/viam/sdk/tests/test_switch.cpp b/src/viam/sdk/tests/test_switch.cpp new file mode 100644 index 000000000..a99479678 --- /dev/null +++ b/src/viam/sdk/tests/test_switch.cpp @@ -0,0 +1,62 @@ +#define BOOST_TEST_MODULE test module test_switch +#include + +#include + +#include +#include + +BOOST_TEST_DONT_PRINT_LOG_VALUE(viam::sdk::ProtoStruct) + +namespace viam { +namespace sdktests { + +using namespace switch_; + +using namespace viam::sdk; + +BOOST_AUTO_TEST_SUITE(test_switch) + +BOOST_AUTO_TEST_CASE(mock_get_api) { + const MockSwitch switch_("mock_switch"); + auto api = switch_.api(); + auto static_api = API::get(); + + BOOST_CHECK_EQUAL(api, static_api); + BOOST_CHECK_EQUAL(static_api.resource_subtype(), "switch"); +} + +BOOST_AUTO_TEST_CASE(test_positions) { + std::shared_ptr mock = MockSwitch::get_mock_switch(); + client_to_mock_pipeline(mock, [&](Switch& client) { + uint32_t position = 3; + client.set_position(position); + BOOST_CHECK_EQUAL(mock->current_position, position); + BOOST_CHECK_EQUAL(client.get_position(), position); + }); +} + +BOOST_AUTO_TEST_CASE(test_number_of_positions) { + std::shared_ptr mock = MockSwitch::get_mock_switch(); + client_to_mock_pipeline(mock, [&](Switch& client) { + mock->number_of_positions = 5; + BOOST_CHECK_EQUAL(client.get_number_of_positions(), 5); + }); +} + +BOOST_AUTO_TEST_CASE(test_do_command) { + std::shared_ptr mock = MockSwitch::get_mock_switch(); + client_to_mock_pipeline(mock, [](Switch& client) { + ProtoStruct expected = fake_map(); + + ProtoStruct command = fake_map(); + ProtoStruct result_map = client.do_command(command); + + BOOST_CHECK(result_map.at("test") == expected.at("test")); + }); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace sdktests +} // namespace viam From 13390021f7450538f3de7d3b55c824af0398c168 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:44:21 -0400 Subject: [PATCH 2/2] add s/switch/switch_/g step to proto custom command --- src/viam/api/CMakeLists.txt | 13 +++++++++++++ src/viam/api/viamcppsdk_replace_switch.cmake | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/viam/api/viamcppsdk_replace_switch.cmake diff --git a/src/viam/api/CMakeLists.txt b/src/viam/api/CMakeLists.txt index 3b23ba8ad..1daeb6919 100644 --- a/src/viam/api/CMakeLists.txt +++ b/src/viam/api/CMakeLists.txt @@ -113,6 +113,16 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS) ) endif() + # List of names of non-compilable generated code + # The Switch component generates protobuf which uses `switch` as a namespace. + # This needs to be processed below. + set(VIAMCPPSDK_SWITCH_REPLACE_PATHS + ${PROTO_GEN_DIR}/component/switch/v1/switch.grpc.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.grpc.pb.h + ${PROTO_GEN_DIR}/component/switch/v1/switch.pb.cc + ${PROTO_GEN_DIR}/component/switch/v1/switch.pb.h + ) + add_custom_command( OUTPUT # Unfortunately, there isn't a good way to know in advance what @@ -245,6 +255,9 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS) COMMAND ${BUF_COMMAND} generate ${BUF_GOOGLE_API_SOURCE} --template buf.gen.yaml --path google/rpc --path google/api COMMAND ${BUF_COMMAND} generate ${BUF_VIAM_GOUTILS_SOURCE} --template buf.gen.yaml COMMAND ${BUF_COMMAND} generate ${BUF_VIAM_API_SOURCE} --template buf.gen.yaml --path ${BUF_PROTO_COMPONENTS_JOINED} + + # After generating the protos, include a step to invoke a search-and-replace for switch -> switch_ in the Switch component files + COMMAND ${CMAKE_COMMAND} "-DSWITCH_REPLACE_PATHS=\"${VIAMCPPSDK_SWITCH_REPLACE_PATHS}\"" -P ${CMAKE_CURRENT_SOURCE_DIR}/viamcppsdk_replace_switch.cmake MAIN_DEPENDENCY buf.gen.yaml ) diff --git a/src/viam/api/viamcppsdk_replace_switch.cmake b/src/viam/api/viamcppsdk_replace_switch.cmake new file mode 100644 index 000000000..1815faaa3 --- /dev/null +++ b/src/viam/api/viamcppsdk_replace_switch.cmake @@ -0,0 +1,10 @@ +if (NOT SWITCH_REPLACE_PATHS) + message(FATAL_ERROR "Please provide SWITCH_REPLACE_PATHS argument to switch replace script") +endif() + +foreach(SOURCE ${SWITCH_REPLACE_PATHS}) + file(READ "${SOURCE}" _src_text) + string(REPLACE "namespace switch " "namespace switch_ " _src_text "${_src_text}") + string(REPLACE "::switch::" "::switch_::" _src_text "${_src_text}") + file(WRITE "${SOURCE}" "${_src_text}") +endforeach()