xref: /aosp_15_r20/external/pigweed/pw_digital_io/digital_io_test.cc (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 
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