blob: c13d1450f5d810ba44497941f40fc83e4d28662f [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2014. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include <Counter.h>
9#include <DigitalInput.h>
10#include <DigitalOutput.h>
11#include <Timer.h>
12#include "gtest/gtest.h"
13#include "TestBench.h"
14
15static const double kCounterTime = 0.001;
16
17static const double kDelayTime = 0.1;
18
19static const double kSynchronousInterruptTime = 2.0;
20static const double kSynchronousInterruptTimeTolerance = 0.01;
21
22/**
23 * A fixture with a digital input and a digital output physically wired
24 * together.
25 */
26class DIOLoopTest : public testing::Test {
27 protected:
28 DigitalInput *m_input;
29 DigitalOutput *m_output;
30
31 virtual void SetUp() override {
32 m_input = new DigitalInput(TestBench::kLoop1InputChannel);
33 m_output = new DigitalOutput(TestBench::kLoop1OutputChannel);
34 }
35
36 virtual void TearDown() override {
37 delete m_input;
38 delete m_output;
39 }
40
41 void Reset() { m_output->Set(false); }
42};
43
44/**
45 * Test the DigitalInput and DigitalOutput classes by setting the output and
46 * reading the input.
47 */
48TEST_F(DIOLoopTest, Loop) {
49 Reset();
50
51 m_output->Set(false);
52 Wait(kDelayTime);
53 EXPECT_FALSE(m_input->Get()) << "The digital output was turned off, but "
54 << "the digital input is on.";
55
56 m_output->Set(true);
57 Wait(kDelayTime);
58 EXPECT_TRUE(m_input->Get()) << "The digital output was turned on, but "
59 << "the digital input is off.";
60}
61
62/**
63 * Test a fake "counter" that uses the DIO loop as an input to make sure the
64 * Counter class works
65 */
66TEST_F(DIOLoopTest, FakeCounter) {
67 Reset();
68
69 Counter counter(m_input);
70
71 EXPECT_EQ(0, counter.Get()) << "Counter did not initialize to 0.";
72
73 /* Count 100 ticks. The counter value should be 100 after this loop. */
74 for (int i = 0; i < 100; i++) {
75 m_output->Set(true);
76 Wait(kCounterTime);
77 m_output->Set(false);
78 Wait(kCounterTime);
79 }
80
81 EXPECT_EQ(100, counter.Get()) << "Counter did not count up to 100.";
82}
83
84static void InterruptHandler(uint32_t interruptAssertedMask, void *param) {
85 *(int *)param = 12345;
86}
87
88TEST_F(DIOLoopTest, AsynchronousInterruptWorks) {
89 int param = 0;
90
91 // Given an interrupt handler that sets an int to 12345
92 m_input->RequestInterrupts(InterruptHandler, &param);
93 m_input->EnableInterrupts();
94
95 // If the voltage rises
96 m_output->Set(false);
97 m_output->Set(true);
98 m_input->CancelInterrupts();
99
100 // Then the int should be 12345
101 Wait(kDelayTime);
102 EXPECT_EQ(12345, param) << "The interrupt did not run.";
103}
104
105static void *InterruptTriggerer(void *data) {
106 DigitalOutput *output = static_cast<DigitalOutput *>(data);
107 output->Set(false);
108 Wait(kSynchronousInterruptTime);
109 output->Set(true);
110 return nullptr;
111}
112
113TEST_F(DIOLoopTest, SynchronousInterruptWorks) {
114 // Given a synchronous interrupt
115 m_input->RequestInterrupts();
116
117 // If we have another thread trigger the interrupt in a few seconds
118 pthread_t interruptTriggererLoop;
119 pthread_create(&interruptTriggererLoop, nullptr, InterruptTriggerer, m_output);
120
121 // Then this thread should pause and resume after that number of seconds
122 Timer timer;
123 timer.Start();
124 m_input->WaitForInterrupt(kSynchronousInterruptTime + 1.0);
125 EXPECT_NEAR(kSynchronousInterruptTime, timer.Get(),
126 kSynchronousInterruptTimeTolerance);
127}