blob: edbf592618abef0e9202e1cff40a5de0c250d088 [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_digital_io/digital_io.h"
#include "gtest/gtest.h"
#include "pw_status/status.h"
namespace pw::digital_io {
namespace {
// The base class should be compact.
static_assert(sizeof(DigitalIoOptional) <= 2 * sizeof(void*),
"DigitalIo should be no larger than two pointers (vtable pointer "
"& packed members)");
// Skeleton implementations to test DigitalIo methods.
class TestDigitalInterrupt : public DigitalInterrupt {
public:
TestDigitalInterrupt() = default;
private:
Status DoEnable(bool) override { return OkStatus(); }
Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
return OkStatus();
}
Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
};
class TestDigitalIn : public DigitalIn {
public:
TestDigitalIn() : state_(State::kInactive) {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Result<State> DoGetState() override { return state_; }
const State state_;
};
class TestDigitalInInterrupt : public DigitalInInterrupt {
public:
TestDigitalInInterrupt() : state_(State::kInactive) {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Result<State> DoGetState() override { return state_; }
Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
return OkStatus();
}
Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
const State state_;
};
class TestDigitalOut : public DigitalOut {
public:
TestDigitalOut() {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Status DoSetState(State) override { return OkStatus(); }
};
class TestDigitalOutInterrupt : public DigitalOutInterrupt {
public:
TestDigitalOutInterrupt() {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Status DoSetState(State) override { return OkStatus(); }
Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
return OkStatus();
}
Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
};
class TestDigitalInOut : public DigitalInOut {
public:
TestDigitalInOut() : state_(State::kInactive) {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Result<State> DoGetState() override { return state_; }
Status DoSetState(State state) override {
state_ = state;
return OkStatus();
}
State state_;
};
class TestDigitalInOutInterrupt : public DigitalInOutInterrupt {
public:
TestDigitalInOutInterrupt() : state_(State::kInactive) {}
private:
Status DoEnable(bool) override { return OkStatus(); }
Result<State> DoGetState() override { return state_; }
Status DoSetState(State state) override {
state_ = state;
return OkStatus();
}
Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) override {
return OkStatus();
}
Status DoEnableInterruptHandler(bool) override { return OkStatus(); }
State state_;
};
// Test conversions between different interfaces.
static_assert(!std::is_convertible<TestDigitalInterrupt, DigitalIn&>());
static_assert(!std::is_convertible<TestDigitalInterrupt, DigitalOut&>());
static_assert(
!std::is_convertible<TestDigitalInterrupt, DigitalInInterrupt&>());
static_assert(
!std::is_convertible<TestDigitalInterrupt, DigitalOutInterrupt&>());
static_assert(
!std::is_convertible<TestDigitalInterrupt, DigitalInOutInterrupt&>());
static_assert(!std::is_convertible<TestDigitalIn, DigitalOut&>());
static_assert(!std::is_convertible<TestDigitalIn, DigitalInterrupt&>());
static_assert(!std::is_convertible<TestDigitalIn, DigitalInInterrupt&>());
static_assert(!std::is_convertible<TestDigitalIn, DigitalOutInterrupt&>());
static_assert(std::is_convertible<TestDigitalInInterrupt, DigitalIn&>());
static_assert(!std::is_convertible<TestDigitalInInterrupt, DigitalOut&>());
static_assert(std::is_convertible<TestDigitalInInterrupt, DigitalInterrupt&>());
static_assert(
!std::is_convertible<TestDigitalInInterrupt, DigitalOutInterrupt&>());
static_assert(!std::is_convertible<TestDigitalOut, DigitalIn&>());
static_assert(!std::is_convertible<TestDigitalOut, DigitalInterrupt&>());
static_assert(!std::is_convertible<TestDigitalOut, DigitalInInterrupt&>());
static_assert(!std::is_convertible<TestDigitalOut, DigitalOutInterrupt&>());
static_assert(!std::is_convertible<TestDigitalOutInterrupt, DigitalIn&>());
static_assert(std::is_convertible<TestDigitalOutInterrupt, DigitalOut&>());
static_assert(
std::is_convertible<TestDigitalOutInterrupt, DigitalInterrupt&>());
static_assert(
!std::is_convertible<TestDigitalOutInterrupt, DigitalInInterrupt&>());
static_assert(std::is_convertible<TestDigitalInOut, DigitalIn&>());
static_assert(std::is_convertible<TestDigitalInOut, DigitalOut&>());
static_assert(!std::is_convertible<TestDigitalInOut, DigitalInterrupt&>());
static_assert(!std::is_convertible<TestDigitalInOut, DigitalInInterrupt&>());
static_assert(!std::is_convertible<TestDigitalInOut, DigitalOutInterrupt&>());
static_assert(std::is_convertible<TestDigitalInOutInterrupt, DigitalIn&>());
static_assert(std::is_convertible<TestDigitalInOutInterrupt, DigitalOut&>());
static_assert(
std::is_convertible<TestDigitalInOutInterrupt, DigitalInterrupt&>());
static_assert(
std::is_convertible<TestDigitalInOutInterrupt, DigitalInInterrupt&>());
static_assert(
std::is_convertible<TestDigitalInOutInterrupt, DigitalOutInterrupt&>());
void FakeInterruptHandler(State) {}
template <typename Line>
void TestInput(Line& line) {
ASSERT_EQ(OkStatus(), line.Enable());
auto state_result = line.GetState();
ASSERT_EQ(OkStatus(), state_result.status());
ASSERT_EQ(State::kInactive, state_result.value());
auto active_result = line.IsStateActive();
ASSERT_EQ(OkStatus(), active_result.status());
ASSERT_EQ(false, active_result.value());
ASSERT_EQ(OkStatus(), line.Disable());
}
template <typename Line>
void TestOutput(Line& line) {
ASSERT_EQ(OkStatus(), line.Enable());
ASSERT_EQ(OkStatus(), line.SetState(State::kActive));
ASSERT_EQ(OkStatus(), line.SetState(State::kInactive));
ASSERT_EQ(OkStatus(), line.SetStateActive());
ASSERT_EQ(OkStatus(), line.SetStateInactive());
ASSERT_EQ(OkStatus(), line.Disable());
}
template <typename Line>
void TestOutputReadback(Line& line) {
ASSERT_EQ(OkStatus(), line.Enable());
ASSERT_EQ(OkStatus(), line.SetState(State::kActive));
auto state_result = line.GetState();
ASSERT_EQ(OkStatus(), state_result.status());
ASSERT_EQ(State::kActive, state_result.value());
ASSERT_EQ(OkStatus(), line.SetState(State::kInactive));
state_result = line.GetState();
ASSERT_EQ(OkStatus(), state_result.status());
ASSERT_EQ(State::kInactive, state_result.value());
ASSERT_EQ(OkStatus(), line.SetStateActive());
auto active_result = line.IsStateActive();
ASSERT_EQ(OkStatus(), active_result.status());
ASSERT_EQ(true, active_result.value());
ASSERT_EQ(OkStatus(), line.SetStateInactive());
active_result = line.IsStateActive();
ASSERT_EQ(OkStatus(), active_result.status());
ASSERT_EQ(false, active_result.value());
ASSERT_EQ(OkStatus(), line.Disable());
}
template <typename Line>
void TestInterrupt(Line& line) {
ASSERT_EQ(OkStatus(), line.Enable());
ASSERT_EQ(OkStatus(),
line.SetInterruptHandler(InterruptTrigger::kBothEdges,
FakeInterruptHandler));
ASSERT_EQ(OkStatus(), line.EnableInterruptHandler());
ASSERT_EQ(OkStatus(), line.EnableInterruptHandler());
ASSERT_EQ(OkStatus(), line.DisableInterruptHandler());
ASSERT_EQ(OkStatus(), line.ClearInterruptHandler());
ASSERT_EQ(OkStatus(), line.Disable());
}
TEST(Digital, Interrupt) {
TestDigitalInterrupt line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(false, optional_line.provides_input());
ASSERT_EQ(false, optional_line.provides_output());
ASSERT_EQ(true, optional_line.provides_interrupt());
TestInterrupt(line);
TestInterrupt(optional_line);
}
TEST(Digital, In) {
TestDigitalIn line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(true, optional_line.provides_input());
ASSERT_EQ(false, optional_line.provides_output());
ASSERT_EQ(false, optional_line.provides_interrupt());
TestInput(line);
TestInput(optional_line);
}
TEST(Digital, InInterrupt) {
TestDigitalInInterrupt line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(true, optional_line.provides_input());
ASSERT_EQ(false, optional_line.provides_output());
ASSERT_EQ(true, optional_line.provides_interrupt());
TestInput(line);
TestInterrupt(line);
TestInput(optional_line);
TestInterrupt(optional_line);
}
TEST(Digital, Out) {
TestDigitalOut line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(false, optional_line.provides_input());
ASSERT_EQ(true, optional_line.provides_output());
ASSERT_EQ(false, optional_line.provides_interrupt());
TestOutput(line);
TestOutput(optional_line);
}
TEST(Digital, OutInterrupt) {
TestDigitalOutInterrupt line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(false, optional_line.provides_input());
ASSERT_EQ(true, optional_line.provides_output());
ASSERT_EQ(true, optional_line.provides_interrupt());
TestOutput(line);
TestInterrupt(line);
TestOutput(optional_line);
TestInterrupt(optional_line);
}
TEST(Digital, InOut) {
TestDigitalInOut line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(true, optional_line.provides_input());
ASSERT_EQ(true, optional_line.provides_output());
ASSERT_EQ(false, optional_line.provides_interrupt());
TestInput(line);
TestOutput(line);
TestOutputReadback(line);
TestInput(optional_line);
TestOutput(optional_line);
TestOutputReadback(optional_line);
}
TEST(DigitalIo, InOutInterrupt) {
TestDigitalInOutInterrupt line;
DigitalIoOptional& optional_line = line;
ASSERT_EQ(true, optional_line.provides_input());
ASSERT_EQ(true, optional_line.provides_output());
ASSERT_EQ(true, optional_line.provides_interrupt());
TestInput(line);
TestOutput(line);
TestOutputReadback(line);
TestInterrupt(line);
TestInput(optional_line);
TestOutput(optional_line);
TestOutputReadback(optional_line);
TestInterrupt(optional_line);
}
} // namespace
} // namespace pw::digital_io