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 #include "pw_analog/microvolt_input.h"
15
16 #include "pw_unit_test/framework.h"
17
18 namespace pw {
19 namespace analog {
20 namespace {
21
22 using namespace std::chrono_literals;
23
24 constexpr int32_t kLimitsMax = 4096;
25 constexpr int32_t kLimitsMin = 0;
26 constexpr int32_t kReferenceMaxVoltageUv = 1800000;
27 constexpr int32_t kReferenceMinVoltageUv = 0;
28 constexpr chrono::SystemClock::duration kTimeout =
29 chrono::SystemClock::for_at_least(1ms);
30
31 constexpr int32_t kBipolarLimitsMax = 4096;
32 constexpr int32_t kBipolarLimitsMin = -4096;
33 constexpr int32_t kBipolarReferenceMaxVoltageUv = 1800000;
34 constexpr int32_t kBipolarReferenceMinVoltageUv = -1800000;
35
36 constexpr int32_t kCornerLimitsMax = std::numeric_limits<int32_t>::max();
37 constexpr int32_t kCornerLimitsMin = std::numeric_limits<int32_t>::min();
38 constexpr int32_t kCornerReferenceMaxVoltageUv =
39 std::numeric_limits<int32_t>::max();
40 constexpr int32_t kCornerReferenceMinVoltageUv =
41 std::numeric_limits<int32_t>::min();
42
43 constexpr int32_t kInvertedLimitsMax = std::numeric_limits<int32_t>::min();
44 constexpr int32_t kInvertedLimitsMin = std::numeric_limits<int32_t>::max();
45 constexpr int32_t kInvertedReferenceMaxVoltageUv =
46 std::numeric_limits<int32_t>::min();
47 constexpr int32_t kInvertedReferenceMinVoltageUv =
48 std::numeric_limits<int32_t>::max();
49
50 // Fake voltage input that's used for testing.
51 class TestMicrovoltInput : public MicrovoltInput {
52 public:
TestMicrovoltInput(AnalogInput::Limits limits,MicrovoltInput::References reference)53 constexpr explicit TestMicrovoltInput(AnalogInput::Limits limits,
54 MicrovoltInput::References reference)
55 : sample_(0), limits_(limits), reference_(reference) {}
56
SetSampleValue(int32_t sample)57 void SetSampleValue(int32_t sample) { sample_ = sample; }
58
59 private:
TryReadUntil(chrono::SystemClock::time_point)60 Result<int32_t> TryReadUntil(chrono::SystemClock::time_point) override {
61 return sample_;
62 }
63
GetLimits() const64 Limits GetLimits() const override { return limits_; }
GetReferences() const65 References GetReferences() const override { return reference_; }
66
67 uint32_t sample_;
68 const Limits limits_;
69 const References reference_;
70 };
71
TEST(MicrovoltInputTest,Construction)72 TEST(MicrovoltInputTest, Construction) {
73 TestMicrovoltInput voltage_input =
74 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
75 {.max_voltage_uv = kReferenceMaxVoltageUv,
76 .min_voltage_uv = kReferenceMinVoltageUv});
77 }
78
TEST(MicrovoltInputTest,ReadMicrovoltsWithSampleAtMin)79 TEST(MicrovoltInputTest, ReadMicrovoltsWithSampleAtMin) {
80 TestMicrovoltInput voltage_input =
81 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
82 {.max_voltage_uv = kReferenceMaxVoltageUv,
83 .min_voltage_uv = kReferenceMinVoltageUv});
84 voltage_input.SetSampleValue(kLimitsMin);
85
86 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
87 ASSERT_TRUE(result.status().ok());
88
89 EXPECT_EQ(result.value(), 0);
90 }
91
TEST(MicrovoltInputTest,ReadMicrovoltsWithSampleAtMax)92 TEST(MicrovoltInputTest, ReadMicrovoltsWithSampleAtMax) {
93 TestMicrovoltInput voltage_input =
94 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
95 {.max_voltage_uv = kReferenceMaxVoltageUv,
96 .min_voltage_uv = kReferenceMinVoltageUv});
97 voltage_input.SetSampleValue(kLimitsMax);
98
99 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
100 ASSERT_TRUE(result.status().ok());
101
102 EXPECT_EQ(result.value(), kReferenceMaxVoltageUv);
103 }
104
TEST(MicrovoltInputTest,ReadMicrovoltsWithSampleAtHalf)105 TEST(MicrovoltInputTest, ReadMicrovoltsWithSampleAtHalf) {
106 TestMicrovoltInput voltage_input =
107 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
108 {.max_voltage_uv = kReferenceMaxVoltageUv,
109 .min_voltage_uv = kReferenceMinVoltageUv});
110 voltage_input.SetSampleValue(kLimitsMax / 2);
111
112 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
113 ASSERT_TRUE(result.status().ok());
114
115 EXPECT_EQ(result.value(), kReferenceMaxVoltageUv / 2);
116 }
117
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarAdcAtZero)118 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarAdcAtZero) {
119 TestMicrovoltInput voltage_input =
120 TestMicrovoltInput({.min = kBipolarLimitsMin, .max = kBipolarLimitsMax},
121 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
122 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
123 voltage_input.SetSampleValue(0);
124
125 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
126 ASSERT_TRUE(result.status().ok());
127
128 EXPECT_EQ(result.value(), 0);
129 }
130
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarAdcAtMin)131 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarAdcAtMin) {
132 TestMicrovoltInput voltage_input =
133 TestMicrovoltInput({.min = kBipolarLimitsMin, .max = kBipolarLimitsMax},
134 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
135 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
136 voltage_input.SetSampleValue(kBipolarLimitsMin);
137
138 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
139 ASSERT_TRUE(result.status().ok());
140
141 EXPECT_EQ(result.value(), kBipolarReferenceMinVoltageUv);
142 }
143
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarAdcAtMax)144 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarAdcAtMax) {
145 TestMicrovoltInput voltage_input =
146 TestMicrovoltInput({.min = kBipolarLimitsMin, .max = kBipolarLimitsMax},
147 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
148 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
149 voltage_input.SetSampleValue(kBipolarLimitsMax);
150
151 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
152 ASSERT_TRUE(result.status().ok());
153
154 EXPECT_EQ(result.value(), kBipolarReferenceMaxVoltageUv);
155 }
156
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarAdcAtUpperHalf)157 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarAdcAtUpperHalf) {
158 TestMicrovoltInput voltage_input =
159 TestMicrovoltInput({.min = kBipolarLimitsMin, .max = kBipolarLimitsMax},
160 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
161 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
162 voltage_input.SetSampleValue(kBipolarLimitsMax / 2);
163
164 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
165 ASSERT_TRUE(result.status().ok());
166
167 EXPECT_EQ(result.value(), kBipolarReferenceMaxVoltageUv / 2);
168 }
169
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarAdcAtLowerHalf)170 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarAdcAtLowerHalf) {
171 TestMicrovoltInput voltage_input =
172 TestMicrovoltInput({.min = kBipolarLimitsMin, .max = kBipolarLimitsMax},
173 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
174 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
175 voltage_input.SetSampleValue(kBipolarLimitsMin / 2);
176
177 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
178 ASSERT_TRUE(result.status().ok());
179
180 EXPECT_EQ(result.value(), kBipolarReferenceMinVoltageUv / 2);
181 }
182
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarReferenceAtZero)183 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarReferenceAtZero) {
184 TestMicrovoltInput voltage_input =
185 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
186 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
187 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
188 voltage_input.SetSampleValue(0);
189
190 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
191 ASSERT_TRUE(result.status().ok());
192
193 EXPECT_EQ(result.value(), kBipolarReferenceMinVoltageUv);
194 }
195
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarReferenceAtMin)196 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarReferenceAtMin) {
197 TestMicrovoltInput voltage_input =
198 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
199 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
200 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
201 voltage_input.SetSampleValue(kLimitsMin);
202
203 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
204 ASSERT_TRUE(result.status().ok());
205
206 EXPECT_EQ(result.value(), kBipolarReferenceMinVoltageUv);
207 }
208
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarReferenceAtMax)209 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarReferenceAtMax) {
210 TestMicrovoltInput voltage_input =
211 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
212 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
213 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
214 voltage_input.SetSampleValue(kLimitsMax);
215
216 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
217 ASSERT_TRUE(result.status().ok());
218
219 EXPECT_EQ(result.value(), kBipolarReferenceMaxVoltageUv);
220 }
221
TEST(MicrovoltInputTest,ReadMicrovoltsWithBipolarReferenceAtHalf)222 TEST(MicrovoltInputTest, ReadMicrovoltsWithBipolarReferenceAtHalf) {
223 TestMicrovoltInput voltage_input =
224 TestMicrovoltInput({.min = kLimitsMin, .max = kLimitsMax},
225 {.max_voltage_uv = kBipolarReferenceMaxVoltageUv,
226 .min_voltage_uv = kBipolarReferenceMinVoltageUv});
227 voltage_input.SetSampleValue(kLimitsMax / 2);
228
229 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
230 ASSERT_TRUE(result.status().ok());
231
232 EXPECT_EQ(result.value(), 0);
233 }
234
TEST(MicrovoltInputTest,ReadMicrovoltsWithSampleAtMinCornerCase)235 TEST(MicrovoltInputTest, ReadMicrovoltsWithSampleAtMinCornerCase) {
236 TestMicrovoltInput voltage_input =
237 TestMicrovoltInput({.min = kCornerLimitsMin, .max = kCornerLimitsMax},
238 {.max_voltage_uv = kCornerReferenceMaxVoltageUv,
239 .min_voltage_uv = kCornerReferenceMinVoltageUv});
240 voltage_input.SetSampleValue(kCornerLimitsMin);
241
242 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
243 ASSERT_EQ(result.status(), pw::Status::Internal());
244 }
245
TEST(MicrovoltInputTest,ReadMicrovoltsWithSampleAtMaxCornerCase)246 TEST(MicrovoltInputTest, ReadMicrovoltsWithSampleAtMaxCornerCase) {
247 TestMicrovoltInput voltage_input =
248 TestMicrovoltInput({.min = kCornerLimitsMin, .max = kCornerLimitsMax},
249 {.max_voltage_uv = kCornerReferenceMaxVoltageUv,
250 .min_voltage_uv = kCornerReferenceMinVoltageUv});
251 voltage_input.SetSampleValue(kCornerLimitsMax);
252
253 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
254 ASSERT_EQ(result.status(), pw::Status::Internal());
255 }
256
TEST(MicrovoltInputTest,ReadMicrovoltsWithInvertedReferenceAtMax)257 TEST(MicrovoltInputTest, ReadMicrovoltsWithInvertedReferenceAtMax) {
258 TestMicrovoltInput voltage_input =
259 TestMicrovoltInput({.min = kInvertedLimitsMin, .max = kInvertedLimitsMax},
260 {.max_voltage_uv = kInvertedReferenceMaxVoltageUv,
261 .min_voltage_uv = kInvertedReferenceMinVoltageUv});
262 voltage_input.SetSampleValue(kInvertedLimitsMax);
263
264 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
265 ASSERT_EQ(result.status(), pw::Status::Internal());
266 }
267
TEST(MicrovoltInputTest,ReadMicrovoltsWithInvertedReferenceAtMin)268 TEST(MicrovoltInputTest, ReadMicrovoltsWithInvertedReferenceAtMin) {
269 TestMicrovoltInput voltage_input =
270 TestMicrovoltInput({.min = kInvertedLimitsMin, .max = kInvertedLimitsMax},
271 {.max_voltage_uv = kInvertedReferenceMaxVoltageUv,
272 .min_voltage_uv = kInvertedReferenceMinVoltageUv});
273 voltage_input.SetSampleValue(kInvertedLimitsMin);
274
275 Result<int32_t> result = voltage_input.TryReadMicrovoltsFor(kTimeout);
276 ASSERT_EQ(result.status(), pw::Status::Internal());
277 }
278
279 } // namespace
280 } // namespace analog
281 } // namespace pw
282