[examples] DigitalCommunication, I2CCommunication: Add tests (#4865)

This commit is contained in:
Starlight220
2023-01-09 02:33:53 +02:00
committed by GitHub
parent 2cd9be413f
commit 79f565191e
13 changed files with 709 additions and 74 deletions

View File

@@ -2,45 +2,28 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <frc/DigitalOutput.h>
#include "Robot.h"
#include <frc/DriverStation.h>
#include <frc/TimedRobot.h>
/**
* This is a sample program demonstrating how to communicate to a light
* controller from the robot code using the roboRIO's DIO ports.
*/
class Robot : public frc::TimedRobot {
public:
void RobotPeriodic() override {
// pull alliance port high if on red alliance, pull low if on blue alliance
m_allianceOutput.Set(frc::DriverStation::GetAlliance() ==
frc::DriverStation::kRed);
void Robot::RobotPeriodic() {
// pull alliance port high if on red alliance, pull low if on blue alliance
m_allianceOutput.Set(frc::DriverStation::GetAlliance() ==
frc::DriverStation::kRed);
// pull enabled port high if enabled, low if disabled
m_enabledOutput.Set(frc::DriverStation::IsEnabled());
// pull enabled port high if enabled, low if disabled
m_enabledOutput.Set(frc::DriverStation::IsEnabled());
// pull auto port high if in autonomous, low if in teleop (or disabled)
m_autonomousOutput.Set(frc::DriverStation::IsAutonomous());
// pull auto port high if in autonomous, low if in teleop (or disabled)
m_autonomousOutput.Set(frc::DriverStation::IsAutonomous());
// pull alert port high if match time remaining is between 30 and 25 seconds
auto matchTime = frc::DriverStation::GetMatchTime();
m_alertOutput.Set(matchTime <= 30 && matchTime >= 25);
}
private:
// define ports for communication with light controller
static constexpr int kAlliancePort = 0;
static constexpr int kEnabledPort = 1;
static constexpr int kAutonomousPort = 2;
static constexpr int kAlertPort = 3;
frc::DigitalOutput m_allianceOutput{kAlliancePort};
frc::DigitalOutput m_enabledOutput{kEnabledPort};
frc::DigitalOutput m_autonomousOutput{kAutonomousPort};
frc::DigitalOutput m_alertOutput{kAlertPort};
};
// pull alert port high if match time remaining is between 30 and 25 seconds
auto matchTime = frc::DriverStation::GetMatchTime();
m_alertOutput.Set(matchTime <= 30 && matchTime >= 25);
}
#ifndef RUNNING_FRC_TESTS
int main() {
return frc::StartRobot<Robot>();
}
#endif

View File

@@ -0,0 +1,31 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <array>
#include <frc/DigitalOutput.h>
#include <frc/TimedRobot.h>
/**
* This is a sample program demonstrating how to communicate to a light
* controller from the robot code using the roboRIO's DIO ports.
*/
class Robot : public frc::TimedRobot {
public:
// define ports for communication with light controller
static constexpr int kAlliancePort = 0;
static constexpr int kEnabledPort = 1;
static constexpr int kAutonomousPort = 2;
static constexpr int kAlertPort = 3;
void RobotPeriodic() override;
private:
frc::DigitalOutput m_allianceOutput{kAlliancePort};
frc::DigitalOutput m_enabledOutput{kEnabledPort};
frc::DigitalOutput m_autonomousOutput{kAutonomousPort};
frc::DigitalOutput m_alertOutput{kAlertPort};
};

View File

@@ -2,45 +2,34 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "Robot.h"
#include <fmt/format.h>
#include <frc/DriverStation.h>
#include <frc/I2C.h>
#include <frc/TimedRobot.h>
#include <frc/Timer.h>
/**
* This is a sample program demonstrating how to communicate to a light
* controller from the robot code using the roboRIO's I2C port.
*/
class Robot : public frc::TimedRobot {
public:
void RobotPeriodic() override {
// Creates a string to hold current robot state information, including
// alliance, enabled state, operation mode, and match time. The message
// is sent in format "AEM###" where A is the alliance color, (R)ed or
// (B)lue, E is the enabled state, (E)nabled or (D)isabled, M is the
// operation mode, (A)utonomous or (T)eleop, and ### is the zero-padded
// time remaining in the match.
//
// For example, "RET043" would indicate that the robot is on the red
// alliance, enabled in teleop mode, with 43 seconds left in the match.
auto string = fmt::format(
"{}{}{}{:03}",
frc::DriverStation::GetAlliance() == frc::DriverStation::Alliance::kRed
? "R"
: "B",
frc::DriverStation::IsEnabled() ? "E" : "D",
frc::DriverStation::IsAutonomous() ? "A" : "T",
static_cast<int>(frc::Timer::GetMatchTime().value()));
void Robot::RobotPeriodic() {
// Creates a string to hold current robot state information, including
// alliance, enabled state, operation mode, and match time. The message
// is sent in format "AEM###" where A is the alliance color, (R)ed or
// (B)lue, E is the enabled state, (E)nabled or (D)isabled, M is the
// operation mode, (A)utonomous or (T)eleop, and ### is the zero-padded
// time remaining in the match.
//
// For example, "RET043" would indicate that the robot is on the red
// alliance, enabled in teleop mode, with 43 seconds left in the match.
auto string = fmt::format(
"{}{}{}{:03}",
frc::DriverStation::GetAlliance() == frc::DriverStation::Alliance::kRed
? "R"
: "B",
frc::DriverStation::IsEnabled() ? "E" : "D",
frc::DriverStation::IsAutonomous() ? "A" : "T",
static_cast<int>(frc::Timer::GetMatchTime().value()));
arduino.WriteBulk(reinterpret_cast<uint8_t*>(string.data()), string.size());
}
private:
static constexpr int deviceAddress = 4;
frc::I2C arduino{frc::I2C::Port::kOnboard, deviceAddress};
};
arduino.WriteBulk(reinterpret_cast<uint8_t*>(string.data()), string.size());
}
#ifndef RUNNING_FRC_TESTS
int main() {

View File

@@ -0,0 +1,25 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <array>
#include <frc/I2C.h>
#include <frc/TimedRobot.h>
/**
* This is a sample program demonstrating how to communicate to a light
* controller from the robot code using the roboRIO's I2C port.
*/
class Robot : public frc::TimedRobot {
public:
void RobotPeriodic() override;
static constexpr frc::I2C::Port kPort = frc::I2C::Port::kOnboard;
private:
static constexpr int deviceAddress = 4;
frc::I2C arduino{kPort, deviceAddress};
};

View File

@@ -0,0 +1,153 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <gtest/gtest.h>
#include <string>
#include <thread>
#include <frc/simulation/DIOSim.h>
#include <frc/simulation/DriverStationSim.h>
#include <frc/simulation/SimHooks.h>
#include <units/time.h>
#include "Robot.h"
template <typename T>
class DigitalCommunicationTest : public testing::TestWithParam<T> {
public:
frc::sim::DIOSim m_allianceOutput{Robot::kAlliancePort};
frc::sim::DIOSim m_enabledOutput{Robot::kEnabledPort};
frc::sim::DIOSim m_autonomousOutput{Robot::kAutonomousPort};
frc::sim::DIOSim m_alertOutput{Robot::kAlertPort};
Robot m_robot;
std::optional<std::thread> m_thread;
void SetUp() override {
frc::sim::PauseTiming();
frc::sim::DriverStationSim::ResetData();
m_thread = std::thread([&] { m_robot.StartCompetition(); });
frc::sim::StepTiming(0.0_ms);
// SimHooks.stepTiming(0.0); // Wait for Notifiers
}
void TearDown() override {
m_robot.EndCompetition();
m_thread->join();
m_allianceOutput.ResetData();
m_enabledOutput.ResetData();
m_autonomousOutput.ResetData();
m_alertOutput.ResetData();
}
};
class AllianceTest : public DigitalCommunicationTest<HAL_AllianceStationID> {};
TEST_P(AllianceTest, Alliance) {
auto alliance = GetParam();
frc::sim::DriverStationSim::SetAllianceStationId(alliance);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_allianceOutput.GetInitialized());
EXPECT_FALSE(m_allianceOutput.GetIsInput());
frc::sim::StepTiming(20_ms);
bool isRed;
switch (alliance) {
case HAL_AllianceStationID_kBlue1:
case HAL_AllianceStationID_kBlue2:
case HAL_AllianceStationID_kBlue3:
isRed = false;
break;
case HAL_AllianceStationID_kRed1:
case HAL_AllianceStationID_kRed2:
case HAL_AllianceStationID_kRed3:
isRed = true;
break;
}
EXPECT_EQ(isRed, m_allianceOutput.GetValue());
}
INSTANTIATE_TEST_SUITE_P(
DigitalCommunicationTests, AllianceTest,
testing::Values<HAL_AllianceStationID>(
HAL_AllianceStationID_kRed1, HAL_AllianceStationID_kRed2,
HAL_AllianceStationID_kRed3, HAL_AllianceStationID_kBlue1,
HAL_AllianceStationID_kBlue2, HAL_AllianceStationID_kBlue3),
[](const testing::TestParamInfo<AllianceTest::ParamType>& info) {
switch (info.param) {
case HAL_AllianceStationID_kBlue1:
return std::string{"Blue1"};
case HAL_AllianceStationID_kBlue2:
return std::string{"Blue2"};
case HAL_AllianceStationID_kBlue3:
return std::string{"Blue3"};
case HAL_AllianceStationID_kRed1:
return std::string{"Red1"};
case HAL_AllianceStationID_kRed2:
return std::string{"Red2"};
case HAL_AllianceStationID_kRed3:
return std::string{"Red3"};
}
return std::string{"Error"};
});
class EnabledTest : public DigitalCommunicationTest<bool> {};
TEST_P(EnabledTest, Enabled) {
auto enabled = GetParam();
frc::sim::DriverStationSim::SetEnabled(enabled);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_enabledOutput.GetInitialized());
EXPECT_FALSE(m_enabledOutput.GetIsInput());
frc::sim::StepTiming(20_ms);
EXPECT_EQ(enabled, m_enabledOutput.GetValue());
}
INSTANTIATE_TEST_SUITE_P(DigitalCommunicationTests, EnabledTest,
testing::Bool(), testing::PrintToStringParamName());
class AutonomousTest : public DigitalCommunicationTest<bool> {};
TEST_P(AutonomousTest, Autonomous) {
auto autonomous = GetParam();
frc::sim::DriverStationSim::SetAutonomous(autonomous);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_autonomousOutput.GetInitialized());
EXPECT_FALSE(m_autonomousOutput.GetIsInput());
frc::sim::StepTiming(20_ms);
EXPECT_EQ(autonomous, m_autonomousOutput.GetValue());
}
INSTANTIATE_TEST_SUITE_P(DigitalCommunicationTests, AutonomousTest,
testing::Bool(), testing::PrintToStringParamName());
class AlertTest : public DigitalCommunicationTest<double> {};
TEST_P(AlertTest, Alert) {
auto matchTime = GetParam();
frc::sim::DriverStationSim::SetMatchTime(matchTime);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_alertOutput.GetInitialized());
EXPECT_FALSE(m_alertOutput.GetIsInput());
frc::sim::StepTiming(20_ms);
EXPECT_EQ(matchTime <= 30 && matchTime >= 25, m_alertOutput.GetValue());
}
INSTANTIATE_TEST_SUITE_P(
DigitalCommunicationTests, AlertTest, testing::Values(45.0, 27.0, 23.0),
[](const testing::TestParamInfo<double>& info) {
return testing::PrintToString(info.param).append("_s");
});

