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
15 #include "pw_digital_io/digital_io.h"
16
17 #include "pw_status/status.h"
18 #include "pw_unit_test/framework.h"
19
20 namespace pw::digital_io {
21 namespace {
22
23 // The base class should be compact.
24 static_assert(sizeof(DigitalIoOptional) <= 2 * sizeof(void*),
25 "DigitalIo should be no larger than two pointers (vtable pointer "
26 "& packed members)");
27
28 // Skeleton implementations to test DigitalIo methods.
29 class TestDigitalInterrupt : public DigitalInterrupt {
30 public:
31 TestDigitalInterrupt() = default;
32
33 private:
DoEnable(bool)34 Status DoEnable(bool) override { return OkStatus(); }
35
DoSetInterruptHandler(InterruptTrigger,InterruptHandler &&)36 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
37 return OkStatus();
38 }
DoEnableInterruptHandler(bool)39 Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
40 };
41
42 class TestDigitalIn : public DigitalIn {
43 public:
TestDigitalIn()44 TestDigitalIn() : state_(State::kInactive) {}
45
46 private:
DoEnable(bool)47 Status DoEnable(bool) override { return OkStatus(); }
DoGetState()48 Result<State> DoGetState() override { return state_; }
49
50 const State state_;
51 };
52
53 class TestDigitalInInterrupt : public DigitalInInterrupt {
54 public:
TestDigitalInInterrupt()55 TestDigitalInInterrupt() : state_(State::kInactive) {}
56
57 private:
DoEnable(bool)58 Status DoEnable(bool) override { return OkStatus(); }
DoGetState()59 Result<State> DoGetState() override { return state_; }
60
DoSetInterruptHandler(InterruptTrigger,InterruptHandler &&)61 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
62 return OkStatus();
63 }
DoEnableInterruptHandler(bool)64 Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
65
66 const State state_;
67 };
68
69 class TestDigitalOut : public DigitalOut {
70 public:
TestDigitalOut()71 TestDigitalOut() {}
72
73 private:
DoEnable(bool)74 Status DoEnable(bool) override { return OkStatus(); }
DoSetState(State)75 Status DoSetState(State) override { return OkStatus(); }
76 };
77
78 class TestDigitalOutInterrupt : public DigitalOutInterrupt {
79 public:
TestDigitalOutInterrupt()80 TestDigitalOutInterrupt() {}
81
82 private:
DoEnable(bool)83 Status DoEnable(bool) override { return OkStatus(); }
DoSetState(State)84 Status DoSetState(State) override { return OkStatus(); }
85
DoSetInterruptHandler(InterruptTrigger,InterruptHandler &&)86 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
87 return OkStatus();
88 }
DoEnableInterruptHandler(bool)89 Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
90 };
91
92 class TestDigitalInOut : public DigitalInOut {
93 public:
TestDigitalInOut()94 TestDigitalInOut() : state_(State::kInactive) {}
95
96 private:
DoEnable(bool)97 Status DoEnable(bool) override { return OkStatus(); }
DoGetState()98 Result<State> DoGetState() override { return state_; }
DoSetState(State state)99 Status DoSetState(State state) override {
100 state_ = state;
101 return OkStatus();
102 }
103
104 State state_;
105 };
106
107 class TestDigitalInOutInterrupt : public DigitalInOutInterrupt {
108 public:
TestDigitalInOutInterrupt()109 TestDigitalInOutInterrupt() : state_(State::kInactive) {}
110
111 private:
DoEnable(bool)112 Status DoEnable(bool) override { return OkStatus(); }
DoGetState()113 Result<State> DoGetState() override { return state_; }
DoSetState(State state)114 Status DoSetState(State state) override {
115 state_ = state;
116 return OkStatus();
117 }
118
DoSetInterruptHandler(InterruptTrigger,InterruptHandler &&)119 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
120 return OkStatus();
121 }
DoEnableInterruptHandler(bool)122 Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
123
124 State state_;
125 };
126
127 // Test conversions between different interfaces.
128 static_assert(!std::is_convertible<TestDigitalInterrupt, DigitalIn&>());
129 static_assert(!std::is_convertible<TestDigitalInterrupt, DigitalOut&>());
130 static_assert(
131 !std::is_convertible<TestDigitalInterrupt, DigitalInInterrupt&>());
132 static_assert(
133 !std::is_convertible<TestDigitalInterrupt, DigitalOutInterrupt&>());
134 static_assert(
135 !std::is_convertible<TestDigitalInterrupt, DigitalInOutInterrupt&>());
136
137 static_assert(!std::is_convertible<TestDigitalIn, DigitalOut&>());
138 static_assert(!std::is_convertible<TestDigitalIn, DigitalInterrupt&>());
139 static_assert(!std::is_convertible<TestDigitalIn, DigitalInInterrupt&>());
140 static_assert(!std::is_convertible<TestDigitalIn, DigitalOutInterrupt&>());
141
142 static_assert(std::is_convertible<TestDigitalInInterrupt, DigitalIn&>());
143 static_assert(!std::is_convertible<TestDigitalInInterrupt, DigitalOut&>());
144 static_assert(std::is_convertible<TestDigitalInInterrupt, DigitalInterrupt&>());
145 static_assert(
146 !std::is_convertible<TestDigitalInInterrupt, DigitalOutInterrupt&>());
147
148 static_assert(!std::is_convertible<TestDigitalOut, DigitalIn&>());
149 static_assert(!std::is_convertible<TestDigitalOut, DigitalInterrupt&>());
150 static_assert(!std::is_convertible<TestDigitalOut, DigitalInInterrupt&>());
151 static_assert(!std::is_convertible<TestDigitalOut, DigitalOutInterrupt&>());
152
153 static_assert(!std::is_convertible<TestDigitalOutInterrupt, DigitalIn&>());
154 static_assert(std::is_convertible<TestDigitalOutInterrupt, DigitalOut&>());
155 static_assert(
156 std::is_convertible<TestDigitalOutInterrupt, DigitalInterrupt&>());
157 static_assert(
158 !std::is_convertible<TestDigitalOutInterrupt, DigitalInInterrupt&>());
159
160 static_assert(std::is_convertible<TestDigitalInOut, DigitalIn&>());
161 static_assert(std::is_convertible<TestDigitalInOut, DigitalOut&>());
162 static_assert(!std::is_convertible<TestDigitalInOut, DigitalInterrupt&>());
163 static_assert(!std::is_convertible<TestDigitalInOut, DigitalInInterrupt&>());
164 static_assert(!std::is_convertible<TestDigitalInOut, DigitalOutInterrupt&>());
165
166 static_assert(std::is_convertible<TestDigitalInOutInterrupt, DigitalIn&>());
167 static_assert(std::is_convertible<TestDigitalInOutInterrupt, DigitalOut&>());
168 static_assert(
169 std::is_convertible<TestDigitalInOutInterrupt, DigitalInterrupt&>());
170 static_assert(
171 std::is_convertible<TestDigitalInOutInterrupt, DigitalInInterrupt&>());
172 static_assert(
173 std::is_convertible<TestDigitalInOutInterrupt, DigitalOutInterrupt&>());
174
FakeInterruptHandler(State)175 void FakeInterruptHandler(State) {}
176
177 template <typename Line>
TestInput(Line & line)178 void TestInput(Line& line) {
179 ASSERT_EQ(OkStatus(), line.Enable());
180
181 auto state_result = line.GetState();
182 ASSERT_EQ(OkStatus(), state_result.status());
183 ASSERT_EQ(State::kInactive, state_result.value());
184
185 auto active_result = line.IsStateActive();
186 ASSERT_EQ(OkStatus(), active_result.status());
187 ASSERT_EQ(false, active_result.value());
188
189 ASSERT_EQ(OkStatus(), line.Disable());
190 }
191
192 template <typename Line>
TestOutput(Line & line)193 void TestOutput(Line& line) {
194 ASSERT_EQ(OkStatus(), line.Enable());
195
196 ASSERT_EQ(OkStatus(), line.SetState(State::kActive));
197 ASSERT_EQ(OkStatus(), line.SetState(State::kInactive));
198
199 ASSERT_EQ(OkStatus(), line.SetStateActive());
200 ASSERT_EQ(OkStatus(), line.SetStateInactive());
201
202 ASSERT_EQ(OkStatus(), line.Disable());
203 }
204
205 template <typename Line>
TestOutputReadback(Line & line)206 void TestOutputReadback(Line& line) {
207 ASSERT_EQ(OkStatus(), line.Enable());
208
209 ASSERT_EQ(OkStatus(), line.SetState(State::kActive));
210 auto state_result = line.GetState();
211 ASSERT_EQ(OkStatus(), state_result.status());
212 ASSERT_EQ(State::kActive, state_result.value());
213
214 ASSERT_EQ(OkStatus(), line.SetState(State::kInactive));
215 state_result = line.GetState();
216 ASSERT_EQ(OkStatus(), state_result.status());
217 ASSERT_EQ(State::kInactive, state_result.value());
218
219 ASSERT_EQ(OkStatus(), line.SetStateActive());
220 auto active_result = line.IsStateActive();
221 ASSERT_EQ(OkStatus(), active_result.status());
222 ASSERT_EQ(true, active_result.value());
223
224 ASSERT_EQ(OkStatus(), line.SetStateInactive());
225 active_result = line.IsStateActive();
226 ASSERT_EQ(OkStatus(), active_result.status());
227 ASSERT_EQ(false, active_result.value());
228
229 ASSERT_EQ(OkStatus(), line.Disable());
230 }
231
232 template <typename Line>
TestInterrupt(Line & line)233 void TestInterrupt(Line& line) {
234 ASSERT_EQ(OkStatus(), line.Enable());
235
236 ASSERT_EQ(OkStatus(),
237 line.SetInterruptHandler(InterruptTrigger::kBothEdges,
238 FakeInterruptHandler));
239 ASSERT_EQ(OkStatus(), line.EnableInterruptHandler());
240 ASSERT_EQ(OkStatus(), line.EnableInterruptHandler());
241 ASSERT_EQ(OkStatus(), line.DisableInterruptHandler());
242 ASSERT_EQ(OkStatus(), line.ClearInterruptHandler());
243
244 ASSERT_EQ(OkStatus(), line.Disable());
245 }
246
TEST(Digital,Interrupt)247 TEST(Digital, Interrupt) {
248 TestDigitalInterrupt line;
249 DigitalIoOptional& optional_line = line;
250
251 ASSERT_EQ(false, optional_line.provides_input());
252 ASSERT_EQ(false, optional_line.provides_output());
253 ASSERT_EQ(true, optional_line.provides_interrupt());
254
255 TestInterrupt(line);
256 TestInterrupt(optional_line);
257 }
258
TEST(Digital,In)259 TEST(Digital, In) {
260 TestDigitalIn line;
261 DigitalIoOptional& optional_line = line;
262
263 ASSERT_EQ(true, optional_line.provides_input());
264 ASSERT_EQ(false, optional_line.provides_output());
265 ASSERT_EQ(false, optional_line.provides_interrupt());
266
267 TestInput(line);
268 TestInput(optional_line);
269 }
270
TEST(Digital,InInterrupt)271 TEST(Digital, InInterrupt) {
272 TestDigitalInInterrupt line;
273 DigitalIoOptional& optional_line = line;
274
275 ASSERT_EQ(true, optional_line.provides_input());
276 ASSERT_EQ(false, optional_line.provides_output());
277 ASSERT_EQ(true, optional_line.provides_interrupt());
278
279 TestInput(line);
280 TestInterrupt(line);
281
282 TestInput(optional_line);
283 TestInterrupt(optional_line);
284 }
285
TEST(Digital,Out)286 TEST(Digital, Out) {
287 TestDigitalOut line;
288 DigitalIoOptional& optional_line = line;
289
290 ASSERT_EQ(false, optional_line.provides_input());
291 ASSERT_EQ(true, optional_line.provides_output());
292 ASSERT_EQ(false, optional_line.provides_interrupt());
293
294 TestOutput(line);
295 TestOutput(optional_line);
296 }
297
TEST(Digital,OutInterrupt)298 TEST(Digital, OutInterrupt) {
299 TestDigitalOutInterrupt line;
300 DigitalIoOptional& optional_line = line;
301
302 ASSERT_EQ(false, optional_line.provides_input());
303 ASSERT_EQ(true, optional_line.provides_output());
304 ASSERT_EQ(true, optional_line.provides_interrupt());
305
306 TestOutput(line);
307 TestInterrupt(line);
308
309 TestOutput(optional_line);
310 TestInterrupt(optional_line);
311 }
312
TEST(Digital,InOut)313 TEST(Digital, InOut) {
314 TestDigitalInOut line;
315 DigitalIoOptional& optional_line = line;
316
317 ASSERT_EQ(true, optional_line.provides_input());
318 ASSERT_EQ(true, optional_line.provides_output());
319 ASSERT_EQ(false, optional_line.provides_interrupt());
320
321 TestInput(line);
322 TestOutput(line);
323 TestOutputReadback(line);
324
325 TestInput(optional_line);
326 TestOutput(optional_line);
327 TestOutputReadback(optional_line);
328 }
329
TEST(DigitalIo,InOutInterrupt)330 TEST(DigitalIo, InOutInterrupt) {
331 TestDigitalInOutInterrupt line;
332 DigitalIoOptional& optional_line = line;
333
334 ASSERT_EQ(true, optional_line.provides_input());
335 ASSERT_EQ(true, optional_line.provides_output());
336 ASSERT_EQ(true, optional_line.provides_interrupt());
337
338 TestInput(line);
339 TestOutput(line);
340 TestOutputReadback(line);
341 TestInterrupt(line);
342
343 TestInput(optional_line);
344 TestOutput(optional_line);
345 TestOutputReadback(optional_line);
346 TestInterrupt(optional_line);
347 }
348
349 } // namespace
350 } // namespace pw::digital_io
351