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