diff options
Diffstat (limited to 'pw_digital_io')
-rw-r--r-- | pw_digital_io/Android.bp | 53 | ||||
-rw-r--r-- | pw_digital_io/BUILD.bazel | 35 | ||||
-rw-r--r-- | pw_digital_io/BUILD.gn | 16 | ||||
-rw-r--r-- | pw_digital_io/CMakeLists.txt | 3 | ||||
-rw-r--r-- | pw_digital_io/digital_io.proto | 55 | ||||
-rw-r--r-- | pw_digital_io/digital_io_service.cc | 104 | ||||
-rw-r--r-- | pw_digital_io/docs.rst | 44 | ||||
-rw-r--r-- | pw_digital_io/public/pw_digital_io/digital_io.h | 328 | ||||
-rw-r--r-- | pw_digital_io/public/pw_digital_io/digital_io_service.h | 54 |
9 files changed, 524 insertions, 168 deletions
diff --git a/pw_digital_io/Android.bp b/pw_digital_io/Android.bp new file mode 100644 index 000000000..25a34ef6a --- /dev/null +++ b/pw_digital_io/Android.bp @@ -0,0 +1,53 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +package { + default_applicable_licenses: ["external_pigweed_license"], +} + +genrule { + name: "pw_digital_io_proto_with_prefix", + defaults: ["pw_rpc_add_prefix_to_proto"], + srcs: [ "digital_io.proto" ], + out: [ "pw_digital_io/digital_io.proto" ], +} + +genrule { + name: "pw_digital_io_pwpb_rpc_header", + defaults: ["pw_rpc_generate_pwpb_rpc_header_with_prefix"], + srcs: [":pw_digital_io_proto_with_prefix"], + out: ["pw_digital_io/digital_io.rpc.pwpb.h"], +} + +genrule { + name: "pw_digital_io_pwpb_proto_header", + defaults: ["pw_rpc_generate_pwpb_proto_with_prefix"], + srcs: [":pw_digital_io_proto_with_prefix"], + out: ["pw_digital_io/digital_io.pwpb.h"], +} + +cc_library_headers { + name: "pw_digital_io_service_pwpb_headers", + cpp_std: "c++20", + vendor_available: true, + host_supported: true, + generated_headers: [ + "pw_digital_io_pwpb_proto_header", + "pw_digital_io_pwpb_rpc_header", + ], + export_generated_headers: [ + "pw_digital_io_pwpb_proto_header", + "pw_digital_io_pwpb_rpc_header", + ], +} diff --git a/pw_digital_io/BUILD.bazel b/pw_digital_io/BUILD.bazel index a4632a5e9..5ccd45e5e 100644 --- a/pw_digital_io/BUILD.bazel +++ b/pw_digital_io/BUILD.bazel @@ -17,6 +17,10 @@ load( "pw_cc_library", "pw_cc_test", ) +load( + "//pw_protobuf_compiler:pw_proto_library.bzl", + "pw_proto_library", +) package(default_visibility = ["//visibility:public"]) @@ -46,3 +50,34 @@ pw_cc_test( "//pw_unit_test", ], ) + +pw_cc_library( + name = "digital_io_controller", + hdrs = ["public/pw_digital_io/digital_io_controller.h"], + includes = ["public"], +) + +pw_cc_library( + name = "digital_io_service", + srcs = ["digital_io_service.cc"], + hdrs = ["public/pw_digital_io/digital_io_service.h"], + includes = ["public"], + deps = [ + ":digital_io_proto_cc.pwpb", + ":digital_io_proto_cc.pwpb_rpc", + ":pw_digital_io", + "//pw_function", + "//pw_rpc/pwpb:server_api", + "//pw_span", + ], +) + +proto_library( + name = "digital_io_proto", + srcs = ["digital_io.proto"], +) + +pw_proto_library( + name = "digital_io_proto_cc", + deps = [":digital_io_proto"], +) diff --git a/pw_digital_io/BUILD.gn b/pw_digital_io/BUILD.gn index 2cf894932..b56492f00 100644 --- a/pw_digital_io/BUILD.gn +++ b/pw_digital_io/BUILD.gn @@ -16,6 +16,7 @@ import("//build_overrides/pigweed.gni") import("$dir_pw_build/target_types.gni") import("$dir_pw_docgen/docs.gni") +import("$dir_pw_protobuf_compiler/proto.gni") import("$dir_pw_toolchain/generate_toolchain.gni") import("$dir_pw_unit_test/test.gni") @@ -39,6 +40,21 @@ pw_source_set("pw_digital_io") { ] } +pw_source_set("digital_io_service") { + public_configs = [ ":public_include_path" ] + public = [ "public/pw_digital_io/digital_io_service.h" ] + sources = [ "digital_io_service.cc" ] + public_deps = [ + ":protos.pwpb_rpc", + ":pw_digital_io", + ] +} + +pw_proto_library("protos") { + sources = [ "digital_io.proto" ] + prefix = "pw_digital_io" +} + pw_doc_group("docs") { sources = [ "docs.rst" ] } diff --git a/pw_digital_io/CMakeLists.txt b/pw_digital_io/CMakeLists.txt index 8c1dbe181..bb8b4469b 100644 --- a/pw_digital_io/CMakeLists.txt +++ b/pw_digital_io/CMakeLists.txt @@ -28,9 +28,6 @@ pw_add_library(pw_digital_io STATIC pw_result pw_status ) -if(Zephyr_FOUND AND CONFIG_PIGWEED_DIGITAL_IO) - zephyr_link_libraries(pw_digital_io) -endif() pw_add_test(pw_digital_io.stream_test SOURCES diff --git a/pw_digital_io/digital_io.proto b/pw_digital_io/digital_io.proto new file mode 100644 index 000000000..0900be6ad --- /dev/null +++ b/pw_digital_io/digital_io.proto @@ -0,0 +1,55 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +syntax = "proto3"; + +package pw.digital_io; + +enum DigitalIoState { + INACTIVE = 0; + ACTIVE = 1; +} + +message DigitalIoEnableRequest { + // Which line to select. + uint32 line_index = 1; + // Whether to enable or disable. + bool enable = 2; +} + +message DigitalIoEnableResponse {} + +message DigitalIoSetStateRequest { + // Which line to select. + uint32 line_index = 1; + // Which state to set to. + DigitalIoState state = 2; +} + +message DigitalIoSetStateResponse {} + +message DigitalIoGetStateRequest { + // Which line to select. + uint32 line_index = 1; +} + +message DigitalIoGetStateResponse { + DigitalIoState state = 1; +} + +service DigitalIo { + rpc Enable(DigitalIoEnableRequest) returns (DigitalIoEnableResponse) {} + rpc SetState(DigitalIoSetStateRequest) returns (DigitalIoSetStateResponse) {} + rpc GetState(DigitalIoGetStateRequest) returns (DigitalIoGetStateResponse) {} +} diff --git a/pw_digital_io/digital_io_service.cc b/pw_digital_io/digital_io_service.cc new file mode 100644 index 000000000..8a7ea3676 --- /dev/null +++ b/pw_digital_io/digital_io_service.cc @@ -0,0 +1,104 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#define PW_LOG_MODULE_NAME "IO" + +#include "pw_digital_io/digital_io_service.h" + +#include "pw_digital_io/digital_io.pwpb.h" +#include "pw_log/log.h" +#include "pw_result/result.h" +#include "pw_rpc/pwpb/server_reader_writer.h" +#include "pw_status/status.h" + +namespace pw::digital_io { + +void DigitalIoService::Enable( + const pwpb::DigitalIoEnableRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoEnableResponse::Message>& + responder) { + Status result = OkStatus(); + if (request.line_index >= lines_.size()) { + result = Status::InvalidArgument(); + } else { + auto& line = lines_[request.line_index].get(); + if (request.enable) { + result = line.Enable(); + } else { + result = line.Disable(); + } + } + + if (const auto finished = responder.Finish({}, result); !finished.ok()) { + PW_LOG_ERROR("Enable failed to send response %d", finished.code()); + } +} + +void DigitalIoService::SetState( + const pwpb::DigitalIoSetStateRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoSetStateResponse::Message>& + responder) { + Status result = OkStatus(); + if (request.line_index >= lines_.size()) { + result = Status::InvalidArgument(); + } else { + auto& line = lines_[request.line_index].get(); + if (!line.provides_output()) { + result = Status::InvalidArgument(); + } else { + if (request.state == pwpb::DigitalIoState::kActive) { + result = line.SetStateActive(); + } else { + result = line.SetStateInactive(); + } + } + } + + if (const auto finished = responder.Finish({}, result); !finished.ok()) { + PW_LOG_ERROR("SetState failed to send response %d", finished.code()); + } +} + +void DigitalIoService::GetState( + const pwpb::DigitalIoGetStateRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoGetStateResponse::Message>& + responder) { + pw::Result<State> result; + if (request.line_index >= lines_.size()) { + result = pw::Status::InvalidArgument(); + } else { + auto& line = lines_[request.line_index].get(); + if (!line.provides_input()) { + result = pw::Status::InvalidArgument(); + } else { + result = line.GetState(); + } + } + + auto finished = pw::OkStatus(); + if (result.ok()) { + pwpb::DigitalIoState state = *result == State::kActive + ? pwpb::DigitalIoState::kActive + : pwpb::DigitalIoState::kInactive; + finished = responder.Finish({.state = state}, OkStatus()); + } else { + finished = responder.Finish({}, result.status()); + } + + if (!finished.ok()) { + PW_LOG_ERROR("GetState failed to send response %d", finished.code()); + } +} + +} // namespace pw::digital_io diff --git a/pw_digital_io/docs.rst b/pw_digital_io/docs.rst index 46f3ba077..1d35468d9 100644 --- a/pw_digital_io/docs.rst +++ b/pw_digital_io/docs.rst @@ -58,7 +58,8 @@ There are 3 basic capabilities of a Digital IO line: Additionally, all lines can be *enabled* and *disabled*: * Enable - tell the hardware to apply power to an output line, connect any - pull-up/down resistors, etc. + pull-up/down resistors, etc. For output lines, the line is set to an initial + output state that is backend-specific. * Disable - tell the hardware to stop applying power and return the line to its default state. This may save power or allow some other component to drive a shared line. @@ -266,7 +267,46 @@ Backend Implemention Notes state. i.e. the same state it would be in after calling ``Enable()`` followed by ``Disable()``. * Calling ``Disable()`` on an uninitialized line must put it into the disabled - state. + state. In general, ``Disable()`` can be called in any state. + +* Calling ``Enable()`` on a line that is already enabled should be a no-op. In + particular, the state of an already-enabled output line should not change. + +----------- +RPC Service +----------- +The ``DigitalIoService`` pw_rpc service is provided to support bringup/debug +efforts. It allows manual control of individual DigitalIo lines for both input +and output. + +.. code-block:: cpp + + std::array<std::reference_wrapper<DigitalIoOptional>> lines = { + ...DigitalIn(), + ...DigitalOut(), + }; + DigitalIoService service(lines); + rpc_server.RegisterService(service); + +Set the state of the output line via RPC. This snippet demonstrates how you +might do that using a Pigweed console device object. + +.. code-block:: python + + from pw_digital_io import digital_io_pb2 + + device.rpcs.pw.digital_io.DigitalIo.SetState( + line_index=0, state=digital_io_pb2.DigitalIoState.ACTIVE) + + +------------- +API reference +------------- +.. note:: + This API reference is incomplete. + +.. doxygenclass:: pw::digital_io::DigitalIoOptional + :members: ------------ Dependencies diff --git a/pw_digital_io/public/pw_digital_io/digital_io.h b/pw_digital_io/public/pw_digital_io/digital_io.h index ba8516b01..8855f019b 100644 --- a/pw_digital_io/public/pw_digital_io/digital_io.h +++ b/pw_digital_io/public/pw_digital_io/digital_io.h @@ -42,136 +42,135 @@ enum class InterruptTrigger : int { // the line. It is backend-specific if, when, and how this state is updated. using InterruptHandler = ::pw::Function<void(State sampled_state)>; -// A digital I/O line that may support input, output, and interrupts, but makes -// no guarantees about whether any operations are supported. You must check the -// various provides_* flags before calling optional methods. Unsupported methods -// invoke PW_CRASH. -// -// All methods are potentially blocking. Unless otherwise specified, access from -// multiple threads to a single line must be externally synchronized - for -// example using pw::Borrowable. Unless otherwise specified, none of the methods -// are safe to call from an interrupt handler. Therefore, this abstraction may -// not be suitable for bitbanging and other low-level uses of GPIO. -// -// Note that the initial state of a line is not guaranteed to be consistent with -// either the "enabled" or "disabled" state. Users of the API who need to ensure -// the line is disabled (ex. output not driving the line) should call Disable. -// -// This class should almost never be used in APIs directly. Instead, use one of -// the derived classes that explicitly supports the functionality that your -// API needs. -// -// This class cannot be extended directly. Instead, extend one of the -// derived classes that explicitly support the functionality that you want to -// implement. -// +/// A digital I/O line that may support input, output, and interrupts, but makes +/// no guarantees about whether any operations are supported. You must check the +/// various `provides_*` flags before calling optional methods. Unsupported +/// methods invoke `PW_CRASH`. +/// +/// All methods are potentially blocking. Unless otherwise specified, access +/// from multiple threads to a single line must be externally synchronized - for +/// example using `pw::Borrowable`. Unless otherwise specified, none of the +/// methods are safe to call from an interrupt handler. Therefore, this +/// abstraction may not be suitable for bitbanging and other low-level uses of +/// GPIO. +/// +/// Note that the initial state of a line is not guaranteed to be consistent +/// with either the "enabled" or "disabled" state. Users of the API who need to +/// ensure the line is disabled (ex. output not driving the line) should call +/// `Disable()`. +/// +/// This class should almost never be used in APIs directly. Instead, use one of +/// the derived classes that explicitly supports the functionality that your +/// API needs. +/// +/// This class cannot be extended directly. Instead, extend one of the +/// derived classes that explicitly support the functionality that you want to +/// implement. class DigitalIoOptional { public: virtual ~DigitalIoOptional() = default; - // True if input (getting state) is supported. + /// @returns `true` if input (getting state) is supported. constexpr bool provides_input() const { return config_.input; } - // True if output (setting state) is supported. + /// @returns `true` if output (setting state) is supported. constexpr bool provides_output() const { return config_.output; } - // True if interrupt handlers can be registered. + /// @returns `true` if interrupt handlers can be registered. constexpr bool provides_interrupt() const { return config_.interrupt; } - // Get the state of the line. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // - // OK - an active or inactive state. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Gets the state of the line. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - An active or inactive state. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Result<State> GetState() { return DoGetState(); } - // Set the state of the line. - // - // Callers are responsible to wait for the voltage level to settle after this - // call returns. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // - // OK - the state has been set. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Sets the state of the line. + /// + /// Callers are responsible to wait for the voltage level to settle after this + /// call returns. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The state has been set. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Status SetState(State state) { return DoSetState(state); } - // Check if the line is in the active state. - // - // The line is in the active state when GetState() returns State::kActive. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // - // OK - true if the line is in the active state, otherwise false. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Checks if the line is in the active state. + /// + /// The line is in the active state when `GetState()` returns + /// `State::kActive`. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - `true` if the line is in the active state, otherwise + /// `false`. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Result<bool> IsStateActive() { PW_TRY_ASSIGN(const State state, GetState()); return state == State::kActive; } - // Sets the line to the active state. Equivalent to SetState(State::kActive). - // - // Callers are responsible to wait for the voltage level to settle after this - // call returns. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // - // OK - the state has been set. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Sets the line to the active state. Equivalent to + /// `SetState(State::kActive)`. + /// + /// Callers are responsible to wait for the voltage level to settle after this + /// call returns. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The state has been set. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Status SetStateActive() { return SetState(State::kActive); } - // Sets the line to the inactive state. Equivalent to - // SetState(State::kInactive). - // - // Callers are responsible to wait for the voltage level to settle after this - // call returns. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // - // OK - the state has been set. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Sets the line to the inactive state. Equivalent to + /// `SetState(State::kInactive)`. + /// + /// Callers are responsible to wait for the voltage level to settle after + /// this call returns. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The state has been set. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Status SetStateInactive() { return SetState(State::kInactive); } - // Set an interrupt handler to execute when an interrupt is triggered, and - // Configure the condition for triggering the interrupt. - // - // The handler is executed in a backend-specific context - this may be a - // system interrupt handler or a shared notification thread. Do not do any - // blocking or expensive work in the handler. The only universally safe - // operations are the IRQ-safe functions on pw_sync primitives. - // - // In particular, it is NOT safe to get the state of a DigitalIo line - either - // from this line or any other DigitalIoOptional instance - inside the - // handler. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Precondition: no handler is currently set. - // - // Returns: - // OK - the interrupt handler was configured. - // INVALID_ARGUMENT - handler is empty. - // Other status codes as defined by the backend. - // + /// Sets an interrupt handler to execute when an interrupt is triggered, and + /// configures the condition for triggering the interrupt. + /// + /// The handler is executed in a backend-specific context—this may be a + /// system interrupt handler or a shared notification thread. Do not do any + /// blocking or expensive work in the handler. The only universally safe + /// operations are the IRQ-safe functions on `pw_sync` primitives. + /// + /// In particular, it is NOT safe to get the state of a `DigitalIo` + /// line—either from this line or any other `DigitalIoOptional` + /// instance—inside the handler. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @pre No handler is currently set. + /// + /// @returns + /// * @pw_status{OK} - The interrupt handler was configured. + /// * @pw_status{INVALID_ARGUMENT} - The handler is empty. + /// * Other status codes as defined by the backend. Status SetInterruptHandler(InterruptTrigger trigger, InterruptHandler&& handler) { if (handler == nullptr) { @@ -180,70 +179,73 @@ class DigitalIoOptional { return DoSetInterruptHandler(trigger, std::move(handler)); } - // Clear the interrupt handler and disable interrupts if enabled. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // OK - the itnerrupt handler was cleared. - // Other status codes as defined by the backend. - // + /// Clears the interrupt handler and disables any existing interrupts that + /// are enabled. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The interrupt handler was cleared. + /// * Other status codes as defined by the backend. Status ClearInterruptHandler() { return DoSetInterruptHandler(InterruptTrigger::kActivatingEdge, nullptr); } - // Enable interrupts which will trigger the interrupt handler. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Precondition: a handler has been set using SetInterruptHandler. - // - // Returns: - // OK - the interrupt handler was configured. - // FAILED_PRECONDITION - The line has not been enabled. - // Other status codes as defined by the backend. - // + /// Enables interrupts which will trigger the interrupt handler. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @pre A handler has been set using `SetInterruptHandler()`. + /// + /// @returns + /// * @pw_status{OK} - The interrupt handler was configured. + /// * @pw_status{FAILED_PRECONDITION} - The line has not been enabled. + /// * Other status codes as defined by the backend. Status EnableInterruptHandler() { return DoEnableInterruptHandler(true); } - // Disable the interrupt handler. This is a no-op if interrupts are disabled. - // - // This method can be called inside the interrupt handler for this line - // without any external synchronization. However, the exact behavior is - // backend-specific. There may be queued events that will trigger the handler - // again after this call returns. - // - // Returns: - // OK - the interrupt handler was configured. - // Other status codes as defined by the backend. - // + /// Disables the interrupt handler. This is a no-op if interrupts are + /// disabled. + /// + /// This method can be called inside the interrupt handler for this line + /// without any external synchronization. However, the exact behavior is + /// backend-specific. There may be queued events that will trigger the handler + /// again after this call returns. + /// + /// @returns + /// * @pw_status{OK} - The interrupt handler was disabled. + /// * Other status codes as defined by the backend. Status DisableInterruptHandler() { return DoEnableInterruptHandler(false); } - // Enable the line to initialize it into the default state as determined by - // the backend. This may enable pull-up/down resistors, drive the line high or - // low, etc. The line must be enabled before getting/setting the state - // or enabling interrupts. - // - // Callers are responsible to wait for the voltage level to settle after this - // call returns. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // OK - the line is enabled and ready for use. - // Other status codes as defined by the backend. - // + /// Enables the line to initialize it into the default state as determined by + /// the backend. + /// + /// This may enable pull-up/down resistors, drive the line high/low, etc. + /// The line must be enabled before getting/setting the state or enabling + /// interrupts. Callers are responsible for waiting for the voltage level to + /// settle after this call returns. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The line is enabled and ready for use. + /// * Other status codes as defined by the backend. Status Enable() { return DoEnable(true); } - // Disable the line to power down any pull-up/down resistors and disconnect - // from any voltage sources. This is usually done to save power. Interrupt - // handlers are automatically disabled. - // - // This method is not thread-safe and cannot be used in interrupt handlers. - // - // Returns: - // OK - the line is disabled. - // Other status codes as defined by the backend. - // + /// Disables the line to power down any pull-up/down resistors and disconnect + /// from any voltage sources. + /// + /// This is usually done to save power. Interrupt handlers are automatically + /// disabled. + /// + /// @warning This method is not thread-safe and cannot be used in interrupt + /// handlers. + /// + /// @returns + /// * @pw_status{OK} - The line is disabled. + /// * Other status codes as defined by the backend. Status Disable() { return DoEnable(false); } private: diff --git a/pw_digital_io/public/pw_digital_io/digital_io_service.h b/pw_digital_io/public/pw_digital_io/digital_io_service.h new file mode 100644 index 000000000..e243839c2 --- /dev/null +++ b/pw_digital_io/public/pw_digital_io/digital_io_service.h @@ -0,0 +1,54 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#pragma once + +#include "pw_digital_io/digital_io.h" +#include "pw_digital_io/digital_io.pwpb.h" +#include "pw_digital_io/digital_io.rpc.pwpb.h" +#include "pw_function/function.h" +#include "pw_rpc/pwpb/server_reader_writer.h" +#include "pw_span/span.h" + +namespace pw::digital_io { + +// Implementation class for pw.digital_io.DigitalIo. +// +// Takes an array of DigitalIoOptional lines to be exposed via the service. +class DigitalIoService + : public pw_rpc::pwpb::DigitalIo::Service<DigitalIoService> { + public: + explicit DigitalIoService( + pw::span<std::reference_wrapper<DigitalIoOptional>> lines) + : lines_(lines) {} + + void Enable(const pwpb::DigitalIoEnableRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoEnableResponse::Message>& + responder); + + void SetState( + const pwpb::DigitalIoSetStateRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoSetStateResponse::Message>& + responder); + + void GetState( + const pwpb::DigitalIoGetStateRequest::Message& request, + rpc::PwpbUnaryResponder<pwpb::DigitalIoGetStateResponse::Message>& + responder); + + private: + pw::span<std::reference_wrapper<DigitalIoOptional>> lines_; +}; + +} // namespace pw::digital_io |