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