diff --git a/src/viam/api/CMakeLists.txt b/src/viam/api/CMakeLists.txt index 453831215..b0131e648 100644 --- a/src/viam/api/CMakeLists.txt +++ b/src/viam/api/CMakeLists.txt @@ -163,6 +163,10 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS) ${PROTO_GEN_DIR}/component/movementsensor/v1/movementsensor.grpc.pb.h ${PROTO_GEN_DIR}/component/movementsensor/v1/movementsensor.pb.cc ${PROTO_GEN_DIR}/component/movementsensor/v1/movementsensor.pb.h + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.grpc.pb.cc + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.grpc.pb.h + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.pb.cc + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.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 @@ -258,6 +262,8 @@ target_sources(viamapi ${PROTO_GEN_DIR}/component/motor/v1/motor.pb.cc ${PROTO_GEN_DIR}/component/movementsensor/v1/movementsensor.grpc.pb.cc ${PROTO_GEN_DIR}/component/movementsensor/v1/movementsensor.pb.cc + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.grpc.pb.cc + ${PROTO_GEN_DIR}/component/sensor/v1/sensor.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 @@ -295,6 +301,8 @@ target_sources(viamapi ${PROTO_GEN_DIR}/../../viam/api/component/motor/v1/motor.pb.h ${PROTO_GEN_DIR}/../../viam/api/component/movementsensor/v1/movementsensor.grpc.pb.h ${PROTO_GEN_DIR}/../../viam/api/component/movementsensor/v1/movementsensor.pb.h + ${PROTO_GEN_DIR}/../../viam/api/component/sensor/v1/sensor.grpc.pb.h + ${PROTO_GEN_DIR}/../../viam/api/component/sensor/v1/sensor.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 88330c663..99ee6afbc 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -71,6 +71,9 @@ target_sources(viamsdk components/movement_sensor/client.cpp components/movement_sensor/movement_sensor.cpp components/movement_sensor/server.cpp + components/sensor/client.cpp + components/sensor/sensor.cpp + components/sensor/server.cpp config/resource.cpp module/handler_map.cpp module/module.cpp @@ -127,6 +130,9 @@ target_sources(viamsdk ../../viam/sdk/components/movement_sensor/client.hpp ../../viam/sdk/components/movement_sensor/movement_sensor.hpp ../../viam/sdk/components/movement_sensor/server.hpp + ../../viam/sdk/components/sensor/client.hpp + ../../viam/sdk/components/sensor/sensor.hpp + ../../viam/sdk/components/sensor/server.hpp ../../viam/sdk/config/resource.hpp ../../viam/sdk/module/handler_map.hpp ../../viam/sdk/module/module.hpp diff --git a/src/viam/sdk/components/movement_sensor/client.hpp b/src/viam/sdk/components/movement_sensor/client.hpp index f76eb87fa..c79916238 100644 --- a/src/viam/sdk/components/movement_sensor/client.hpp +++ b/src/viam/sdk/components/movement_sensor/client.hpp @@ -1,4 +1,4 @@ -/// @file components/movementsensor/client.hpp +/// @file components/movement_sensor/client.hpp /// /// @brief Implements a gRPC client for the `MovementSensor` component. #pragma once diff --git a/src/viam/sdk/components/movement_sensor/movement_sensor.cpp b/src/viam/sdk/components/movement_sensor/movement_sensor.cpp index 6552076cb..77f5cfb40 100644 --- a/src/viam/sdk/components/movement_sensor/movement_sensor.cpp +++ b/src/viam/sdk/components/movement_sensor/movement_sensor.cpp @@ -14,36 +14,6 @@ namespace viam { namespace sdk { -// todo: move me somewhere central -template -class ResourceRegistration2 : public ResourceRegistration { - public: - using ResourceRegistration::ResourceRegistration; - std::shared_ptr create_resource_server( - std::shared_ptr manager) override { - return std::make_shared(manager); - } - - std::shared_ptr create_rpc_client(std::string name, - std::shared_ptr chan) override { - return std::make_shared(std::move(name), std::move(chan)); - } - - static std::shared_ptr resource_registration() { - const google::protobuf::DescriptorPool* p = - google::protobuf::DescriptorPool::generated_pool(); - const google::protobuf::ServiceDescriptor* sd = - p->FindServiceByName(ProtoServiceT::service_full_name()); - if (!sd) { - throw std::runtime_error("Unable to get service descriptor"); - } - return std::make_shared(sd); - } -}; - API MovementSensor::static_api() { return {kRDK, kComponent, "movement_sensor"}; } diff --git a/src/viam/sdk/components/movement_sensor/movement_sensor.hpp b/src/viam/sdk/components/movement_sensor/movement_sensor.hpp index 0044f27ce..50cd45687 100644 --- a/src/viam/sdk/components/movement_sensor/movement_sensor.hpp +++ b/src/viam/sdk/components/movement_sensor/movement_sensor.hpp @@ -1,4 +1,4 @@ -/// @file components/movementsensor/movementsensor.hpp +/// @file components/movement_sensor/movement_sensor.hpp /// /// @brief Defines a `MovementSensor` component. #pragma once @@ -21,7 +21,7 @@ namespace sdk { /// @defgroup MovementSensor Classes related to the MovementSensor component. -/// @class MovementSensor movementsensor.hpp "components/movementsensor/movementsensor.hpp" +/// @class MovementSensor movement_sensor.hpp "components/movement_sensor/movement_sensor.hpp" /// @ingroup MovementSensor /// /// This acts as an abstract base class to be inherited from by any drivers representing diff --git a/src/viam/sdk/components/movement_sensor/server.cpp b/src/viam/sdk/components/movement_sensor/server.cpp index e0ff0862f..8ac49ece4 100644 --- a/src/viam/sdk/components/movement_sensor/server.cpp +++ b/src/viam/sdk/components/movement_sensor/server.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -16,177 +17,129 @@ MovementSensorServer::MovementSensorServer() MovementSensorServer::MovementSensorServer(std::shared_ptr manager) : ResourceServer(manager){}; -::grpc::Status MovementSensorServer::GetLinearVelocity(::grpc::ServerContext* context, - const GetLinearVelocityRequest* request, - GetLinearVelocityResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - Vector3 result = status.movementsensor->get_linear_velocity(status.extra); - *response->mutable_linear_velocity() = Vector3::to_proto(result); - - return ::grpc::Status(); +::grpc::Status MovementSensorServer::GetLinearVelocity( + ::grpc::ServerContext* context, + const GetLinearVelocityRequest* request, + GetLinearVelocityResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetLinearVelocity", + this, + request)([&](auto& helper, auto& movementsensor) { + const Vector3 result = movementsensor->get_linear_velocity(helper.getExtra()); + *response->mutable_linear_velocity() = Vector3::to_proto(result); + }); } -::grpc::Status MovementSensorServer::GetAngularVelocity(::grpc::ServerContext* context, - const GetAngularVelocityRequest* request, - GetAngularVelocityResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - Vector3 result = status.movementsensor->get_angular_velocity(status.extra); - *response->mutable_angular_velocity() = Vector3::to_proto(result); - - return ::grpc::Status(); +::grpc::Status MovementSensorServer::GetAngularVelocity( + ::grpc::ServerContext* context, + const GetAngularVelocityRequest* request, + GetAngularVelocityResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetAngularVelocity", + this, + request)([&](auto& helper, auto& movementsensor) { + const Vector3 result = movementsensor->get_angular_velocity(helper.getExtra()); + *response->mutable_angular_velocity() = Vector3::to_proto(result); + }); } -::grpc::Status MovementSensorServer::GetCompassHeading(::grpc::ServerContext* context, - const GetCompassHeadingRequest* request, - GetCompassHeadingResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - MovementSensor::compassheading result = - status.movementsensor->get_compass_heading(status.extra); - response->set_value(result.value); - - return ::grpc::Status(); +::grpc::Status MovementSensorServer::GetCompassHeading( + ::grpc::ServerContext* context, + const GetCompassHeadingRequest* request, + GetCompassHeadingResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetCompassHeading", + this, + request)([&](auto& helper, auto& movementsensor) { + const MovementSensor::compassheading result = + movementsensor->get_compass_heading(helper.getExtra()); + response->set_value(result.value); + }); } ::grpc::Status MovementSensorServer::GetOrientation(::grpc::ServerContext* context, const GetOrientationRequest* request, - GetOrientationResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - MovementSensor::orientation result = status.movementsensor->get_orientation(status.extra); - *response->mutable_orientation() = MovementSensor::to_proto(result); - - return ::grpc::Status(); + GetOrientationResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetOrientation", + this, + request)([&](auto& helper, auto& movementsensor) { + const MovementSensor::orientation result = + movementsensor->get_orientation(helper.getExtra()); + *response->mutable_orientation() = MovementSensor::to_proto(result); + }); } ::grpc::Status MovementSensorServer::GetPosition(::grpc::ServerContext* context, const GetPositionRequest* request, - GetPositionResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - MovementSensor::position result = status.movementsensor->get_position(status.extra); - *response->mutable_coordinate() = result.coordinate.to_proto(); - response->set_altitude_m(result.altitude_m); - - return ::grpc::Status(); + GetPositionResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetPosition", this, request)( + [&](auto& helper, auto& movementsensor) { + const MovementSensor::position result = movementsensor->get_position(helper.getExtra()); + *response->mutable_coordinate() = result.coordinate.to_proto(); + response->set_altitude_m(result.altitude_m); + }); } ::grpc::Status MovementSensorServer::GetProperties(::grpc::ServerContext* context, const GetPropertiesRequest* request, - GetPropertiesResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - MovementSensor::properties result = status.movementsensor->get_properties(status.extra); - response->set_linear_velocity_supported(result.linear_velocity_supported); - response->set_angular_velocity_supported(result.angular_velocity_supported); - response->set_orientation_supported(result.orientation_supported); - response->set_position_supported(result.position_supported); - response->set_compass_heading_supported(result.compass_heading_supported); - response->set_linear_acceleration_supported(result.linear_acceleration_supported); - - return ::grpc::Status(); + GetPropertiesResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetProperties", + this, + request)([&](auto& helper, auto& movementsensor) { + const MovementSensor::properties result = movementsensor->get_properties(helper.getExtra()); + response->set_linear_velocity_supported(result.linear_velocity_supported); + response->set_angular_velocity_supported(result.angular_velocity_supported); + response->set_orientation_supported(result.orientation_supported); + response->set_position_supported(result.position_supported); + response->set_compass_heading_supported(result.compass_heading_supported); + response->set_linear_acceleration_supported(result.linear_acceleration_supported); + }); } ::grpc::Status MovementSensorServer::GetAccuracy(::grpc::ServerContext* context, const GetAccuracyRequest* request, - GetAccuracyResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - std::unordered_map result = - status.movementsensor->get_accuracy(status.extra); - response->mutable_accuracy()->empty(); - for (const auto& i : result) { - response->mutable_accuracy()->insert({i.first, i.second}); - } - - return ::grpc::Status(); + GetAccuracyResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetAccuracy", this, request)( + [&](auto& helper, auto& movementsensor) { + const auto result = movementsensor->get_accuracy(helper.getExtra()); + for (const auto& i : result) { + response->mutable_accuracy()->insert({i.first, i.second}); + } + }); } ::grpc::Status MovementSensorServer::GetLinearAcceleration( ::grpc::ServerContext* context, const GetLinearAccelerationRequest* request, - GetLinearAccelerationResponse* response) { - const auto status = server_wrapper(request); - if (!status.ok()) { - return status.status; - } - - Vector3 result = status.movementsensor->get_linear_acceleration(status.extra); - *response->mutable_linear_acceleration() = Vector3::to_proto(result); - - return ::grpc::Status(); + GetLinearAccelerationResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetLinearAcceleration", + this, + request)([&](auto& helper, auto& movementsensor) { + const Vector3 result = movementsensor->get_linear_acceleration(helper.getExtra()); + *response->mutable_linear_acceleration() = Vector3::to_proto(result); + }); } -::grpc::Status MovementSensorServer::DoCommand(grpc::ServerContext* context, - const viam::common::v1::DoCommandRequest* request, - viam::common::v1::DoCommandResponse* response) { - if (!request) { - return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, - "Called [MovementSensor::DoCommand] without a request"); - }; - - auto rb = resource_manager()->resource(request->name()); - if (!rb) { - return grpc::Status(grpc::UNKNOWN, "resource not found: " + request->name()); - } - - const std::shared_ptr sensor = std::dynamic_pointer_cast(rb); - const AttributeMap result = sensor->do_command(struct_to_map(request->command())); - - *response->mutable_result() = map_to_struct(result); - - return ::grpc::Status(); +::grpc::Status MovementSensorServer::DoCommand( + grpc::ServerContext* context, + const viam::common::v1::DoCommandRequest* request, + viam::common::v1::DoCommandResponse* response) noexcept { + return make_service_helper( + "MovementSensorServer::DoCommand", this, request)([&](auto& helper, auto& movementsensor) { + const AttributeMap result = movementsensor->do_command(struct_to_map(request->command())); + *response->mutable_result() = map_to_struct(result); + }); } ::grpc::Status MovementSensorServer::GetGeometries( ::grpc::ServerContext* context, const ::viam::common::v1::GetGeometriesRequest* request, - ::viam::common::v1::GetGeometriesResponse* response) { - if (!request) { - return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, - "Called [MovementSensor::GetGeometries] without a request"); - }; - - const std::shared_ptr rb = resource_manager()->resource(request->name()); - if (!rb) { - return grpc::Status(grpc::UNKNOWN, "resource not found: " + request->name()); - } - - AttributeMap extra; - if (request->has_extra()) { - extra = struct_to_map(request->extra()); - } - - const std::shared_ptr sensor = std::dynamic_pointer_cast(rb); - const std::vector geometries = sensor->get_geometries(extra); - for (const auto& geometry : geometries) { - *response->mutable_geometries()->Add() = geometry.to_proto(); - } - - return ::grpc::Status(); + ::viam::common::v1::GetGeometriesResponse* response) noexcept { + return make_service_helper("MovementSensorServer::GetGeometries", + this, + request)([&](auto& helper, auto& movementsensor) { + const auto geometries = movementsensor->get_geometries(helper.getExtra()); + for (const auto& geometry : geometries) { + *response->mutable_geometries()->Add() = geometry.to_proto(); + } + }); } void MovementSensorServer::register_server(std::shared_ptr server) { diff --git a/src/viam/sdk/components/movement_sensor/server.hpp b/src/viam/sdk/components/movement_sensor/server.hpp index ba00d8e34..c006bbe92 100644 --- a/src/viam/sdk/components/movement_sensor/server.hpp +++ b/src/viam/sdk/components/movement_sensor/server.hpp @@ -1,4 +1,4 @@ -/// @file components/movementsensor/server.hpp +/// @file components/movement_sensor/server.hpp /// /// @brief Implements a gRPC server for the `MovementSensor` component. #pragma once @@ -25,85 +25,57 @@ class MovementSensorServer ::grpc::Status GetLinearVelocity( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetLinearVelocityRequest* request, - ::viam::component::movementsensor::v1::GetLinearVelocityResponse* response) override; + ::viam::component::movementsensor::v1::GetLinearVelocityResponse* response) noexcept + override; ::grpc::Status GetAngularVelocity( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetAngularVelocityRequest* request, - ::viam::component::movementsensor::v1::GetAngularVelocityResponse* response) override; + ::viam::component::movementsensor::v1::GetAngularVelocityResponse* response) noexcept + override; ::grpc::Status GetCompassHeading( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetCompassHeadingRequest* request, - ::viam::component::movementsensor::v1::GetCompassHeadingResponse* response) override; + ::viam::component::movementsensor::v1::GetCompassHeadingResponse* response) noexcept + override; ::grpc::Status GetOrientation( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetOrientationRequest* request, - ::viam::component::movementsensor::v1::GetOrientationResponse* response) override; + ::viam::component::movementsensor::v1::GetOrientationResponse* response) noexcept override; ::grpc::Status GetPosition( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetPositionRequest* request, - ::viam::component::movementsensor::v1::GetPositionResponse* response) override; + ::viam::component::movementsensor::v1::GetPositionResponse* response) noexcept override; ::grpc::Status GetProperties( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetPropertiesRequest* request, - ::viam::component::movementsensor::v1::GetPropertiesResponse* response) override; + ::viam::component::movementsensor::v1::GetPropertiesResponse* response) noexcept override; ::grpc::Status GetAccuracy( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetAccuracyRequest* request, - ::viam::component::movementsensor::v1::GetAccuracyResponse* response) override; + ::viam::component::movementsensor::v1::GetAccuracyResponse* response) noexcept override; ::grpc::Status GetLinearAcceleration( ::grpc::ServerContext* context, const ::viam::component::movementsensor::v1::GetLinearAccelerationRequest* request, - ::viam::component::movementsensor::v1::GetLinearAccelerationResponse* response) override; + ::viam::component::movementsensor::v1::GetLinearAccelerationResponse* response) noexcept + override; ::grpc::Status DoCommand(::grpc::ServerContext* context, const viam::common::v1::DoCommandRequest* request, - viam::common::v1::DoCommandResponse* response) override; + viam::common::v1::DoCommandResponse* response) noexcept override; - ::grpc::Status GetGeometries(::grpc::ServerContext* context, - const ::viam::common::v1::GetGeometriesRequest* request, - ::viam::common::v1::GetGeometriesResponse* response) override; + ::grpc::Status GetGeometries( + ::grpc::ServerContext* context, + const ::viam::common::v1::GetGeometriesRequest* request, + ::viam::common::v1::GetGeometriesResponse* response) noexcept override; void register_server(std::shared_ptr server) override; - - private: - template - struct ServerWrapperResult { - ::grpc::Status status; - AttributeMap extra; - std::shared_ptr movementsensor; - - bool ok() const { - return status.ok(); - } - }; - - // wrapper template for boilerplate - template - ServerWrapperResult server_wrapper(const Req* request) { - if (!request) { - auto status = ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, - "Called MovementSensorServer method without a request"); - return ServerWrapperResult{status}; - }; - const std::shared_ptr rb = resource_manager()->resource(request->name()); - if (!rb) { - auto status = grpc::Status(grpc::UNKNOWN, "resource not found: " + request->name()); - return ServerWrapperResult{status}; - } - ServerWrapperResult ret; - ret.movementsensor = std::dynamic_pointer_cast(rb); - if (request->has_extra()) { - ret.extra = struct_to_map(request->extra()); - } - return ret; - } }; } // namespace sdk diff --git a/src/viam/sdk/components/sensor/client.cpp b/src/viam/sdk/components/sensor/client.cpp new file mode 100644 index 000000000..aeaa5ec7f --- /dev/null +++ b/src/viam/sdk/components/sensor/client.cpp @@ -0,0 +1,62 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace viam { +namespace sdk { + +SensorClient::SensorClient(std::string name, std::shared_ptr channel) + : Sensor(std::move(name)), + stub_(viam::component::sensor::v1::SensorService::NewStub(channel)), + channel_(std::move(channel)){}; + +using namespace viam::common::v1; + +AttributeMap SensorClient::get_readings(const AttributeMap& extra) { + GetReadingsResponse response; + stub_wrapper(this, response, {}, &SensorClient::Stub::GetReadings); + + AttributeMap result = + std::make_shared>>(); + for (const auto& r : response.readings()) { + result->emplace(std::move(r.first), std::make_shared(r.second)); + } + return result; +} + +AttributeMap SensorClient::do_command(const AttributeMap& command) { + DoCommandRequest request; + DoCommandResponse response; + + grpc::ClientContext ctx; + + const google::protobuf::Struct proto_command = map_to_struct(command); + *request.mutable_command() = proto_command; + *request.mutable_name() = this->name(); + + const auto status = stub_->DoCommand(&ctx, request, &response); + if (!status.ok()) { + throw std::runtime_error(status.error_message()); + } + return struct_to_map(response.result()); +} + +std::vector SensorClient::get_geometries(const AttributeMap& extra) { + GetGeometriesResponse resp; + stub_wrapper(this, resp, extra, &SensorClient::Stub::GetGeometries); + return GeometryConfig::from_proto(resp); +} + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/sensor/client.hpp b/src/viam/sdk/components/sensor/client.hpp new file mode 100644 index 000000000..80d3cea06 --- /dev/null +++ b/src/viam/sdk/components/sensor/client.hpp @@ -0,0 +1,55 @@ +/// @file components/sensor/client.hpp +/// +/// @brief Implements a gRPC client for the `Sensor` component. +#pragma once + +#include + +#include + +#include +#include +#include + +namespace viam { +namespace sdk { + +/// @class SensorClient +/// @brief gRPC client implementation of a `Sensor` component. +/// @ingroup Sensor +class SensorClient : public Sensor { + public: + SensorClient(std::string name, std::shared_ptr channel); + AttributeMap get_readings(const AttributeMap& extra) override; + AttributeMap do_command(const AttributeMap& command) override; + std::vector get_geometries(const AttributeMap& extra) override; + + using Sensor::get_geometries; + using Sensor::get_readings; + + typedef viam::component::sensor::v1::SensorService::StubInterface Stub; + + private: + // template to wrap a stub + template + void stub_wrapper(Cls* self, + Response& resp, + const AttributeMap& extra, + ::grpc::Status (Cls::Stub::*method)(::grpc::ClientContext*, + const Request&, + Response*)) { + Request request; + grpc::ClientContext ctx; + *request.mutable_name() = self->name(); + *request.mutable_extra() = map_to_struct(extra); + const auto status = (*(self->stub_).*method)(&ctx, request, &resp); + if (!status.ok()) { + throw std::runtime_error(status.error_message()); + } + } + std::unique_ptr stub_; + std::shared_ptr channel_; +}; + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/sensor/sensor.cpp b/src/viam/sdk/components/sensor/sensor.cpp new file mode 100644 index 000000000..f444df10e --- /dev/null +++ b/src/viam/sdk/components/sensor/sensor.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include + +#include +#include +#include +#include + +namespace viam { +namespace sdk { + +API Sensor::static_api() { + return {kRDK, kComponent, "sensor"}; +} + +API Sensor::dynamic_api() const { + return static_api(); +} + +namespace { +class SensorRegistration final + : public ResourceRegistration2 { + public: + using ResourceRegistration2::ResourceRegistration2; +}; + +bool init() { + Registry::register_resource(Sensor::static_api(), SensorRegistration::resource_registration()); + return true; +}; + +// NOLINTNEXTLINE(cert-err58-cpp) +const bool inited = init(); +} // namespace + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/sensor/sensor.hpp b/src/viam/sdk/components/sensor/sensor.hpp new file mode 100644 index 000000000..ef0796fba --- /dev/null +++ b/src/viam/sdk/components/sensor/sensor.hpp @@ -0,0 +1,64 @@ +/// @file components/sensor/sensor.hpp +/// +/// @brief Defines a `Sensor` component. +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace viam { +namespace sdk { + +/// @defgroup Sensor Classes related to the Sensor component. + +/// @class Sensor sensor.hpp "components/sensor/sensor.hpp" +/// @ingroup Sensor +/// +/// This acts as an abstract base class to be inherited from by any drivers representing +/// specific sensor implementations. This class cannot be used on its own. +class Sensor : public Component { + public: + static API static_api(); + API dynamic_api() const override; + + /// @brief Send/receive arbitrary commands to the resource. + /// @param Command the command to execute. + /// @return The result of the executed command. + virtual AttributeMap do_command(const AttributeMap& command) = 0; + + /// @brief Returns `GeometryConfig`s associated with the calling sensor. + /// @return The requested `GeometryConfig`s associated with the component. + inline std::vector get_geometries() { + return get_geometries({}); + } + + /// @brief Returns `GeometryConfig`s associated with the calling sensor. + /// @param extra Any additional arguments to the method. + /// @return The requested `GeometryConfig`s associated with the component. + virtual std::vector get_geometries(const AttributeMap& extra) = 0; + + /// @brief Returns the measurements/data specific to this sensor. + /// @return The requested measurements/data specific to this sensor. + inline AttributeMap get_readings() { + return get_readings({}); + } + + /// @brief Returns the measurements/data specific to this sensor. + /// @param extra Any additional arguments to the method. + /// @return The requested measurements/data specific to this sensor. + virtual AttributeMap get_readings(const AttributeMap& extra) = 0; + + protected: + explicit Sensor(std::string name) : Component(std::move(name)){}; +}; + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/sensor/server.cpp b/src/viam/sdk/components/sensor/server.cpp new file mode 100644 index 000000000..1f66f57c1 --- /dev/null +++ b/src/viam/sdk/components/sensor/server.cpp @@ -0,0 +1,56 @@ +#include + +#include +#include +#include +#include +#include + +using namespace viam::common::v1; + +namespace viam { +namespace sdk { + +SensorServer::SensorServer() : ResourceServer(std::make_shared()){}; +SensorServer::SensorServer(std::shared_ptr manager) : ResourceServer(manager){}; + +::grpc::Status SensorServer::GetReadings(::grpc::ServerContext* context, + const GetReadingsRequest* request, + GetReadingsResponse* response) noexcept { + return make_service_helper( + "SensorServer::GetReadings", this, request)([&](auto& helper, auto& sensor) { + const AttributeMap result = sensor->get_readings(helper.getExtra()); + for (const auto& r : *result) { + response->mutable_readings()->insert({r.first, r.second->proto_value()}); + } + }); +} + +::grpc::Status SensorServer::DoCommand(grpc::ServerContext* context, + const DoCommandRequest* request, + DoCommandResponse* response) noexcept { + return make_service_helper( + "SensorServer::DoCommand", this, request)([&](auto& helper, auto& sensor) { + const AttributeMap result = sensor->do_command(struct_to_map(request->command())); + *response->mutable_result() = map_to_struct(result); + }); +} + +::grpc::Status SensorServer::GetGeometries(::grpc::ServerContext* context, + const GetGeometriesRequest* request, + GetGeometriesResponse* response) noexcept { + return make_service_helper( + "SensorServer::GetGeometries", this, request)([&](auto& helper, auto& sensor) { + const auto geometries = sensor->get_geometries(helper.getExtra()); + for (const auto& geometry : geometries) { + *response->mutable_geometries()->Add() = geometry.to_proto(); + } + }); +} + +void SensorServer::register_server(std::shared_ptr server) { + server->register_service(this); +} + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/components/sensor/server.hpp b/src/viam/sdk/components/sensor/server.hpp new file mode 100644 index 000000000..0c48a67ea --- /dev/null +++ b/src/viam/sdk/components/sensor/server.hpp @@ -0,0 +1,42 @@ +/// @file components/sensor/server.hpp +/// +/// @brief Implements a gRPC server for the `Sensor` component. +#pragma once + +#include +#include + +#include +#include + +using namespace viam::common::v1; + +namespace viam { +namespace sdk { + +/// @class SensorServer +/// @brief gRPC server implementation of a `Sensor` component. +/// @ingroup Sensor +class SensorServer : public ResourceServer, + public viam::component::sensor::v1::SensorService::Service { + public: + SensorServer(); + explicit SensorServer(std::shared_ptr manager); + + ::grpc::Status GetReadings(::grpc::ServerContext* context, + const GetReadingsRequest* request, + GetReadingsResponse* response) noexcept override; + + ::grpc::Status DoCommand(::grpc::ServerContext* context, + const DoCommandRequest* request, + DoCommandResponse* response) noexcept override; + + ::grpc::Status GetGeometries(::grpc::ServerContext* context, + const GetGeometriesRequest* request, + GetGeometriesResponse* response) noexcept override; + + void register_server(std::shared_ptr server) override; +}; + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index 9c99db5bf..e573c6665 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -58,6 +58,37 @@ class ResourceRegistration { const google::protobuf::ServiceDescriptor* service_descriptor_; }; +// TODO(RSDK-3030): Potentially make ResourceRegistration2 the one and only +// form of resource registration. +template +class ResourceRegistration2 : public ResourceRegistration { + public: + using ResourceRegistration::ResourceRegistration; + std::shared_ptr create_resource_server( + std::shared_ptr manager) override { + return std::make_shared(manager); + } + + std::shared_ptr create_rpc_client(std::string name, + std::shared_ptr chan) override { + return std::make_shared(std::move(name), std::move(chan)); + } + + static std::shared_ptr resource_registration() { + const google::protobuf::DescriptorPool* p = + google::protobuf::DescriptorPool::generated_pool(); + const google::protobuf::ServiceDescriptor* sd = + p->FindServiceByName(ProtoServiceT::service_full_name()); + if (!sd) { + throw std::runtime_error("Unable to get service descriptor"); + } + return std::make_shared(sd); + } +}; + /// @class ModelRegistration /// @brief Information about a registered model, including a constructor and config validator. class ModelRegistration { diff --git a/src/viam/sdk/tests/CMakeLists.txt b/src/viam/sdk/tests/CMakeLists.txt index 2bad24fb8..ae873406c 100644 --- a/src/viam/sdk/tests/CMakeLists.txt +++ b/src/viam/sdk/tests/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources(viamsdk_test mocks/mock_motor.cpp mocks/mock_motion.cpp mocks/mock_movement_sensor.cpp + mocks/mock_sensor.cpp mocks/mock_robot.cpp test_utils.cpp ) @@ -46,5 +47,6 @@ viamcppsdk_add_boost_test(test_mlmodel.cpp) viamcppsdk_add_boost_test(test_motor.cpp) viamcppsdk_add_boost_test(test_motion.cpp) viamcppsdk_add_boost_test(test_movement_sensor.cpp) +viamcppsdk_add_boost_test(test_sensor.cpp) viamcppsdk_add_boost_test(test_robot.cpp) viamcppsdk_add_boost_test(test_types.cpp) diff --git a/src/viam/sdk/tests/mocks/mock_movement_sensor.cpp b/src/viam/sdk/tests/mocks/mock_movement_sensor.cpp index 8ee15e82f..c8dbc8050 100644 --- a/src/viam/sdk/tests/mocks/mock_movement_sensor.cpp +++ b/src/viam/sdk/tests/mocks/mock_movement_sensor.cpp @@ -43,7 +43,7 @@ AttributeMap MockMovementSensor::do_command(const AttributeMap& command) { return command; }; std::vector MockMovementSensor::get_geometries(const AttributeMap& extra) { - return std::vector(); + return fake_geometries(); }; std::shared_ptr MockMovementSensor::get_mock_movementsensor() { diff --git a/src/viam/sdk/tests/mocks/mock_movement_sensor.hpp b/src/viam/sdk/tests/mocks/mock_movement_sensor.hpp index 73fd55005..46a017b32 100644 --- a/src/viam/sdk/tests/mocks/mock_movement_sensor.hpp +++ b/src/viam/sdk/tests/mocks/mock_movement_sensor.hpp @@ -30,7 +30,6 @@ class MockMovementSensor : public sdk::MovementSensor { // These variables allow the testing infra to `peek` into the mock // and ensure that the correct values were passed - // sdk::Vector3 peek_return_vec; sdk::MovementSensor::compassheading peek_compass_heading; sdk::MovementSensor::orientation peek_orientation; diff --git a/src/viam/sdk/tests/mocks/mock_sensor.cpp b/src/viam/sdk/tests/mocks/mock_sensor.cpp new file mode 100644 index 000000000..c93e055e0 --- /dev/null +++ b/src/viam/sdk/tests/mocks/mock_sensor.cpp @@ -0,0 +1,34 @@ +#include + +#include +#include +#include + +#include +#include +#include + +namespace viam { +namespace sdktests { +namespace sensor { + +using namespace viam::sdk; + +AttributeMap MockSensor::get_readings(const AttributeMap& extra) { + return fake_map(); +}; +AttributeMap MockSensor::do_command(const AttributeMap& command) { + return command; +}; +std::vector MockSensor::get_geometries(const AttributeMap& extra) { + return fake_geometries(); +}; + +std::shared_ptr MockSensor::get_mock_sensor() { + auto sensor = std::make_shared("mock_sensor"); + return sensor; +} + +} // namespace sensor +} // namespace sdktests +} // namespace viam diff --git a/src/viam/sdk/tests/mocks/mock_sensor.hpp b/src/viam/sdk/tests/mocks/mock_sensor.hpp new file mode 100644 index 000000000..8dc4a27d6 --- /dev/null +++ b/src/viam/sdk/tests/mocks/mock_sensor.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace viam { +namespace sdktests { +namespace sensor { + +class MockSensor : public sdk::Sensor { + public: + sdk::AttributeMap get_readings(const sdk::AttributeMap& extra) override; + sdk::AttributeMap do_command(const sdk::AttributeMap& command) override; + static std::shared_ptr get_mock_sensor(); + std::vector get_geometries(const sdk::AttributeMap& extra) override; + + MockSensor(std::string name) : Sensor(std::move(name)){}; +}; + +} // namespace sensor +} // namespace sdktests +} // namespace viam diff --git a/src/viam/sdk/tests/test_movement_sensor.cpp b/src/viam/sdk/tests/test_movement_sensor.cpp index f6f49a9c6..5597fcd91 100644 --- a/src/viam/sdk/tests/test_movement_sensor.cpp +++ b/src/viam/sdk/tests/test_movement_sensor.cpp @@ -173,6 +173,15 @@ BOOST_AUTO_TEST_CASE(test_do_command) { }); } +BOOST_AUTO_TEST_CASE(test_get_geometries) { + server_to_mock_pipeline( + [](MovementSensor& client, std::shared_ptr mock) -> void { + std::vector expected = fake_geometries(); + std::vector geometries = client.get_geometries(); + BOOST_CHECK(expected == geometries); + }); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace sdktests diff --git a/src/viam/sdk/tests/test_sensor.cpp b/src/viam/sdk/tests/test_sensor.cpp new file mode 100644 index 000000000..66199aec7 --- /dev/null +++ b/src/viam/sdk/tests/test_sensor.cpp @@ -0,0 +1,109 @@ +#define BOOST_TEST_MODULE test module test_sensor +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +BOOST_TEST_DONT_PRINT_LOG_VALUE(std::vector) + +namespace viam { +namespace sdktests { + +using namespace sensor; + +using namespace viam::sdk; + +BOOST_AUTO_TEST_SUITE(test_sensor) + +// This sets up the following architecture +// -- MockComponent +// /\ +// +// | (function calls) +// +// \/ +// -- ComponentServer (Real) +// /\ +// +// | (grpc InProcessChannel) +// +// \/ +// -- ComponentClient (Real) +// +// This is as close to a real setup as we can get +// without starting another process +// +// The passed in lambda function has access to the ComponentClient +// +template +void server_to_mock_pipeline(Lambda&& func) { + SensorServer sensor_server; + std::shared_ptr mock = MockSensor::get_mock_sensor(); + sensor_server.resource_manager()->add(std::string("mock_sensor"), mock); + + grpc::ServerBuilder builder; + builder.RegisterService(&sensor_server); + + std::unique_ptr server = builder.BuildAndStart(); + + grpc::ChannelArguments args; + auto grpc_channel = server->InProcessChannel(args); + SensorClient client("mock_sensor", grpc_channel); + // Run the passed test on the created stack + std::forward(func)(client, mock); + // shutdown afterwards + server->Shutdown(); +} + +BOOST_AUTO_TEST_CASE(test_get_readings) { + server_to_mock_pipeline([](Sensor& client, std::shared_ptr mock) -> void { + AttributeMap expected = fake_map(); + + AttributeMap readings = client.get_readings(); + + ProtoType expected_pt = *(expected->at(std::string("test"))); + ProtoType result_pt = *(readings->at(std::string("test"))); + BOOST_CHECK(result_pt == expected_pt); + }); +} + +BOOST_AUTO_TEST_CASE(test_do_command) { + server_to_mock_pipeline([](Sensor& client, std::shared_ptr mock) -> void { + AttributeMap expected = fake_map(); + + AttributeMap command = fake_map(); + AttributeMap result_map = client.do_command(command); + + ProtoType expected_pt = *(expected->at(std::string("test"))); + ProtoType result_pt = *(result_map->at(std::string("test"))); + BOOST_CHECK(result_pt == expected_pt); + }); +} + +BOOST_AUTO_TEST_CASE(test_get_geometries) { + server_to_mock_pipeline([](Sensor& client, std::shared_ptr mock) -> void { + std::vector expected = fake_geometries(); + std::vector geometries = client.get_geometries(); + BOOST_CHECK(expected == geometries); + }); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace sdktests +} // namespace viam