[wpilib] Add EventLoop (#4104)

This is a generic expansion of the command-based Trigger framework.
This commit is contained in:
Starlight220
2022-06-09 08:16:51 +03:00
committed by GitHub
parent 16a4888c52
commit 45b7fc445b
27 changed files with 1265 additions and 428 deletions

View File

@@ -0,0 +1,168 @@
// 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.event;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
class BooleanEventTest {
@Test
void testBinaryCompositions() {
var loop = new EventLoop();
var andCounter = new AtomicInteger(0);
var orCounter = new AtomicInteger(0);
assertEquals(0, andCounter.get());
assertEquals(0, orCounter.get());
new BooleanEvent(loop, () -> true).and(() -> false).ifHigh(andCounter::incrementAndGet);
new BooleanEvent(loop, () -> true).or(() -> false).ifHigh(orCounter::incrementAndGet);
loop.poll();
assertEquals(0, andCounter.get());
assertEquals(1, orCounter.get());
}
@Test
void testBinaryCompositionLoopSemantics() {
var loop1 = new EventLoop();
var loop2 = new EventLoop();
var counter1 = new AtomicInteger(0);
var counter2 = new AtomicInteger(0);
new BooleanEvent(loop1, () -> true)
.and(new BooleanEvent(loop2, () -> true))
.ifHigh(counter1::incrementAndGet);
new BooleanEvent(loop2, () -> true)
.and(new BooleanEvent(loop1, () -> true))
.ifHigh(counter2::incrementAndGet);
assertEquals(0, counter1.get());
assertEquals(0, counter2.get());
loop1.poll();
assertEquals(1, counter1.get());
assertEquals(0, counter2.get());
loop2.poll();
assertEquals(1, counter1.get());
assertEquals(1, counter2.get());
}
@Test
void testEdgeDecorators() {
var bool = new AtomicBoolean(false);
var counter = new AtomicInteger(0);
var loop = new EventLoop();
new BooleanEvent(loop, bool::get).falling().ifHigh(counter::decrementAndGet);
new BooleanEvent(loop, bool::get).rising().ifHigh(counter::incrementAndGet);
assertEquals(0, counter.get());
bool.set(false);
loop.poll();
assertEquals(0, counter.get());
bool.set(true);
loop.poll();
assertEquals(1, counter.get());
bool.set(true);
loop.poll();
assertEquals(1, counter.get());
bool.set(false);
loop.poll();
assertEquals(0, counter.get());
}
@Test
void testEdgeReuse() {
var loop = new EventLoop();
var bool = new AtomicBoolean(false);
var counter = new AtomicInteger(0);
var event = new BooleanEvent(loop, bool::get).rising();
event.ifHigh(counter::incrementAndGet);
event.ifHigh(counter::incrementAndGet);
assertEquals(0, counter.get());
loop.poll();
assertEquals(0, counter.get());
bool.set(true);
loop.poll();
assertEquals(1, counter.get()); // FIXME?: natural sense dictates counter == 2!!
loop.poll();
assertEquals(1, counter.get());
bool.set(false);
loop.poll();
assertEquals(1, counter.get());
bool.set(true);
loop.poll();
assertEquals(2, counter.get());
}
@Test
void testEdgeReconstruct() {
var loop = new EventLoop();
var bool = new AtomicBoolean(false);
var counter = new AtomicInteger(0);
var event = new BooleanEvent(loop, bool::get);
event.rising().ifHigh(counter::incrementAndGet);
event.rising().ifHigh(counter::incrementAndGet);
assertEquals(0, counter.get());
loop.poll();
assertEquals(0, counter.get());
bool.set(true);
loop.poll();
// unlike the previous test ...
assertEquals(2, counter.get()); // as natural sense dictates, counter == 2
loop.poll();
assertEquals(2, counter.get());
bool.set(false);
loop.poll();
assertEquals(2, counter.get());
bool.set(true);
loop.poll();
assertEquals(4, counter.get());
}
}

View File

@@ -0,0 +1,61 @@
// 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.event;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
class EventLoopTest {
@Test
void testConditions() {
var counterTrue = new AtomicInteger(0);
var counterFalse = new AtomicInteger(0);
var loop = new EventLoop();
loop.bind(() -> true, counterTrue::incrementAndGet);
loop.bind(() -> false, counterFalse::incrementAndGet);
assertEquals(0, counterTrue.get());
assertEquals(0, counterFalse.get());
loop.poll();
assertEquals(1, counterTrue.get());
assertEquals(0, counterFalse.get());
loop.poll();
assertEquals(2, counterTrue.get());
assertEquals(0, counterFalse.get());
}
@Test
void testClear() {
var condition = new AtomicBoolean(false);
var counter = new AtomicInteger(0);
var loop = new EventLoop();
// first ensure binding works
loop.bind(condition::get, counter::incrementAndGet);
condition.set(false);
loop.poll();
assertEquals(0, counter.get());
condition.set(true);
loop.poll();
assertEquals(1, counter.get());
// clear bindings
loop.clear();
condition.set(true);
loop.poll();
// shouldn't change
assertEquals(1, counter.get());
}
}