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