aboutsummaryrefslogtreecommitdiff
path: root/pw_digital_io
diff options
context:
space:
mode:
Diffstat (limited to 'pw_digital_io')
-rw-r--r--pw_digital_io/Android.bp53
-rw-r--r--pw_digital_io/BUILD.bazel35
-rw-r--r--pw_digital_io/BUILD.gn16
-rw-r--r--pw_digital_io/CMakeLists.txt3
-rw-r--r--pw_digital_io/digital_io.proto55
-rw-r--r--pw_digital_io/digital_io_service.cc104
-rw-r--r--pw_digital_io/docs.rst44
-rw-r--r--pw_digital_io/public/pw_digital_io/digital_io.h328
-rw-r--r--pw_digital_io/public/pw_digital_io/digital_io_service.h54
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