View File

@@ -0,0 +1,17 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <hal/HALBase.h>
#include "gtest/gtest.h"
/**
* Runs all unit tests.
*/
int main(int argc, char** argv) {
HAL_Initialize(500, 0);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}

View File

@@ -0,0 +1,160 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <gtest/gtest.h>
#include <string>
#include <thread>
#include <frc/simulation/DriverStationSim.h>
#include <frc/simulation/SimHooks.h>
#include <hal/simulation/I2CData.h>
#include <units/time.h>
#include "Robot.h"
static std::string gString;
void callback(const char* name, void* param, const unsigned char* buffer,
unsigned int count) {
gString.assign(reinterpret_cast<const char*>(buffer),
static_cast<int>(count));
}
template <typename T>
class I2CCommunicationTest : public testing::TestWithParam<T> {
public:
Robot m_robot;
std::optional<std::thread> m_thread;
int32_t m_callback;
int32_t m_port;
void SetUp() override {
gString = std::string();
frc::sim::PauseTiming();
frc::sim::DriverStationSim::ResetData();
m_port = static_cast<int32_t>(Robot::kPort);
m_callback = HALSIM_RegisterI2CWriteCallback(m_port, &callback, nullptr);
m_thread = std::thread([&] { m_robot.StartCompetition(); });
frc::sim::StepTiming(0.0_ms); // Wait for Notifiers
}
void TearDown() override {
m_robot.EndCompetition();
m_thread->join();
HALSIM_CancelI2CWriteCallback(m_port, m_callback);
HALSIM_ResetI2CData(m_port);
}
};
class AllianceTest : public I2CCommunicationTest<HAL_AllianceStationID> {};
TEST_P(AllianceTest, Alliance) {
auto alliance = GetParam();
frc::sim::DriverStationSim::SetAllianceStationId(alliance);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(HALSIM_GetI2CInitialized(m_port));
frc::sim::StepTiming(20_ms);
char expected;
switch (alliance) {
case HAL_AllianceStationID_kBlue1:
case HAL_AllianceStationID_kBlue2:
case HAL_AllianceStationID_kBlue3:
expected = 'B';
break;
case HAL_AllianceStationID_kRed1:
case HAL_AllianceStationID_kRed2:
case HAL_AllianceStationID_kRed3:
expected = 'R';
break;
}
EXPECT_EQ(expected, gString.at(0));
}
INSTANTIATE_TEST_SUITE_P(
I2CCommunicationTests, AllianceTest,
testing::Values<HAL_AllianceStationID>(
HAL_AllianceStationID_kRed1, HAL_AllianceStationID_kRed2,
HAL_AllianceStationID_kRed3, HAL_AllianceStationID_kBlue1,
HAL_AllianceStationID_kBlue2, HAL_AllianceStationID_kBlue3),
[](const testing::TestParamInfo<AllianceTest::ParamType>& info) {
switch (info.param) {
case HAL_AllianceStationID_kBlue1:
return std::string{"Blue1"};
case HAL_AllianceStationID_kBlue2:
return std::string{"Blue2"};
case HAL_AllianceStationID_kBlue3:
return std::string{"Blue3"};
case HAL_AllianceStationID_kRed1:
return std::string{"Red1"};
case HAL_AllianceStationID_kRed2:
return std::string{"Red2"};
case HAL_AllianceStationID_kRed3:
return std::string{"Red3"};
}
return std::string{"Error"};
});
class EnabledTest : public I2CCommunicationTest<bool> {};
TEST_P(EnabledTest, Enabled) {
auto enabled = GetParam();
frc::sim::DriverStationSim::SetEnabled(enabled);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(HALSIM_GetI2CInitialized(m_port));
frc::sim::StepTiming(20_ms);
char expected = enabled ? 'E' : 'D';
EXPECT_EQ(expected, gString.at(1));
}
INSTANTIATE_TEST_SUITE_P(I2CCommunicationTests, EnabledTest, testing::Bool(),
testing::PrintToStringParamName());
class AutonomousTest : public I2CCommunicationTest<bool> {};
TEST_P(AutonomousTest, Autonomous) {
auto autonomous = GetParam();
frc::sim::DriverStationSim::SetAutonomous(autonomous);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(HALSIM_GetI2CInitialized(m_port));
frc::sim::StepTiming(20_ms);
char expected = autonomous ? 'A' : 'T';
EXPECT_EQ(expected, gString.at(2));
}
INSTANTIATE_TEST_SUITE_P(I2CCommunicationTests, AutonomousTest, testing::Bool(),
testing::PrintToStringParamName());
class MatchTimeTest : public I2CCommunicationTest<int> {};
TEST_P(MatchTimeTest, Alert) {
auto matchTime = GetParam();
frc::sim::DriverStationSim::SetMatchTime(matchTime);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(HALSIM_GetI2CInitialized(m_port));
frc::sim::StepTiming(20_ms);
std::string expected = fmt::format("{:03}", matchTime);
EXPECT_EQ(expected, gString.substr(3));
}
INSTANTIATE_TEST_SUITE_P(
I2CCommunicationTests, MatchTimeTest, testing::Values(112, 45, 27, 23, 3),
[](const testing::TestParamInfo<int>& info) {
return testing::PrintToString(info.param).append("_s");
});

