From 3c22a34cf1ca3e5df12463d2f616abd3419ad1f3 Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Sun, 11 Aug 2024 13:40:07 -0400 Subject: [PATCH 01/11] Fix Java LED patterns not offsetting reads Was causing bugs when combined with patterns that need to read back from the buffer (eg masks and overlays) --- .../edu/wpi/first/wpilibj/LEDPattern.java | 30 ++- .../java/edu/wpi/first/wpilibj/LEDReader.java | 51 ++++++ .../edu/wpi/first/wpilibj/LEDPatternTest.java | 172 ++++++++++++++++++ 3 files changed, 249 insertions(+), 4 deletions(-) diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java index 5e2a65a0ea4..dfbae246608 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java @@ -145,7 +145,29 @@ default void applyTo(T readWriter) { default LEDPattern reversed() { return (reader, writer) -> { int bufLen = reader.getLength(); - applyTo(reader, (i, r, g, b) -> writer.setRGB((bufLen - 1) - i, r, g, b)); + applyTo( + new LEDReader() { + @Override + public int getLength() { + return reader.getLength(); + } + + @Override + public int getRed(int index) { + return reader.getRed(getLength() - 1 - index); + } + + @Override + public int getGreen(int index) { + return reader.getGreen(getLength() - 1 - index); + } + + @Override + public int getBlue(int index) { + return reader.getBlue(getLength() - 1 - index); + } + }, + (i, r, g, b) -> writer.setRGB((bufLen - 1) - i, r, g, b)); }; } @@ -160,7 +182,7 @@ default LEDPattern offsetBy(int offset) { return (reader, writer) -> { int bufLen = reader.getLength(); applyTo( - reader, + new LEDReader.OffsetLEDReader(reader, offset), (i, r, g, b) -> { int shiftedIndex = Math.floorMod(i + offset, bufLen); writer.setRGB(shiftedIndex, r, g, b); @@ -198,7 +220,7 @@ default LEDPattern scrollAtRelativeSpeed(Frequency velocity) { int offset = (int) (t * bufLen); applyTo( - reader, + new LEDReader.OffsetLEDReader(reader, offset), (i, r, g, b) -> { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = Math.floorMod(i + offset, bufLen); @@ -248,7 +270,7 @@ default LEDPattern scrollAtAbsoluteSpeed(LinearVelocity velocity, Distance ledSp var offset = now / microsPerLED; applyTo( - reader, + new LEDReader.OffsetLEDReader(reader, offset), (i, r, g, b) -> { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = Math.floorMod(i + offset, bufLen); diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java index 176884a9221..078c3de5350 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java @@ -4,6 +4,7 @@ package edu.wpi.first.wpilibj; +import edu.wpi.first.util.ErrorMessages; import edu.wpi.first.wpilibj.util.Color; import edu.wpi.first.wpilibj.util.Color8Bit; @@ -96,4 +97,54 @@ default void forEach(IndexedColorIterator iterator) { iterator.accept(i, getRed(i), getGreen(i), getBlue(i)); } } + + /** + * An LED reader implementation that operates on offset indexes. Offsets are circular and will + * wrap around the end of the base reader back to the start. + */ + class OffsetLEDReader implements LEDReader { + private final LEDReader m_reader; + private final long m_offset; + + /** + * Creates a new offset LED reader based on an existing reader and the integer offset. + * + * @param reader the backing reader to use + * @param offset the offset to use when reading data + */ + public OffsetLEDReader(LEDReader reader, long offset) { + m_reader = ErrorMessages.requireNonNullParam(reader, "reader", "OffsetLEDReader"); + m_offset = offset; + } + + @Override + public int getLength() { + return m_reader.getLength(); + } + + @Override + public int getRed(int index) { + return m_reader.getRed(remapIndex(index)); + } + + @Override + public int getGreen(int index) { + return m_reader.getGreen(remapIndex(index)); + } + + @Override + public int getBlue(int index) { + return m_reader.getBlue(remapIndex(index)); + } + + /** + * Remaps an input index to the corresponding offset index. + * + * @param index the input index to remap + * @return the remapped index + */ + public int remapIndex(int index) { + return Math.floorMod(index + m_offset, getLength()); + } + } } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java index adb96cde572..452f7456ef5 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java @@ -5,6 +5,7 @@ package edu.wpi.first.wpilibj; import static edu.wpi.first.units.Units.Centimeters; +import static edu.wpi.first.units.Units.Meters; import static edu.wpi.first.units.Units.MetersPerSecond; import static edu.wpi.first.units.Units.Microsecond; import static edu.wpi.first.units.Units.Microseconds; @@ -15,6 +16,7 @@ import static edu.wpi.first.wpilibj.LEDPattern.GradientType.kDiscontinuous; import static edu.wpi.first.wpilibj.util.Color.kBlack; import static edu.wpi.first.wpilibj.util.Color.kBlue; +import static edu.wpi.first.wpilibj.util.Color.kGreen; import static edu.wpi.first.wpilibj.util.Color.kLime; import static edu.wpi.first.wpilibj.util.Color.kMagenta; import static edu.wpi.first.wpilibj.util.Color.kMidnightBlue; @@ -815,6 +817,176 @@ void clippingBrightness() { assertColorEquals(kWhite, buffer.getLED(0)); } + @Test + void reverseMask() { + var pattern = + LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.75, kGreen)) + .mask(LEDPattern.steps(Map.of(0, kWhite, 0.5, kBlack))) + .reversed(); + var buffer = new AddressableLEDBuffer(8); + + pattern.applyTo(buffer); + + assertColorEquals(kRed, buffer.getLED(7)); + assertColorEquals(kRed, buffer.getLED(6)); + assertColorEquals(kBlue, buffer.getLED(5)); + assertColorEquals(kBlue, buffer.getLED(4)); + assertColorEquals(kBlack, buffer.getLED(3)); + assertColorEquals(kBlack, buffer.getLED(2)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kBlack, buffer.getLED(0)); + } + + @Test + void offsetMask() { + var pattern = + LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.77, kGreen)) + .mask(LEDPattern.steps(Map.of(0, kWhite, 0.5, kBlack))) + .offsetBy(4); + var buffer = new AddressableLEDBuffer(8); + + pattern.applyTo(buffer); + + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kBlack, buffer.getLED(2)); + assertColorEquals(kBlack, buffer.getLED(3)); + assertColorEquals(kRed, buffer.getLED(4)); + assertColorEquals(kRed, buffer.getLED(5)); + assertColorEquals(kBlue, buffer.getLED(6)); + assertColorEquals(kBlue, buffer.getLED(7)); + } + + @Test + void relativeScrollingMask() { + // [red, red, blue, blue, yellow, yellow, green, green] + // under a mask of first 50% on, last 50% off + // [red, red, blue, blue, black, black, black, black] + // all scrolling at 1 LED per microsecond + var pattern = + LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.75, kGreen)) + .mask(LEDPattern.steps(Map.of(0, kWhite, 0.5, kBlack))) + .scrollAtRelativeSpeed(Percent.per(Microsecond).of(12.5)); + var buffer = new AddressableLEDBuffer(8); + + { + WPIUtilJNI.setMockTime(0); // start + pattern.applyTo(buffer); + assertColorEquals(kRed, buffer.getLED(0)); + assertColorEquals(kRed, buffer.getLED(1)); + assertColorEquals(kBlue, buffer.getLED(2)); + assertColorEquals(kBlue, buffer.getLED(3)); + assertColorEquals(kBlack, buffer.getLED(4)); + assertColorEquals(kBlack, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(1); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kRed, buffer.getLED(1)); + assertColorEquals(kRed, buffer.getLED(2)); + assertColorEquals(kBlue, buffer.getLED(3)); + assertColorEquals(kBlue, buffer.getLED(4)); + assertColorEquals(kBlack, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(2); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kRed, buffer.getLED(2)); + assertColorEquals(kRed, buffer.getLED(3)); + assertColorEquals(kBlue, buffer.getLED(4)); + assertColorEquals(kBlue, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(3); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kBlack, buffer.getLED(2)); + assertColorEquals(kRed, buffer.getLED(3)); + assertColorEquals(kRed, buffer.getLED(4)); + assertColorEquals(kBlue, buffer.getLED(5)); + assertColorEquals(kBlue, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + } + + @Test + void absoluteScrollingMask() { + // [red, red, blue, blue, yellow, yellow, green, green] + // under a mask of first 50% on, last 50% off + // [red, red, blue, blue, black, black, black, black] + // all scrolling at 1 LED per microsecond + var pattern = + LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.75, kGreen)) + .mask(LEDPattern.steps(Map.of(0, kWhite, 0.5, kBlack))) + .scrollAtAbsoluteSpeed(Meters.per(Microsecond).of(1), Meters.one()); + var buffer = new AddressableLEDBuffer(8); + + { + WPIUtilJNI.setMockTime(0); // start + pattern.applyTo(buffer); + assertColorEquals(kRed, buffer.getLED(0)); + assertColorEquals(kRed, buffer.getLED(1)); + assertColorEquals(kBlue, buffer.getLED(2)); + assertColorEquals(kBlue, buffer.getLED(3)); + assertColorEquals(kBlack, buffer.getLED(4)); + assertColorEquals(kBlack, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(1); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kRed, buffer.getLED(1)); + assertColorEquals(kRed, buffer.getLED(2)); + assertColorEquals(kBlue, buffer.getLED(3)); + assertColorEquals(kBlue, buffer.getLED(4)); + assertColorEquals(kBlack, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(2); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kRed, buffer.getLED(2)); + assertColorEquals(kRed, buffer.getLED(3)); + assertColorEquals(kBlue, buffer.getLED(4)); + assertColorEquals(kBlue, buffer.getLED(5)); + assertColorEquals(kBlack, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + + { + WPIUtilJNI.setMockTime(3); + pattern.applyTo(buffer); + assertColorEquals(kBlack, buffer.getLED(0)); + assertColorEquals(kBlack, buffer.getLED(1)); + assertColorEquals(kBlack, buffer.getLED(2)); + assertColorEquals(kRed, buffer.getLED(3)); + assertColorEquals(kRed, buffer.getLED(4)); + assertColorEquals(kBlue, buffer.getLED(5)); + assertColorEquals(kBlue, buffer.getLED(6)); + assertColorEquals(kBlack, buffer.getLED(7)); + } + } + void assertColorEquals(Color expected, Color actual) { assertEquals(new Color8Bit(expected), new Color8Bit(actual)); } From a08aa275aa74bc564e456de37e77437b41a0922f Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Tue, 22 Oct 2024 23:26:32 -0400 Subject: [PATCH 02/11] Fix 0.77 step Didn't actually cause issues due to the small buffer size, but it's good to be consistent --- wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java index 452f7456ef5..836e64ca501 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java @@ -840,7 +840,7 @@ void reverseMask() { @Test void offsetMask() { var pattern = - LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.77, kGreen)) + LEDPattern.steps(Map.of(0, kRed, 0.25, kBlue, 0.5, kYellow, 0.75, kGreen)) .mask(LEDPattern.steps(Map.of(0, kWhite, 0.5, kBlack))) .offsetBy(4); var buffer = new AddressableLEDBuffer(8); From 54a86d6ebe44bb1c90931bc5cfc1eeea91dc911a Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Tue, 22 Oct 2024 23:27:27 -0400 Subject: [PATCH 03/11] Start on C++ fixes --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 10 +- .../src/test/native/cpp/LEDPatternTest.cpp | 226 ++++++++++++++++++ 2 files changed, 232 insertions(+), 4 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index d06d1be5268..5d47be4b8ee 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include "frc/MathUtil.h" @@ -31,7 +33,7 @@ void LEDPattern::ApplyTo(std::span data) const { LEDPattern LEDPattern::Reversed() { return LEDPattern{[self = *this](auto data, auto writer) { - self.ApplyTo(data, [&](int i, Color color) { + self.ApplyTo(std::ranges::reverse_view{data}, [&](int i, Color color) { writer((data.size() - 1) - i, color); }); }}; @@ -39,7 +41,7 @@ LEDPattern LEDPattern::Reversed() { LEDPattern LEDPattern::OffsetBy(int offset) { return LEDPattern{[=, self = *this](auto data, auto writer) { - self.ApplyTo(data, [&data, &writer, offset](int i, Color color) { + self.ApplyTo(wpi::rotated_span{data, offset}, [&data, &writer, offset](int i, Color color) { int shiftedIndex = frc::FloorMod(i + offset, static_cast(data.size())); writer(shiftedIndex, color); @@ -62,7 +64,7 @@ LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { (now % static_cast(std::floor(periodMicros))) / periodMicros; int offset = static_cast(std::floor(t * bufLen)); - self.ApplyTo(data, [=](int i, Color color) { + self.ApplyTo(wpi::rotated_span{data, offset}, [=](int i, Color color) { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); writer(shiftedIndex, color); @@ -87,7 +89,7 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( // offset values for negative velocities auto offset = static_cast(now) / microsPerLed; - self.ApplyTo(data, [=, &writer](int i, Color color) { + self.ApplyTo(wpi::rotated_span{data, offset}, [=, &writer](int i, Color color) { // FloorMod so if the offset is negative, we still get positive outputs int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp index cd9e7d76b7e..c695e164bef 100644 --- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp +++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp @@ -813,6 +813,232 @@ TEST(LEDPatternTest, ClippingBrightness) { AssertIndexColor(buffer, 0, Color::kWhite); } +TEST(LEDPatternTest, ReverseMask) { + std::array buffer; + + std::array, 4> colorSteps{ + std::pair{0.0, Color::kRed}, + std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, + std::pair{0.75, Color::kGreen} + }; + std::array, 2> maskSteps{ + std::pair{0, Color::kWhite}, + std::pair{0.5, Color::kBlack} + }; + + auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed(); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 7, Color::kRed); + AssertIndexColor(buffer, 6, Color::kRed); + AssertIndexColor(buffer, 5, Color::kBlue); + AssertIndexColor(buffer, 4, Color::kBlue); + AssertIndexColor(buffer, 3, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 0, Color::kBlack); +} + +TEST(LEDPatternTest, OffsetMask) { + std::array buffer; + + std::array, 4> colorSteps{ + std::pair{0.0, Color::kRed}, + std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, + std::pair{0.75, Color::kGreen} + }; + std::array, 2> maskSteps{ + std::pair{0, Color::kWhite}, + std::pair{0.5, Color::kBlack} + }; + + auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().OffsetBy(4); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kBlack); + AssertIndexColor(buffer, 3, Color::kBlack); + AssertIndexColor(buffer, 4, Color::kRed); + AssertIndexColor(buffer, 5, Color::kRed); + AssertIndexColor(buffer, 6, Color::kBlue); + AssertIndexColor(buffer, 7, Color::kBlue); +} + +TEST(LEDPatternTest, RelativeScrollingMask) { + std::array buffer; + + std::array, 4> colorSteps{ + std::pair{0.0, Color::kRed}, + std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, + std::pair{0.75, Color::kGreen} + }; + std::array, 2> maskSteps{ + std::pair{0, Color::kWhite}, + std::pair{0.5, Color::kBlack} + }; + + auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().ScrollAtRelativeSpeed(units::hertz_t{ 12.5 * 1e3 }); + + pattern.ApplyTo(buffer); + + static uint64_t now = 0ull; + WPI_SetNowImpl([] { return now; }); + + { + now = 0ull; // start + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kRed); + AssertIndexColor(buffer, 1, Color::kRed); + AssertIndexColor(buffer, 2, Color::kBlue); + AssertIndexColor(buffer, 3, Color::kBlue); + AssertIndexColor(buffer, 4, Color::kBlack); + AssertIndexColor(buffer, 5, Color::kBlack); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 1ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kRed); + AssertIndexColor(buffer, 2, Color::kRed); + AssertIndexColor(buffer, 3, Color::kBlue); + AssertIndexColor(buffer, 4, Color::kBlue); + AssertIndexColor(buffer, 5, Color::kBlack); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 2ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kRed); + AssertIndexColor(buffer, 3, Color::kRed); + AssertIndexColor(buffer, 4, Color::kBlue); + AssertIndexColor(buffer, 5, Color::kBlue); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 3ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kBlack); + AssertIndexColor(buffer, 3, Color::kRed); + AssertIndexColor(buffer, 4, Color::kRed); + AssertIndexColor(buffer, 5, Color::kBlue); + AssertIndexColor(buffer, 6, Color::kBlue); + AssertIndexColor(buffer, 7, Color::kBlack); + } + + WPI_SetNowImpl(nullptr); // cleanup +} + +TEST(LEDPatternTest, AbsoluteScrollingMask) { + std::array buffer; + + std::array, 4> colorSteps{ + std::pair{0.0, Color::kRed}, + std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, + std::pair{0.75, Color::kGreen} + }; + std::array, 2> maskSteps{ + std::pair{0, Color::kWhite}, + std::pair{0.5, Color::kBlack} + }; + + auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().ScrollAtAbsoluteSpeed(1_mps, 1_m); + + pattern.ApplyTo(buffer); + + static uint64_t now = 0ull; + WPI_SetNowImpl([] { return now; }); + + { + now = 0ull; // start + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kRed); + AssertIndexColor(buffer, 1, Color::kRed); + AssertIndexColor(buffer, 2, Color::kBlue); + AssertIndexColor(buffer, 3, Color::kBlue); + AssertIndexColor(buffer, 4, Color::kBlack); + AssertIndexColor(buffer, 5, Color::kBlack); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 1000000ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kRed); + AssertIndexColor(buffer, 2, Color::kRed); + AssertIndexColor(buffer, 3, Color::kBlue); + AssertIndexColor(buffer, 4, Color::kBlue); + AssertIndexColor(buffer, 5, Color::kBlack); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 2000000ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kRed); + AssertIndexColor(buffer, 3, Color::kRed); + AssertIndexColor(buffer, 4, Color::kBlue); + AssertIndexColor(buffer, 5, Color::kBlue); + AssertIndexColor(buffer, 6, Color::kBlack); + AssertIndexColor(buffer, 7, Color::kBlack); + } + { + now = 3000000ull; + SCOPED_TRACE(fmt::format("Time {}", now)); + + pattern.ApplyTo(buffer); + + AssertIndexColor(buffer, 0, Color::kBlack); + AssertIndexColor(buffer, 1, Color::kBlack); + AssertIndexColor(buffer, 2, Color::kBlack); + AssertIndexColor(buffer, 3, Color::kRed); + AssertIndexColor(buffer, 4, Color::kRed); + AssertIndexColor(buffer, 5, Color::kBlue); + AssertIndexColor(buffer, 6, Color::kBlue); + AssertIndexColor(buffer, 7, Color::kBlack); + } + + WPI_SetNowImpl(nullptr); // cleanup +} + void AssertIndexColor(std::span data, int index, Color color) { frc::Color8Bit color8bit{color}; From cc363e749c38e883e745ac13bc878ec72607fa2a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 03:32:37 +0000 Subject: [PATCH 04/11] Formatting fixes --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 16 ++--- .../src/test/native/cpp/LEDPatternTest.cpp | 63 ++++++++----------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index 5d47be4b8ee..86d5cbb50ac 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -13,8 +13,8 @@ #include #include -#include #include +#include #include "frc/MathUtil.h" @@ -41,11 +41,12 @@ LEDPattern LEDPattern::Reversed() { LEDPattern LEDPattern::OffsetBy(int offset) { return LEDPattern{[=, self = *this](auto data, auto writer) { - self.ApplyTo(wpi::rotated_span{data, offset}, [&data, &writer, offset](int i, Color color) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(data.size())); - writer(shiftedIndex, color); - }); + self.ApplyTo(wpi::rotated_span{data, offset}, + [&data, &writer, offset](int i, Color color) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(data.size())); + writer(shiftedIndex, color); + }); }}; } @@ -89,7 +90,8 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( // offset values for negative velocities auto offset = static_cast(now) / microsPerLed; - self.ApplyTo(wpi::rotated_span{data, offset}, [=, &writer](int i, Color color) { + self.ApplyTo(wpi::rotated_span{data, offset}, [=, &writer](int i, + Color color) { // FloorMod so if the offset is negative, we still get positive outputs int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp index c695e164bef..c2d09847cbb 100644 --- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp +++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp @@ -817,17 +817,14 @@ TEST(LEDPatternTest, ReverseMask) { std::array buffer; std::array, 4> colorSteps{ - std::pair{0.0, Color::kRed}, - std::pair{0.25, Color::kBlue}, - std::pair{0.5, Color::kYellow}, - std::pair{0.75, Color::kGreen} - }; + std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}}; std::array, 2> maskSteps{ - std::pair{0, Color::kWhite}, - std::pair{0.5, Color::kBlack} - }; + std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}}; - auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed(); + auto pattern = LEDPattern::Steps(colorSteps) + .Mask(LEDPattern::Steps(maskSteps)) + .Reversed(); pattern.ApplyTo(buffer); @@ -845,17 +842,15 @@ TEST(LEDPatternTest, OffsetMask) { std::array buffer; std::array, 4> colorSteps{ - std::pair{0.0, Color::kRed}, - std::pair{0.25, Color::kBlue}, - std::pair{0.5, Color::kYellow}, - std::pair{0.75, Color::kGreen} - }; + std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}}; std::array, 2> maskSteps{ - std::pair{0, Color::kWhite}, - std::pair{0.5, Color::kBlack} - }; + std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}}; - auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().OffsetBy(4); + auto pattern = LEDPattern::Steps(colorSteps) + .Mask(LEDPattern::Steps(maskSteps)) + .Reversed() + .OffsetBy(4); pattern.ApplyTo(buffer); @@ -873,17 +868,15 @@ TEST(LEDPatternTest, RelativeScrollingMask) { std::array buffer; std::array, 4> colorSteps{ - std::pair{0.0, Color::kRed}, - std::pair{0.25, Color::kBlue}, - std::pair{0.5, Color::kYellow}, - std::pair{0.75, Color::kGreen} - }; + std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}}; std::array, 2> maskSteps{ - std::pair{0, Color::kWhite}, - std::pair{0.5, Color::kBlack} - }; + std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}}; - auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().ScrollAtRelativeSpeed(units::hertz_t{ 12.5 * 1e3 }); + auto pattern = LEDPattern::Steps(colorSteps) + .Mask(LEDPattern::Steps(maskSteps)) + .Reversed() + .ScrollAtRelativeSpeed(units::hertz_t{12.5 * 1e3}); pattern.ApplyTo(buffer); @@ -958,17 +951,15 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) { std::array buffer; std::array, 4> colorSteps{ - std::pair{0.0, Color::kRed}, - std::pair{0.25, Color::kBlue}, - std::pair{0.5, Color::kYellow}, - std::pair{0.75, Color::kGreen} - }; + std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue}, + std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}}; std::array, 2> maskSteps{ - std::pair{0, Color::kWhite}, - std::pair{0.5, Color::kBlack} - }; + std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}}; - auto pattern = LEDPattern::Steps(colorSteps).Mask(LEDPattern::Steps(maskSteps)).Reversed().ScrollAtAbsoluteSpeed(1_mps, 1_m); + auto pattern = LEDPattern::Steps(colorSteps) + .Mask(LEDPattern::Steps(maskSteps)) + .Reversed() + .ScrollAtAbsoluteSpeed(1_mps, 1_m); pattern.ApplyTo(buffer); From 535459ec000572f6d43b46109c411a1a4ec19b34 Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Wed, 23 Oct 2024 22:40:11 -0400 Subject: [PATCH 05/11] Use LEDReader structure in C++ For wrapping different types of containers (std::span, wpi::rotated_span, etc) with a single type and without templating the LEDPattern class Probably still scuffed --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 62 ++++++++++++++----- .../src/main/native/include/frc/LEDPattern.h | 43 ++++++++----- .../src/test/native/cpp/LEDPatternTest.cpp | 5 +- 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index 86d5cbb50ac..eb5a0202337 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -13,40 +13,57 @@ #include #include -#include #include #include "frc/MathUtil.h" using namespace frc; -LEDPattern::LEDPattern(LEDPatternFn impl) : m_impl(std::move(impl)) {} +LEDPattern::LEDPattern(std::function)> impl) : m_impl(std::move(impl)) {} + +void LEDPattern::ApplyTo(LEDPattern::LEDReader reader, std::function writer) const { + m_impl(reader, writer); +} void LEDPattern::ApplyTo(std::span data, - LEDWriterFn writer) const { - m_impl(data, writer); + std::function writer) const { + ApplyTo(LEDPattern::LEDReader{[=] (size_t i) { return data[i]; }, data.size()}, writer); } void LEDPattern::ApplyTo(std::span data) const { ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); } +//void LEDPattern:ApplyTo(std::range::views::reversed data) const { +// ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); +//} + LEDPattern LEDPattern::Reversed() { return LEDPattern{[self = *this](auto data, auto writer) { - self.ApplyTo(std::ranges::reverse_view{data}, [&](int i, Color color) { - writer((data.size() - 1) - i, color); - }); + self.ApplyTo( + LEDPattern::LEDReader{ [=](auto i) { + return data[data.size() - 1 - i]; + }, data.size() }, + [&](int i, Color color) { + writer((data.size() - 1) - i, color); + } + ); }}; } LEDPattern LEDPattern::OffsetBy(int offset) { - return LEDPattern{[=, self = *this](auto data, auto writer) { - self.ApplyTo(wpi::rotated_span{data, offset}, - [&data, &writer, offset](int i, Color color) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(data.size())); - writer(shiftedIndex, color); - }); + return LEDPattern{[=, self = *this](LEDPattern::LEDReader data, auto writer) { + self.ApplyTo( + LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(d.size())); + return d[shiftedIndex]; + }, data.size()}, + [&data, &writer, offset](int i, Color color) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(data.size())); + writer(shiftedIndex, color); + }); }}; } @@ -65,7 +82,13 @@ LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { (now % static_cast(std::floor(periodMicros))) / periodMicros; int offset = static_cast(std::floor(t * bufLen)); - self.ApplyTo(wpi::rotated_span{data, offset}, [=](int i, Color color) { + self.ApplyTo( + LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(d.size())); + return d[shiftedIndex]; + }, data.size()}, + [=](int i, Color color) { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); writer(shiftedIndex, color); @@ -90,8 +113,13 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( // offset values for negative velocities auto offset = static_cast(now) / microsPerLed; - self.ApplyTo(wpi::rotated_span{data, offset}, [=, &writer](int i, - Color color) { + self.ApplyTo( + LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(d.size())); + return d[shiftedIndex]; + }, data.size()}, + [=, &writer](int i, Color color) { // FloorMod so if the offset is negative, we still get positive outputs int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); diff --git a/wpilibc/src/main/native/include/frc/LEDPattern.h b/wpilibc/src/main/native/include/frc/LEDPattern.h index f2dcf28485c..c135596b5df 100644 --- a/wpilibc/src/main/native/include/frc/LEDPattern.h +++ b/wpilibc/src/main/native/include/frc/LEDPattern.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -18,21 +19,33 @@ namespace frc { -/** - * Sets the LED at the given index to the given color. - */ -using LEDWriterFn = std::function; - -/** - * Accepts a data buffer (1st argument) and a callback (2nd argument) for - * writing data. - */ -using LEDPatternFn = - std::function, LEDWriterFn)>; - class LEDPattern { public: - explicit LEDPattern(LEDPatternFn impl); + /** + * A wrapper around a length and an arbitrary reader function that accepts an + * LED index and returns data for the LED at that index. This configuration + * allows us to abstract over different container types without templating. + */ + class LEDReader { + public: + LEDReader(std::function impl, size_t size) : m_impl{std::move(impl)}, m_size{size} {} + + frc::AddressableLED::LEDData operator[](size_t index) const { + return m_impl(index); + } + + size_t size() const { + return m_size; + } + + private: + std::function m_impl; + size_t m_size; + }; + + explicit LEDPattern(std::function)> impl); + + void ApplyTo(LEDReader reader, std::function writer) const; /** * Writes the pattern to an LED buffer. Dynamic animations should be called @@ -48,7 +61,7 @@ class LEDPattern { * @param writer data writer for setting new LED colors on the LED strip */ void ApplyTo(std::span data, - LEDWriterFn writer) const; + std::function writer) const; /** * Writes the pattern to an LED buffer. Dynamic animations should be called @@ -373,6 +386,6 @@ class LEDPattern { static LEDPattern Rainbow(int saturation, int value); private: - LEDPatternFn m_impl; + std::function)> m_impl; }; } // namespace frc diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp index c2d09847cbb..4a01d253959 100644 --- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp +++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp @@ -849,7 +849,6 @@ TEST(LEDPatternTest, OffsetMask) { auto pattern = LEDPattern::Steps(colorSteps) .Mask(LEDPattern::Steps(maskSteps)) - .Reversed() .OffsetBy(4); pattern.ApplyTo(buffer); @@ -875,8 +874,7 @@ TEST(LEDPatternTest, RelativeScrollingMask) { auto pattern = LEDPattern::Steps(colorSteps) .Mask(LEDPattern::Steps(maskSteps)) - .Reversed() - .ScrollAtRelativeSpeed(units::hertz_t{12.5 * 1e3}); + .ScrollAtRelativeSpeed(units::hertz_t{1e6/8.0}); pattern.ApplyTo(buffer); @@ -958,7 +956,6 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) { auto pattern = LEDPattern::Steps(colorSteps) .Mask(LEDPattern::Steps(maskSteps)) - .Reversed() .ScrollAtAbsoluteSpeed(1_mps, 1_m); pattern.ApplyTo(buffer); From 54bbb661802e4241df1cf2eed637655daa08e00c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 02:44:53 +0000 Subject: [PATCH 06/11] Formatting fixes --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 103 ++++++++++-------- .../src/main/native/include/frc/LEDPattern.h | 21 ++-- .../src/test/native/cpp/LEDPatternTest.cpp | 2 +- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index eb5a0202337..f787c3fffda 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -19,51 +19,54 @@ using namespace frc; -LEDPattern::LEDPattern(std::function)> impl) : m_impl(std::move(impl)) {} +LEDPattern::LEDPattern(std::function)> + impl) + : m_impl(std::move(impl)) {} -void LEDPattern::ApplyTo(LEDPattern::LEDReader reader, std::function writer) const { +void LEDPattern::ApplyTo(LEDPattern::LEDReader reader, + std::function writer) const { m_impl(reader, writer); } void LEDPattern::ApplyTo(std::span data, std::function writer) const { - ApplyTo(LEDPattern::LEDReader{[=] (size_t i) { return data[i]; }, data.size()}, writer); + ApplyTo(LEDPattern::LEDReader{[=](size_t i) { return data[i]; }, data.size()}, + writer); } void LEDPattern::ApplyTo(std::span data) const { ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); } -//void LEDPattern:ApplyTo(std::range::views::reversed data) const { -// ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); -//} +// void LEDPattern:ApplyTo(std::range::views::reversed +// data) const { +// ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); +// } LEDPattern LEDPattern::Reversed() { return LEDPattern{[self = *this](auto data, auto writer) { self.ApplyTo( - LEDPattern::LEDReader{ [=](auto i) { - return data[data.size() - 1 - i]; - }, data.size() }, - [&](int i, Color color) { - writer((data.size() - 1) - i, color); - } - ); + LEDPattern::LEDReader{[=](auto i) { return data[data.size() - 1 - i]; }, + data.size()}, + [&](int i, Color color) { writer((data.size() - 1) - i, color); }); }}; } LEDPattern LEDPattern::OffsetBy(int offset) { return LEDPattern{[=, self = *this](LEDPattern::LEDReader data, auto writer) { - self.ApplyTo( - LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(d.size())); - return d[shiftedIndex]; - }, data.size()}, - [&data, &writer, offset](int i, Color color) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(data.size())); - writer(shiftedIndex, color); - }); + self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { + int shiftedIndex = frc::FloorMod( + i + offset, + static_cast(d.size())); + return d[shiftedIndex]; + }, + data.size()}, + [&data, &writer, offset](int i, Color color) { + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(data.size())); + writer(shiftedIndex, color); + }); }}; } @@ -82,17 +85,20 @@ LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { (now % static_cast(std::floor(periodMicros))) / periodMicros; int offset = static_cast(std::floor(t * bufLen)); - self.ApplyTo( - LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(d.size())); - return d[shiftedIndex]; - }, data.size()}, - [=](int i, Color color) { - // floorMod so if the offset is negative, we still get positive outputs - int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); - writer(shiftedIndex, color); - }); + self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { + int shiftedIndex = frc::FloorMod( + i + offset, + static_cast(d.size())); + return d[shiftedIndex]; + }, + data.size()}, + [=](int i, Color color) { + // floorMod so if the offset is negative, we still get + // positive outputs + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(bufLen)); + writer(shiftedIndex, color); + }); }}; } @@ -113,18 +119,21 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( // offset values for negative velocities auto offset = static_cast(now) / microsPerLed; - self.ApplyTo( - LEDPattern::LEDReader{ [=, d = std::move(data)](auto i) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(d.size())); - return d[shiftedIndex]; - }, data.size()}, - [=, &writer](int i, Color color) { - // FloorMod so if the offset is negative, we still get positive outputs - int shiftedIndex = frc::FloorMod(i + offset, static_cast(bufLen)); - - writer(shiftedIndex, color); - }); + self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { + int shiftedIndex = frc::FloorMod( + i + offset, + static_cast(d.size())); + return d[shiftedIndex]; + }, + data.size()}, + [=, &writer](int i, Color color) { + // FloorMod so if the offset is negative, we still get + // positive outputs + int shiftedIndex = + frc::FloorMod(i + offset, static_cast(bufLen)); + + writer(shiftedIndex, color); + }); }}; } diff --git a/wpilibc/src/main/native/include/frc/LEDPattern.h b/wpilibc/src/main/native/include/frc/LEDPattern.h index c135596b5df..478a8f57e32 100644 --- a/wpilibc/src/main/native/include/frc/LEDPattern.h +++ b/wpilibc/src/main/native/include/frc/LEDPattern.h @@ -5,8 +5,8 @@ #pragma once #include -#include #include +#include #include #include @@ -28,24 +28,27 @@ class LEDPattern { */ class LEDReader { public: - LEDReader(std::function impl, size_t size) : m_impl{std::move(impl)}, m_size{size} {} + LEDReader(std::function impl, + size_t size) + : m_impl{std::move(impl)}, m_size{size} {} frc::AddressableLED::LEDData operator[](size_t index) const { return m_impl(index); } - size_t size() const { - return m_size; - } + size_t size() const { return m_size; } private: std::function m_impl; size_t m_size; }; - explicit LEDPattern(std::function)> impl); + explicit LEDPattern(std::function)> + impl); - void ApplyTo(LEDReader reader, std::function writer) const; + void ApplyTo(LEDReader reader, + std::function writer) const; /** * Writes the pattern to an LED buffer. Dynamic animations should be called @@ -386,6 +389,8 @@ class LEDPattern { static LEDPattern Rainbow(int saturation, int value); private: - std::function)> m_impl; + std::function)> + m_impl; }; } // namespace frc diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp index 4a01d253959..467b4bbd813 100644 --- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp +++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp @@ -874,7 +874,7 @@ TEST(LEDPatternTest, RelativeScrollingMask) { auto pattern = LEDPattern::Steps(colorSteps) .Mask(LEDPattern::Steps(maskSteps)) - .ScrollAtRelativeSpeed(units::hertz_t{1e6/8.0}); + .ScrollAtRelativeSpeed(units::hertz_t{1e6 / 8.0}); pattern.ApplyTo(buffer); From b73607ac6905136dd5d177299839de4c03eb6c96 Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Thu, 7 Nov 2024 21:33:20 -0500 Subject: [PATCH 07/11] Clean up C++ files --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 6 ------ wpilibc/src/main/native/include/frc/LEDPattern.h | 1 - 2 files changed, 7 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index f787c3fffda..fdfd4c21bba 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -39,11 +38,6 @@ void LEDPattern::ApplyTo(std::span data) const { ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); } -// void LEDPattern:ApplyTo(std::range::views::reversed -// data) const { -// ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); -// } - LEDPattern LEDPattern::Reversed() { return LEDPattern{[self = *this](auto data, auto writer) { self.ApplyTo( diff --git a/wpilibc/src/main/native/include/frc/LEDPattern.h b/wpilibc/src/main/native/include/frc/LEDPattern.h index 478a8f57e32..2db8dad6296 100644 --- a/wpilibc/src/main/native/include/frc/LEDPattern.h +++ b/wpilibc/src/main/native/include/frc/LEDPattern.h @@ -5,7 +5,6 @@ #pragma once #include -#include #include #include From 768a054c6b1f54702081f86f2b43cd08f966fde9 Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Thu, 7 Nov 2024 21:41:45 -0500 Subject: [PATCH 08/11] Change OffsetLEDReader to a more generic RemappedReader implementation Now operates on arbitrary remapping functions, not just a fixed offset --- .../edu/wpi/first/wpilibj/LEDPattern.java | 8 ++--- .../java/edu/wpi/first/wpilibj/LEDReader.java | 34 ++++++++++++++----- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java index dfbae246608..4e891761527 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java @@ -182,7 +182,7 @@ default LEDPattern offsetBy(int offset) { return (reader, writer) -> { int bufLen = reader.getLength(); applyTo( - new LEDReader.OffsetLEDReader(reader, offset), + LEDReader.RemappedReader.offset(reader, offset), (i, r, g, b) -> { int shiftedIndex = Math.floorMod(i + offset, bufLen); writer.setRGB(shiftedIndex, r, g, b); @@ -220,7 +220,7 @@ default LEDPattern scrollAtRelativeSpeed(Frequency velocity) { int offset = (int) (t * bufLen); applyTo( - new LEDReader.OffsetLEDReader(reader, offset), + LEDReader.RemappedReader.offset(reader, offset), (i, r, g, b) -> { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = Math.floorMod(i + offset, bufLen); @@ -267,10 +267,10 @@ default LEDPattern scrollAtAbsoluteSpeed(LinearVelocity velocity, Distance ledSp long now = WPIUtilJNI.now(); // every step in time that's a multiple of microsPerLED will increment the offset by 1 - var offset = now / microsPerLED; + var offset = (int) (now / microsPerLED); applyTo( - new LEDReader.OffsetLEDReader(reader, offset), + LEDReader.RemappedReader.offset(reader, offset), (i, r, g, b) -> { // floorMod so if the offset is negative, we still get positive outputs int shiftedIndex = Math.floorMod(i + offset, bufLen); diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java index 078c3de5350..b02af03b313 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java @@ -7,6 +7,7 @@ import edu.wpi.first.util.ErrorMessages; import edu.wpi.first.wpilibj.util.Color; import edu.wpi.first.wpilibj.util.Color8Bit; +import java.util.function.IntUnaryOperator; /** Generic interface for reading data from an LED buffer. */ public interface LEDReader { @@ -99,22 +100,37 @@ default void forEach(IndexedColorIterator iterator) { } /** - * An LED reader implementation that operates on offset indexes. Offsets are circular and will - * wrap around the end of the base reader back to the start. + * An LED reader implementation that operates on remapped indices. Remapping can be done using + * arbitrary mapping functions; a static factory function is also provided for the common use case + * of offset readers for things like scrolling animations. */ - class OffsetLEDReader implements LEDReader { + class RemappedReader implements LEDReader { private final LEDReader m_reader; - private final long m_offset; + private final IntUnaryOperator m_mapping; /** - * Creates a new offset LED reader based on an existing reader and the integer offset. + * Creates a new remapping reader for a backing reader and an arbitrary index remapping + * function. + * + * @param reader the backing reader to use + * @param mapping the mapping function to use + */ + public RemappedReader(LEDReader reader, IntUnaryOperator mapping) { + m_reader = ErrorMessages.requireNonNullParam(reader, "reader", "RemappedReader"); + m_mapping = ErrorMessages.requireNonNullParam(mapping, "mapping", "RemappedReader"); + } + + /** + * Creates a new offset LED reader based on an existing reader and integer offset. The offset + * reader will be circular and wrap around. * * @param reader the backing reader to use * @param offset the offset to use when reading data + * @return the offset reader */ - public OffsetLEDReader(LEDReader reader, long offset) { - m_reader = ErrorMessages.requireNonNullParam(reader, "reader", "OffsetLEDReader"); - m_offset = offset; + public static RemappedReader offset(LEDReader reader, int offset) { + return new RemappedReader( + reader, original -> Math.floorMod(original + offset, reader.getLength())); } @Override @@ -144,7 +160,7 @@ public int getBlue(int index) { * @return the remapped index */ public int remapIndex(int index) { - return Math.floorMod(index + m_offset, getLength()); + return m_mapping.applyAsInt(index); } } } From 55957940da7160b441608b72ea37f8c08a77ea5e Mon Sep 17 00:00:00 2001 From: Joseph Eng Date: Mon, 11 Nov 2024 11:56:58 -0800 Subject: [PATCH 09/11] Use generic index mapping function --- wpilibc/src/main/native/cpp/LEDPattern.cpp | 77 ++++--------- .../src/main/native/include/frc/LEDPattern.h | 9 ++ .../edu/wpi/first/wpilibj/LEDPattern.java | 107 +++++++++--------- .../java/edu/wpi/first/wpilibj/LEDReader.java | 67 ----------- 4 files changed, 86 insertions(+), 174 deletions(-) diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index fdfd4c21bba..363bd545fe4 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -38,30 +38,26 @@ void LEDPattern::ApplyTo(std::span data) const { ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); } -LEDPattern LEDPattern::Reversed() { - return LEDPattern{[self = *this](auto data, auto writer) { +LEDPattern LEDPattern::MapIndex( + std::function indexMapper) { + return LEDPattern{[self = *this, indexMapper](auto data, auto writer) { + size_t bufLen = data.size(); self.ApplyTo( - LEDPattern::LEDReader{[=](auto i) { return data[data.size() - 1 - i]; }, - data.size()}, - [&](int i, Color color) { writer((data.size() - 1) - i, color); }); + LEDPattern::LEDReader{ + [=](auto i) { return data[indexMapper(bufLen, i)]; }, bufLen}, + [&](int i, Color color) { writer(indexMapper(bufLen, i), color); }); }}; } +LEDPattern LEDPattern::Reversed() { + return MapIndex([](size_t bufLen, size_t i) { return bufLen - 1 - i; }); +} + LEDPattern LEDPattern::OffsetBy(int offset) { - return LEDPattern{[=, self = *this](LEDPattern::LEDReader data, auto writer) { - self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { - int shiftedIndex = frc::FloorMod( - i + offset, - static_cast(d.size())); - return d[shiftedIndex]; - }, - data.size()}, - [&data, &writer, offset](int i, Color color) { - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(data.size())); - writer(shiftedIndex, color); - }); - }}; + return MapIndex([offset](size_t bufLen, size_t i) { + return frc::FloorMod(static_cast(i) + offset, + static_cast(bufLen)); + }); } LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { @@ -70,8 +66,7 @@ LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { // Invert and multiply by 1,000,000 to get microseconds double periodMicros = 1e6 / velocity.value(); - return LEDPattern{[=, self = *this](auto data, auto writer) { - auto bufLen = data.size(); + return MapIndex([=](size_t bufLen, size_t i) { auto now = wpi::Now(); // index should move by (bufLen) / (period) @@ -79,21 +74,9 @@ LEDPattern LEDPattern::ScrollAtRelativeSpeed(units::hertz_t velocity) { (now % static_cast(std::floor(periodMicros))) / periodMicros; int offset = static_cast(std::floor(t * bufLen)); - self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { - int shiftedIndex = frc::FloorMod( - i + offset, - static_cast(d.size())); - return d[shiftedIndex]; - }, - data.size()}, - [=](int i, Color color) { - // floorMod so if the offset is negative, we still get - // positive outputs - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(bufLen)); - writer(shiftedIndex, color); - }); - }}; + return frc::FloorMod(static_cast(i) + offset, + static_cast(bufLen)); + }); } LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( @@ -103,8 +86,7 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( auto microsPerLed = static_cast(std::floor((ledSpacing / velocity).value() * 1e6)); - return LEDPattern{[=, self = *this](auto data, auto writer) { - auto bufLen = data.size(); + return MapIndex([=](size_t bufLen, size_t i) { auto now = wpi::Now(); // every step in time that's a multiple of microsPerLED will increment @@ -113,22 +95,9 @@ LEDPattern LEDPattern::ScrollAtAbsoluteSpeed( // offset values for negative velocities auto offset = static_cast(now) / microsPerLed; - self.ApplyTo(LEDPattern::LEDReader{[=, d = std::move(data)](auto i) { - int shiftedIndex = frc::FloorMod( - i + offset, - static_cast(d.size())); - return d[shiftedIndex]; - }, - data.size()}, - [=, &writer](int i, Color color) { - // FloorMod so if the offset is negative, we still get - // positive outputs - int shiftedIndex = - frc::FloorMod(i + offset, static_cast(bufLen)); - - writer(shiftedIndex, color); - }); - }}; + return frc::FloorMod(static_cast(i) + offset, + static_cast(bufLen)); + }); } LEDPattern LEDPattern::Blink(units::second_t onTime, units::second_t offTime) { diff --git a/wpilibc/src/main/native/include/frc/LEDPattern.h b/wpilibc/src/main/native/include/frc/LEDPattern.h index 2db8dad6296..0b8cfcbd0b7 100644 --- a/wpilibc/src/main/native/include/frc/LEDPattern.h +++ b/wpilibc/src/main/native/include/frc/LEDPattern.h @@ -79,6 +79,15 @@ class LEDPattern { */ void ApplyTo(std::span data) const; + /** + * Creates a pattern with remapped indices. + * + * @param indexMapper the index mapper + * @return the mapped pattern + */ + [[nodiscard]] + LEDPattern MapIndex(std::function indexMapper); + /** * Creates a pattern that displays this one in reverse. Scrolling patterns * will scroll in the opposite direction (but at the same speed). It will diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java index 4e891761527..2148c304053 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java @@ -93,6 +93,18 @@ */ @FunctionalInterface public interface LEDPattern { + /** A functional interface for index mapping functions. */ + @FunctionalInterface + interface IndexMapper { + /** + * Maps the index. + * + * @param bufLen Length of the buffer + * @param index The index to map + */ + int apply(int bufLen, int index); + } + /** * Writes the pattern to an LED buffer. Dynamic animations should be called periodically (such as * with a command or with a periodic method) to refresh the buffer over time. @@ -130,19 +142,12 @@ default void applyTo(T readWriter) { } /** - * Creates a pattern that displays this one in reverse. Scrolling patterns will scroll in the - * opposite direction (but at the same speed). It will treat the end of an LED strip as the start, - * and the start of the strip as the end. This can be useful for making ping-pong patterns that - * travel from one end of an LED strip to the other, then reverse direction and move back to the - * start. This can also be useful when working with LED strips connected in a serpentine pattern - * (where the start of one strip is connected to the end of the previous one); however, consider - * using a {@link AddressableLEDBufferView#reversed() reversed view} of the overall buffer for - * that segment rather than reversing patterns. + * Creates a pattern with remapped indices. * - * @return the reverse pattern - * @see AddressableLEDBufferView#reversed() + * @param indexMapper the index mapper + * @return the mapped pattern */ - default LEDPattern reversed() { + default LEDPattern mapIndex(IndexMapper indexMapper) { return (reader, writer) -> { int bufLen = reader.getLength(); applyTo( @@ -154,23 +159,40 @@ public int getLength() { @Override public int getRed(int index) { - return reader.getRed(getLength() - 1 - index); + return reader.getRed(indexMapper.apply(bufLen, index)); } @Override public int getGreen(int index) { - return reader.getGreen(getLength() - 1 - index); + return reader.getGreen(indexMapper.apply(bufLen, index)); } @Override public int getBlue(int index) { - return reader.getBlue(getLength() - 1 - index); + return reader.getBlue(indexMapper.apply(bufLen, index)); } }, - (i, r, g, b) -> writer.setRGB((bufLen - 1) - i, r, g, b)); + (i, r, g, b) -> writer.setRGB(indexMapper.apply(bufLen, i), r, g, b)); }; } + /** + * Creates a pattern that displays this one in reverse. Scrolling patterns will scroll in the + * opposite direction (but at the same speed). It will treat the end of an LED strip as the start, + * and the start of the strip as the end. This can be useful for making ping-pong patterns that + * travel from one end of an LED strip to the other, then reverse direction and move back to the + * start. This can also be useful when working with LED strips connected in a serpentine pattern + * (where the start of one strip is connected to the end of the previous one); however, consider + * using a {@link AddressableLEDBufferView#reversed() reversed view} of the overall buffer for + * that segment rather than reversing patterns. + * + * @return the reverse pattern + * @see AddressableLEDBufferView#reversed() + */ + default LEDPattern reversed() { + return mapIndex((length, index) -> length - 1 - index); + } + /** * Creates a pattern that plays this one, but offset by a certain number of LEDs. The offset * pattern will wrap around, if necessary. @@ -179,15 +201,7 @@ public int getBlue(int index) { * @return the offset pattern */ default LEDPattern offsetBy(int offset) { - return (reader, writer) -> { - int bufLen = reader.getLength(); - applyTo( - LEDReader.RemappedReader.offset(reader, offset), - (i, r, g, b) -> { - int shiftedIndex = Math.floorMod(i + offset, bufLen); - writer.setRGB(shiftedIndex, r, g, b); - }); - }; + return mapIndex((length, index) -> Math.floorMod(index + offset, length)); } /** @@ -211,23 +225,16 @@ default LEDPattern offsetBy(int offset) { default LEDPattern scrollAtRelativeSpeed(Frequency velocity) { final double periodMicros = velocity.asPeriod().in(Microseconds); - return (reader, writer) -> { - int bufLen = reader.getLength(); - long now = WPIUtilJNI.now(); + return mapIndex( + (bufLen, index) -> { + long now = WPIUtilJNI.now(); - // index should move by (buf.length) / (period) - double t = (now % (long) periodMicros) / periodMicros; - int offset = (int) (t * bufLen); + // index should move by (buf.length) / (period) + double t = (now % (long) periodMicros) / periodMicros; + int offset = (int) (t * bufLen); - applyTo( - LEDReader.RemappedReader.offset(reader, offset), - (i, r, g, b) -> { - // floorMod so if the offset is negative, we still get positive outputs - int shiftedIndex = Math.floorMod(i + offset, bufLen); - - writer.setRGB(shiftedIndex, r, g, b); - }); - }; + return Math.floorMod(index + offset, bufLen); + }); } /** @@ -262,22 +269,16 @@ default LEDPattern scrollAtAbsoluteSpeed(LinearVelocity velocity, Distance ledSp var metersPerMicro = velocity.in(Meters.per(Microsecond)); var microsPerLED = (int) (ledSpacing.in(Meters) / metersPerMicro); - return (reader, writer) -> { - int bufLen = reader.getLength(); - long now = WPIUtilJNI.now(); - - // every step in time that's a multiple of microsPerLED will increment the offset by 1 - var offset = (int) (now / microsPerLED); + return mapIndex( + (bufLen, index) -> { + long now = WPIUtilJNI.now(); - applyTo( - LEDReader.RemappedReader.offset(reader, offset), - (i, r, g, b) -> { - // floorMod so if the offset is negative, we still get positive outputs - int shiftedIndex = Math.floorMod(i + offset, bufLen); + // every step in time that's a multiple of microsPerLED will increment the offset by 1 + var offset = (int) (now / microsPerLED); - writer.setRGB(shiftedIndex, r, g, b); - }); - }; + // floorMod so if the offset is negative, we still get positive outputs + return Math.floorMod(index + offset, bufLen); + }); } /** diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java index b02af03b313..176884a9221 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDReader.java @@ -4,10 +4,8 @@ package edu.wpi.first.wpilibj; -import edu.wpi.first.util.ErrorMessages; import edu.wpi.first.wpilibj.util.Color; import edu.wpi.first.wpilibj.util.Color8Bit; -import java.util.function.IntUnaryOperator; /** Generic interface for reading data from an LED buffer. */ public interface LEDReader { @@ -98,69 +96,4 @@ default void forEach(IndexedColorIterator iterator) { iterator.accept(i, getRed(i), getGreen(i), getBlue(i)); } } - - /** - * An LED reader implementation that operates on remapped indices. Remapping can be done using - * arbitrary mapping functions; a static factory function is also provided for the common use case - * of offset readers for things like scrolling animations. - */ - class RemappedReader implements LEDReader { - private final LEDReader m_reader; - private final IntUnaryOperator m_mapping; - - /** - * Creates a new remapping reader for a backing reader and an arbitrary index remapping - * function. - * - * @param reader the backing reader to use - * @param mapping the mapping function to use - */ - public RemappedReader(LEDReader reader, IntUnaryOperator mapping) { - m_reader = ErrorMessages.requireNonNullParam(reader, "reader", "RemappedReader"); - m_mapping = ErrorMessages.requireNonNullParam(mapping, "mapping", "RemappedReader"); - } - - /** - * Creates a new offset LED reader based on an existing reader and integer offset. The offset - * reader will be circular and wrap around. - * - * @param reader the backing reader to use - * @param offset the offset to use when reading data - * @return the offset reader - */ - public static RemappedReader offset(LEDReader reader, int offset) { - return new RemappedReader( - reader, original -> Math.floorMod(original + offset, reader.getLength())); - } - - @Override - public int getLength() { - return m_reader.getLength(); - } - - @Override - public int getRed(int index) { - return m_reader.getRed(remapIndex(index)); - } - - @Override - public int getGreen(int index) { - return m_reader.getGreen(remapIndex(index)); - } - - @Override - public int getBlue(int index) { - return m_reader.getBlue(remapIndex(index)); - } - - /** - * Remaps an input index to the corresponding offset index. - * - * @param index the input index to remap - * @return the remapped index - */ - public int remapIndex(int index) { - return m_mapping.applyAsInt(index); - } - } } From b93c183a67807b3cdf11d88b443c970426337ebb Mon Sep 17 00:00:00 2001 From: Joseph Eng Date: Tue, 12 Nov 2024 06:36:13 -0800 Subject: [PATCH 10/11] Add missing javadoc return tag --- wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java | 1 + 1 file changed, 1 insertion(+) diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java index 2148c304053..d453093373e 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/LEDPattern.java @@ -101,6 +101,7 @@ interface IndexMapper { * * @param bufLen Length of the buffer * @param index The index to map + * @return The mapped index */ int apply(int bufLen, int index); } From a727614af14f8a3eb2b6ea73405767b49408d8d0 Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Thu, 28 Nov 2024 12:26:39 -0500 Subject: [PATCH 11/11] Fix mock time --- .../edu/wpi/first/wpilibj/LEDPatternTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java index 00e1a3d59d0..a3c70849132 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/LEDPatternTest.java @@ -870,7 +870,7 @@ void relativeScrollingMask() { var buffer = new AddressableLEDBuffer(8); { - WPIUtilJNI.setMockTime(0); // start + m_mockTime = 0; // start pattern.applyTo(buffer); assertColorEquals(kRed, buffer.getLED(0)); assertColorEquals(kRed, buffer.getLED(1)); @@ -883,7 +883,7 @@ void relativeScrollingMask() { } { - WPIUtilJNI.setMockTime(1); + m_mockTime = 1; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kRed, buffer.getLED(1)); @@ -896,7 +896,7 @@ void relativeScrollingMask() { } { - WPIUtilJNI.setMockTime(2); + m_mockTime = 2; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kBlack, buffer.getLED(1)); @@ -909,7 +909,7 @@ void relativeScrollingMask() { } { - WPIUtilJNI.setMockTime(3); + m_mockTime = 3; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kBlack, buffer.getLED(1)); @@ -935,7 +935,7 @@ void absoluteScrollingMask() { var buffer = new AddressableLEDBuffer(8); { - WPIUtilJNI.setMockTime(0); // start + m_mockTime = 0; // start pattern.applyTo(buffer); assertColorEquals(kRed, buffer.getLED(0)); assertColorEquals(kRed, buffer.getLED(1)); @@ -948,7 +948,7 @@ void absoluteScrollingMask() { } { - WPIUtilJNI.setMockTime(1); + m_mockTime = 1; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kRed, buffer.getLED(1)); @@ -961,7 +961,7 @@ void absoluteScrollingMask() { } { - WPIUtilJNI.setMockTime(2); + m_mockTime = 2; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kBlack, buffer.getLED(1)); @@ -974,7 +974,7 @@ void absoluteScrollingMask() { } { - WPIUtilJNI.setMockTime(3); + m_mockTime = 3; pattern.applyTo(buffer); assertColorEquals(kBlack, buffer.getLED(0)); assertColorEquals(kBlack, buffer.getLED(1));