xref: /aosp_15_r20/external/pigweed/pw_analog/public/pw_analog/microvolt_input.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 #include "pw_analog/analog_input.h"
16 #include "pw_chrono/system_clock.h"
17 #include "pw_result/result.h"
18 #include "pw_status/try.h"
19 
20 namespace pw::analog {
21 
22 /// The common interface for obtaining voltage samples in microvolts. This
23 /// interface represents a single voltage input or channel. Users will need to
24 /// supply their own ADC driver implementation in order to provide the reference
25 /// voltages and to configure and enable the ADC peripheral where needed. Users
26 /// are responsible for managing multi-threaded access to the ADC driver if the
27 /// ADC services multiple channels.
28 class MicrovoltInput : public AnalogInput {
29  public:
30   /// Specifies the maximum and minimum microvolt range the analog input can
31   /// measure. The reference voltage difference cannot be bigger than
32   /// `sizeof(int32_t)` which should be just above 2000V. These values do not
33   /// change at run time. Inversion of `min` or `max` is supported.
34   struct References {
35     /// Microvolts at `AnalogInput::Limits::max`.
36     int32_t max_voltage_uv;
37     /// Microvolts at `AnalogInput::Limits::min`.
38     int32_t min_voltage_uv;
39   };
40 
41   ~MicrovoltInput() override = default;
42 
43   /// Blocks until the specified timeout duration has elapsed or the voltage
44   /// sample has been returned, whichever comes first.
45   ///
46   /// This method is thread-safe.
47   ///
48   /// @returns @rst
49   ///
50   /// .. pw-status-codes::
51   ///
52   ///    OK: Returns a voltage sample in microvolts (uV) on success.
53   ///
54   ///    RESOURCE_EXHAUSTED: ADC peripheral in use.
55   ///
56   ///    DEADLINE_EXCEEDED: Timed out waiting for a sample.
57   ///
58   /// Other statuses left up to the implementer.
59   ///
60   /// @endrst
TryReadMicrovoltsFor(chrono::SystemClock::duration timeout)61   Result<int32_t> TryReadMicrovoltsFor(chrono::SystemClock::duration timeout) {
62     return TryReadMicrovoltsUntil(
63         chrono::SystemClock::TimePointAfterAtLeast(timeout));
64   }
65 
66   /// Blocks until the deadline time has been reached or the voltage sample has
67   /// been returned, whichever comes first.
68   ///
69   /// This method is thread-safe.
70   ///
71   /// @returns @rst
72   ///
73   /// .. pw-status-codes::
74   ///
75   ///    OK: Returns a voltage sample in microvolts (uV) on success.
76   ///
77   ///    RESOURCE_EXHAUSTED: ADC peripheral in use.
78   ///
79   ///    DEADLINE_EXCEEDED: Timed out waiting for a sample.
80   ///
81   /// Other statuses left up to the implementer.
82   ///
83   /// @endrst
TryReadMicrovoltsUntil(chrono::SystemClock::time_point deadline)84   Result<int32_t> TryReadMicrovoltsUntil(
85       chrono::SystemClock::time_point deadline) {
86     PW_TRY_ASSIGN(const int32_t sample, TryReadUntil(deadline));
87 
88     const References reference = GetReferences();
89     const AnalogInput::Limits limits = GetLimits();
90 
91     constexpr int64_t kMaxReferenceDiffUv = std::numeric_limits<int32_t>::max();
92 
93     if (std::abs(static_cast<int64_t>(reference.max_voltage_uv) -
94                  static_cast<int64_t>(reference.min_voltage_uv)) >
95         kMaxReferenceDiffUv) {
96       return pw::Status::Internal();
97     }
98 
99     return (((static_cast<int64_t>(sample) - static_cast<int64_t>(limits.min)) *
100              (reference.max_voltage_uv - reference.min_voltage_uv)) /
101             (limits.max - limits.min)) +
102            reference.min_voltage_uv;
103   }
104 
105  private:
106   // Returns the reference voltage needed to calculate the voltage.
107   // These values do not change at run time.
108   virtual References GetReferences() const = 0;
109 };
110 
111 }  // namespace pw::analog
112