View File

@@ -0,0 +1,17 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <hal/HALBase.h>
#include "gtest/gtest.h"
/**
* Runs all unit tests.
*/
int main(int argc, char** argv) {
HAL_Initialize(500, 0);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}

View File

@@ -14,10 +14,10 @@ import edu.wpi.first.wpilibj.TimedRobot;
*/
public class Robot extends TimedRobot {
// define ports for digitalcommunication with light controller
private static final int kAlliancePort = 0;
private static final int kEnabledPort = 1;
private static final int kAutonomousPort = 2;
private static final int kAlertPort = 3;
static final int kAlliancePort = 0;
static final int kEnabledPort = 1;
static final int kAutonomousPort = 2;
static final int kAlertPort = 3;
private final DigitalOutput m_allianceOutput = new DigitalOutput(kAlliancePort);
private final DigitalOutput m_enabledOutput = new DigitalOutput(kEnabledPort);
@@ -39,4 +39,14 @@ public class Robot extends TimedRobot {
var matchTime = DriverStation.getMatchTime();
m_alertOutput.set(matchTime <= 30 && matchTime >= 25);
}
/** Close all resources. */
@Override
public void close() {
m_allianceOutput.close();
m_enabledOutput.close();
m_autonomousOutput.close();
m_alertOutput.close();
super.close();
}
}

