pw_analog: Add analog::AnalogInput interface
Adds the pw_analog module with the pw::analog::AnalogInput interface for
sampling the ADC to get a voltage reading.
Testing:
Host test -- OK
Change-Id: Ief497da89e34eec6aa1be4c3f29c484a85a39cfb
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/38601
Commit-Queue: Kevin Zeng <zengk@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 6040df6..2011dea 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -205,6 +205,7 @@
deps = [
"$dir_pigweed/docs",
"$dir_pw_allocator",
+ "$dir_pw_analog",
"$dir_pw_base64",
"$dir_pw_blob_store",
"$dir_pw_bytes",
@@ -247,6 +248,7 @@
pw_test_group("pw_module_tests") {
group_deps = [
"$dir_pw_allocator:tests",
+ "$dir_pw_analog:tests",
"$dir_pw_assert:tests",
"$dir_pw_base64:tests",
"$dir_pw_blob_store:tests",
diff --git a/modules.gni b/modules.gni
index fa5c03c..d0c9043 100644
--- a/modules.gni
+++ b/modules.gni
@@ -17,6 +17,7 @@
# allows modules to be moved or swapped out without breaking existing builds.
# All module variables are prefixed with dir_.
dir_docker = get_path_info("docker", "abspath")
+ dir_pw_analog = get_path_info("pw_analog", "abspath")
dir_pw_allocator = get_path_info("pw_allocator", "abspath")
dir_pw_arduino_build = get_path_info("pw_arduino_build", "abspath")
dir_pw_assert = get_path_info("pw_assert", "abspath")
diff --git a/pw_analog/BUILD b/pw_analog/BUILD
new file mode 100644
index 0000000..3d524d9
--- /dev/null
+++ b/pw_analog/BUILD
@@ -0,0 +1,46 @@
+# Copyright 2021 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.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_library",
+ "pw_cc_test",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache License 2.0
+
+pw_cc_library(
+ name = "analog_input",
+ hdrs = [
+ "public/pw_analog/analog_input.h",
+ ],
+ includes = ["public"],
+ deps = [
+ "//pw_chrono:system_clock",
+ "//pw_result",
+ ],
+)
+
+pw_cc_test(
+ name = "analog_input_test",
+ srcs = [
+ "analog_input_test.cc",
+ ],
+ deps = [
+ ":analog_input",
+ "//pw_unit_test",
+ ],
+)
diff --git a/pw_analog/BUILD.gn b/pw_analog/BUILD.gn
new file mode 100644
index 0000000..8b1eab7
--- /dev/null
+++ b/pw_analog/BUILD.gn
@@ -0,0 +1,47 @@
+# Copyright 2021 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_chrono/backend.gni")
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("public_include_path") {
+ include_dirs = [ "public" ]
+}
+
+pw_source_set("pw_analog") {
+ public_configs = [ ":public_include_path" ]
+ public_deps = [
+ "$dir_pw_chrono:system_clock",
+ "$dir_pw_result",
+ ]
+ public = [ "public/pw_analog/analog_input.h" ]
+}
+
+pw_test_group("tests") {
+ tests = [ ":analog_input_test" ]
+}
+
+pw_test("analog_input_test") {
+ enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
+ sources = [ "analog_input_test.cc" ]
+ deps = [ ":pw_analog" ]
+}
+
+pw_doc_group("docs") {
+ sources = [ "docs.rst" ]
+}
diff --git a/pw_analog/analog_input_test.cc b/pw_analog/analog_input_test.cc
new file mode 100644
index 0000000..a704fcb
--- /dev/null
+++ b/pw_analog/analog_input_test.cc
@@ -0,0 +1,57 @@
+// Copyright 2021 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.
+#include "pw_analog/analog_input.h"
+
+#include "gtest/gtest.h"
+
+namespace pw {
+namespace analog {
+namespace {
+
+constexpr int32_t kLimitsMax = 4096;
+constexpr int32_t kLimitsMin = 0;
+
+// Dummy test analog input that's used for testing.
+class TestAnalogInput : public AnalogInput {
+ public:
+ TestAnalogInput()
+ : limits_({
+ .min = kLimitsMin,
+ .max = kLimitsMax,
+ }) {}
+
+ Result<int32_t> TryReadUntil(chrono::SystemClock::time_point) override {
+ return Status::Unimplemented();
+ }
+
+ Limits GetLimits() const override { return limits_; }
+
+ private:
+ const Limits limits_;
+};
+
+TEST(AnalogInputTest, Construction) {
+ TestAnalogInput analog_input = TestAnalogInput();
+}
+
+TEST(AnalogInputTest, GetLimits) {
+ TestAnalogInput analog_input = TestAnalogInput();
+ AnalogInput::Limits limits = analog_input.GetLimits();
+ EXPECT_EQ(limits.min, kLimitsMin);
+ EXPECT_EQ(limits.max, kLimitsMax);
+}
+
+} // namespace
+} // namespace analog
+} // namespace pw
diff --git a/pw_analog/docs.rst b/pw_analog/docs.rst
new file mode 100644
index 0000000..1c5d485
--- /dev/null
+++ b/pw_analog/docs.rst
@@ -0,0 +1,21 @@
+.. _module-pw_analog:
+
+---------
+pw_analog
+---------
+
+.. warning::
+ This module is under construction and may not be ready for use.
+
+pw_analog contains interfaces and utility functions for using the ADC.
+
+Features
+========
+
+pw::analog::AnalogInput
+-----------------------
+The common interface for obtaining ADC samples. This interface represents
+a single analog input or channel. Users will need to supply their own ADC
+driver implementation in order to configure and enable the ADC peripheral.
+Users are responsible for managing multithreaded access to the ADC driver if the
+ADC services multiple channels.
diff --git a/pw_analog/public/pw_analog/analog_input.h b/pw_analog/public/pw_analog/analog_input.h
new file mode 100644
index 0000000..39024a0
--- /dev/null
+++ b/pw_analog/public/pw_analog/analog_input.h
@@ -0,0 +1,74 @@
+// Copyright 2021 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_chrono/system_clock.h"
+#include "pw_result/result.h"
+
+namespace pw::analog {
+
+// Base interface for getting ADC samples from one ADC channel in a thread
+// safe manner.
+//
+// The ADC backend interface is up to the user to define and implement for now.
+// This gives the flexibility for the ADC driver implementation.
+//
+// AnalogInput controls a specific input/channel where the ADC peripheral may be
+// shared across multiple channels that may be controlled by multiple threads.
+// The implementer of this pure virtual interface is responsible for ensuring
+// thread safety and access at the driver level.
+class AnalogInput {
+ public:
+ // Limits struct that specifies the min and max of the sample range.
+ // These values do not change at run time.
+ struct Limits {
+ int32_t min;
+ int32_t max;
+ };
+
+ virtual ~AnalogInput() = default;
+
+ // Blocks until the specified timeout duration has elapsed or the ADC sample
+ // has been returned, whichever comes first.
+ //
+ // This method is thread safe.
+ //
+ // Returns:
+ // Sample.
+ // ResourceExhuasted: ADC peripheral in use.
+ // DeadlineExceedded: Timed out waiting for a sample.
+ // Other statuses left up to the implementer.
+ Result<int32_t> TryReadFor(chrono::SystemClock::duration timeout) {
+ return TryReadUntil(chrono::SystemClock::TimePointAfterAtLeast(timeout));
+ }
+
+ // Blocks until the deadline time has been reached or the ADC sample
+ // has been returned, whichever comes first.
+ //
+ // This method is thread safe.
+ //
+ // Returns:
+ // Sample.
+ // ResourceExhuasted: ADC peripheral in use.
+ // DeadlineExceedded: Timed out waiting for a sample.
+ // Other statuses left up to the implementer.
+ virtual Result<int32_t> TryReadUntil(
+ chrono::SystemClock::time_point deadline) = 0;
+
+ // Returns the range of the ADC sample.
+ // These values do not change at run time.
+ virtual Limits GetLimits() const = 0;
+};
+
+} // namespace pw::analog