View File

@@ -803,7 +803,8 @@
"name": "Digital Communication Sample",
"description": "An example program that communicates with external devices (such as an Arduino) using the roboRIO's DIO",
"tags": [
"Digital"
"Digital",
"Unit Testing"
],
"foldername": "digitalcommunication",
"gradlebase": "java",

View File

@@ -6,6 +6,7 @@ package edu.wpi.first.wpilibj.examples.i2ccommunication;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.I2C;
import edu.wpi.first.wpilibj.I2C.Port;
import edu.wpi.first.wpilibj.TimedRobot;
/**
@@ -13,9 +14,10 @@ import edu.wpi.first.wpilibj.TimedRobot;
* code using the roboRIO's I2C port.
*/
public class Robot extends TimedRobot {
private static int kDeviceAddress = 4;
static final Port kPort = Port.kOnboard;
private static final int kDeviceAddress = 4;
private static I2C m_arduino = new I2C(I2C.Port.kOnboard, kDeviceAddress);
private final I2C m_arduino = new I2C(kPort, kDeviceAddress);
private void writeString(String input) {
// Creates a char array from the input string
@@ -30,7 +32,7 @@ public class Robot extends TimedRobot {
}
// Writes bytes over I2C
m_arduino.transaction(data, data.length, null, 0);
m_arduino.transaction(data, data.length, new byte[] {}, 0);
}
@Override
@@ -54,4 +56,11 @@ public class Robot extends TimedRobot {
writeString(stateMessage.toString());
}
/** Close all resources. */
@Override
public void close() {
m_arduino.close();
super.close();
}
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.examples.digitalcommunication;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.AllianceStationID;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.simulation.DIOSim;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.parallel.ResourceLock;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
@ResourceLock("timing")
class DigitalCommunicationTest {
private Robot m_robot;
private Thread m_thread;
private final DIOSim m_allianceOutput = new DIOSim(Robot.kAlliancePort);
private final DIOSim m_enabledOutput = new DIOSim(Robot.kEnabledPort);
private final DIOSim m_autonomousOutput = new DIOSim(Robot.kAutonomousPort);
private final DIOSim m_alertOutput = new DIOSim(Robot.kAlertPort);
@BeforeEach
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
DriverStationSim.resetData();
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
}
@AfterEach
void stopThread() {
m_robot.endCompetition();
try {
m_thread.interrupt();
m_thread.join();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
m_robot.close();
m_allianceOutput.resetData();
m_enabledOutput.resetData();
m_autonomousOutput.resetData();
m_alertOutput.resetData();
}
@EnumSource(AllianceStationID.class)
@ParameterizedTest(name = "alliance[{index}]: {0}")
void allianceTest(AllianceStationID alliance) {
DriverStationSim.setAllianceStationId(alliance);
DriverStationSim.notifyNewData();
assertTrue(m_allianceOutput.getInitialized());
assertFalse(m_allianceOutput.getIsInput());
SimHooks.stepTiming(0.02);
assertEquals(alliance.name().startsWith("Red"), m_allianceOutput.getValue());
}
@ValueSource(booleans = {true, false})
@ParameterizedTest(name = "enabled[{index}]: {0}")
void enabledTest(boolean enabled) {
DriverStationSim.setEnabled(enabled);
DriverStationSim.notifyNewData();
assertTrue(m_enabledOutput.getInitialized());
assertFalse(m_enabledOutput.getIsInput());
SimHooks.stepTiming(0.02);
assertEquals(enabled, m_enabledOutput.getValue());
}
@ValueSource(booleans = {true, false})
@ParameterizedTest(name = "autonomous[{index}]: {0}")
void autonomousTest(boolean autonomous) {
DriverStationSim.setAutonomous(autonomous);
DriverStationSim.notifyNewData();
assertTrue(m_autonomousOutput.getInitialized());
assertFalse(m_autonomousOutput.getIsInput());
SimHooks.stepTiming(0.02);
assertEquals(autonomous, m_autonomousOutput.getValue());
}
@ValueSource(doubles = {45.0, 27.0, 23.0})
@ParameterizedTest(name = "alert[{index}]: {0}s")
void alertTest(double matchTime) {
DriverStationSim.setMatchTime(matchTime);
DriverStationSim.notifyNewData();
assertTrue(m_alertOutput.getInitialized());
assertFalse(m_alertOutput.getIsInput());
SimHooks.stepTiming(0.02);
assertEquals(matchTime <= 30 && matchTime >= 25, m_alertOutput.getValue());
}
}

View File

@@ -0,0 +1,126 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.examples.i2ccommunication;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.AllianceStationID;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.simulation.CallbackStore;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj.simulation.I2CSim;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.parallel.ResourceLock;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
@ResourceLock("timing")
class I2CCommunicationTest {
private Robot m_robot;
private Thread m_thread;
private final I2CSim m_i2c = new I2CSim(Robot.kPort.value);
private CompletableFuture<String> m_future;
private CallbackStore m_callback;
@BeforeEach
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
DriverStationSim.resetData();
m_future = new CompletableFuture<>();
m_callback =
m_i2c.registerWriteCallback(
(name, buffer, count) -> m_future.complete(new String(buffer, 0, count)));
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
}
@AfterEach
void stopThread() {
m_robot.endCompetition();
try {
m_thread.interrupt();
m_thread.join();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
m_robot.close();
m_callback.close();
m_i2c.resetData();
}
@EnumSource(AllianceStationID.class)
@ParameterizedTest(name = "alliance[{index}]: {0}")
void allianceTest(AllianceStationID alliance) {
DriverStationSim.setAllianceStationId(alliance);
DriverStationSim.notifyNewData();
assertTrue(m_i2c.getInitialized());
SimHooks.stepTiming(0.02);
String str = assertTimeoutPreemptively(Duration.ofMillis(20L), () -> m_future.get());
char expected = alliance.name().startsWith("Red") ? 'R' : 'B';
assertEquals(expected, str.charAt(0));
}
@ValueSource(booleans = {true, false})
@ParameterizedTest(name = "enabled[{index}]: {0}")
void enabledTest(boolean enabled) {
DriverStationSim.setEnabled(enabled);
DriverStationSim.notifyNewData();
assertTrue(m_i2c.getInitialized());
SimHooks.stepTiming(0.02);
String str = assertTimeoutPreemptively(Duration.ofMillis(20L), () -> m_future.get());
char expected = enabled ? 'E' : 'D';
assertEquals(expected, str.charAt(1));
}
@ValueSource(booleans = {true, false})
@ParameterizedTest(name = "autonomous[{index}]: {0}")
void autonomousTest(boolean autonomous) {
DriverStationSim.setAutonomous(autonomous);
DriverStationSim.notifyNewData();
assertTrue(m_i2c.getInitialized());
SimHooks.stepTiming(0.02);
String str = assertTimeoutPreemptively(Duration.ofMillis(20L), () -> m_future.get());
char expected = autonomous ? 'A' : 'T';
assertEquals(expected, str.charAt(2));
}
@ValueSource(doubles = {112.0, 45.0, 27.0, 23.0, 3.0})
@ParameterizedTest(name = "matchTime[{index}]: {0}s")
void matchTimeTest(double matchTime) {
DriverStationSim.setMatchTime(matchTime);
DriverStationSim.notifyNewData();
assertTrue(m_i2c.getInitialized());
SimHooks.stepTiming(0.02);
String str = assertTimeoutPreemptively(Duration.ofMillis(20L), () -> m_future.get());
String expected = String.format("%03d", (int) DriverStation.getMatchTime());
assertEquals(expected, str.substring(3));
}
}