mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-30 02:31:44 +00:00
Compare commits
55 Commits
v2024.1.1-
...
v2024.1.1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1a82828fe | ||
|
|
2a04e12c6f | ||
|
|
33e0089afb | ||
|
|
d06fa633d5 | ||
|
|
049732afb8 | ||
|
|
87f7c19f90 | ||
|
|
6b53ef47cf | ||
|
|
8a3a268ae6 | ||
|
|
1c35d42cd0 | ||
|
|
ddc8db6c26 | ||
|
|
c6aff2c431 | ||
|
|
a9c5b18a39 | ||
|
|
9540b6922d | ||
|
|
83a7d33c47 | ||
|
|
a4a8ad9c75 | ||
|
|
9eecf2a456 | ||
|
|
9536a311cb | ||
|
|
8d5e6737fc | ||
|
|
07e13d60a2 | ||
|
|
1713386869 | ||
|
|
35472f5fc9 | ||
|
|
ed168b522c | ||
|
|
3e7ba2cc6f | ||
|
|
80c47da237 | ||
|
|
abe1cec90c | ||
|
|
cdf981abba | ||
|
|
04dcd80adb | ||
|
|
49920234ac | ||
|
|
366b715942 | ||
|
|
3ba501f947 | ||
|
|
ec569a58ef | ||
|
|
b91317fd36 | ||
|
|
2ab4fcbc24 | ||
|
|
98c14f1692 | ||
|
|
60bcdeded9 | ||
|
|
c87f8fd538 | ||
|
|
ad80eb3a0b | ||
|
|
c7d6ad5a0b | ||
|
|
8a8e220792 | ||
|
|
cfc6a47f76 | ||
|
|
8efa586ace | ||
|
|
23ea188e60 | ||
|
|
928e87b4f4 | ||
|
|
63ef585d4b | ||
|
|
b03a7668f9 | ||
|
|
3f08bcde54 | ||
|
|
196d963dc4 | ||
|
|
f4cbcbc984 | ||
|
|
ec0f7fefb0 | ||
|
|
3d618bdbfd | ||
|
|
1fa7445667 | ||
|
|
269b9647da | ||
|
|
bee32f080e | ||
|
|
25dad5a531 | ||
|
|
4a93581f1a |
12
.github/workflows/cmake.yml
vendored
12
.github/workflows/cmake.yml
vendored
@@ -76,12 +76,6 @@ jobs:
|
||||
- name: Install CMake
|
||||
uses: lukka/get-cmake@v3.27.6
|
||||
|
||||
- name: Run vcpkg
|
||||
uses: lukka/run-vcpkg@v11.1
|
||||
with:
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: 78b61582c9e093fda56a01ebb654be15a0033897 # HEAD on 2023-08-6
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
|
||||
@@ -90,6 +84,12 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Run vcpkg
|
||||
uses: lukka/run-vcpkg@v11.1
|
||||
with:
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: 78b61582c9e093fda56a01ebb654be15a0033897 # HEAD on 2023-08-6
|
||||
|
||||
- name: configure
|
||||
run: cmake -S . -B build -G "Ninja" -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_BUILD_TYPE=Release -DWITH_JAVA=OFF -DWITH_EXAMPLES=ON -DUSE_SYSTEM_FMTLIB=ON -DUSE_SYSTEM_LIBUV=ON -DUSE_SYSTEM_EIGEN=ON -DCMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALL_OPTIONS=--clean-after-build -DVCPKG_TARGET_TRIPLET=x64-windows-release -DVCPKG_HOST_TRIPLET=x64-windows-release
|
||||
env:
|
||||
|
||||
6
.github/workflows/comment-command.yml
vendored
6
.github/workflows/comment-command.yml
vendored
@@ -9,11 +9,11 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: React Rocket
|
||||
uses: actions/github-script@v4
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.issue
|
||||
github.reactions.createForIssueComment({
|
||||
github.rest.reactions.createForIssueComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
GITHUB_TOKEN: "${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}"
|
||||
NUMBER: ${{ github.event.issue.number }}
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Setup Java
|
||||
|
||||
15
.github/workflows/gradle.yml
vendored
15
.github/workflows/gradle.yml
vendored
@@ -193,6 +193,19 @@ jobs:
|
||||
needs: [build-docker, build-host, build-documentation]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
- uses: actions/checkout@v3
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
@@ -223,7 +236,7 @@ jobs:
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 11
|
||||
java-version: 17
|
||||
- name: Combine (Main)
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
|
||||
2
.github/workflows/sanitizers.yml
vendored
2
.github/workflows/sanitizers.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-14 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-14 ${{ matrix.cmake-flags }} ..
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-14 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-14 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ ENDIF("${isSystemDir}" STREQUAL "-1")
|
||||
|
||||
# Options for building certain parts of the repo. Everything is built by default.
|
||||
option(BUILD_SHARED_LIBS "Build with shared libs (needed for JNI)" ON)
|
||||
option(WITH_JAVA "Include java and JNI in the build" ON)
|
||||
option(WITH_JAVA "Include Java and JNI in the build" ON)
|
||||
option(WITH_JAVA_SOURCE "Build Java source jars" ON)
|
||||
option(WITH_CSCORE "Build cscore (needs OpenCV)" ON)
|
||||
option(WITH_NTCORE "Build ntcore" ON)
|
||||
option(WITH_WPIMATH "Build wpimath" ON)
|
||||
|
||||
@@ -34,6 +34,8 @@ The following build options are available:
|
||||
|
||||
* `WITH_JAVA` (ON Default)
|
||||
* This option will enable Java and JNI builds. If this is on, `WITH_SHARED_LIBS` must be on. Otherwise CMake will error.
|
||||
* `WITH_JAVA_SOURCE` (ON Default)
|
||||
* This option will build Java source JARs for each enabled Java library. This does not require `WITH_JAVA` to be on, allowing source JARs to be built without the compiled JARs if desired.
|
||||
* `WITH_SHARED_LIBS` (ON Default)
|
||||
* This option will cause cmake to build static libraries instead of shared libraries. If this is off, `WITH_JAVA` must be off. Otherwise CMake will error.
|
||||
* `WITH_CSCORE` (ON Default)
|
||||
|
||||
19
README.md
19
README.md
@@ -88,9 +88,24 @@ If opening from a fresh clone, generated java dependencies will not exist. Most
|
||||
|
||||
`./gradlew build` builds _everything_, which includes debug and release builds for desktop and all installed cross compilers. Many developers don't need or want to build all of this. Therefore, common tasks have shortcuts to only build necessary components for common development and testing tasks.
|
||||
|
||||
`./gradlew testDesktopCpp` and `./gradlew testDesktopJava` will build and run the tests for `wpilibc` and `wpilibj` respectively. They will only build the minimum components required to run the tests.
|
||||
`./gradlew testDesktopCpp` and `./gradlew testDesktopJava` will build and run the tests for `wpilibc` and `wpilibj` respectively. They will only build the minimum components required to run the tests. `./gradlew testDesktop` will run both `testDesktopJava` and `testDesktopCpp`.
|
||||
|
||||
`testDesktopCpp` and `testDesktopJava` tasks also exist for the projects `wpiutil`, `ntcore`, `cscore`, `hal` `wpilibNewCommands` and `cameraserver`. These can be ran with `./gradlew :projectName:task`.
|
||||
`testDesktopCpp`, `testDesktopJava`, and `testDesktop` tasks also exist for the following projects:
|
||||
|
||||
- `apriltag`
|
||||
- `cameraserver`
|
||||
- `cscore`
|
||||
- `hal`
|
||||
- `ntcore`
|
||||
- `wpilibNewCommands`
|
||||
- `wpimath`
|
||||
- `wpinet`
|
||||
- `wpiunits`
|
||||
- `wpiutil`
|
||||
- `romiVendordep`
|
||||
- `xrpVendordep`
|
||||
|
||||
These can be ran with `./gradlew :projectName:task`.
|
||||
|
||||
`./gradlew buildDesktopCpp` and `./gradlew buildDesktopJava` will compile `wpilibcExamples` and `wpilibjExamples` respectively. The results can't be ran, but they can compile.
|
||||
|
||||
|
||||
@@ -66,6 +66,21 @@ if (WITH_JAVA)
|
||||
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB APRILTAG_SOURCES src/main/java/edu/wpi/first/apriltag/*.java)
|
||||
add_jar(apriltag_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/apriltag" ${APRILTAG_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/apriltag/jni" src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java
|
||||
OUTPUT_NAME apriltag-sources)
|
||||
|
||||
get_property(APRILTAG_SRC_JAR_FILE TARGET apriltag_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${APRILTAG_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET apriltag_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
generate_resources(src/main/native/resources/edu/wpi/first/apriltag generated/main/cpp APRILTAG frc apriltag_resources_src)
|
||||
|
||||
file(GLOB apriltag_native_src src/main/native/cpp/*.cpp)
|
||||
|
||||
@@ -113,6 +113,26 @@ public class AprilTagFieldLayout {
|
||||
return new ArrayList<>(m_apriltags.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing in meters.
|
||||
*
|
||||
* @return length, in meters
|
||||
*/
|
||||
@JsonIgnore
|
||||
public double getFieldLength() {
|
||||
return m_fieldDimensions.fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing in meters.
|
||||
*
|
||||
* @return width, in meters
|
||||
*/
|
||||
@JsonIgnore
|
||||
public double getFieldWidth() {
|
||||
return m_fieldDimensions.fieldWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin based on a predefined enumeration of coordinate frame origins. The origins are
|
||||
* calculated from the field dimensions.
|
||||
@@ -152,6 +172,16 @@ public class AprilTagFieldLayout {
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the origin used for tag pose transformation.
|
||||
*
|
||||
* @return the origin
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Pose3d getOrigin() {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an AprilTag pose by its ID.
|
||||
*
|
||||
|
||||
@@ -41,6 +41,14 @@ AprilTagFieldLayout::AprilTagFieldLayout(std::vector<AprilTag> apriltags,
|
||||
}
|
||||
}
|
||||
|
||||
units::meter_t AprilTagFieldLayout::GetFieldLength() const {
|
||||
return m_fieldLength;
|
||||
}
|
||||
|
||||
units::meter_t AprilTagFieldLayout::GetFieldWidth() const {
|
||||
return m_fieldWidth;
|
||||
}
|
||||
|
||||
void AprilTagFieldLayout::SetOrigin(OriginPosition origin) {
|
||||
switch (origin) {
|
||||
case OriginPosition::kBlueAllianceWallRightSide:
|
||||
@@ -59,6 +67,10 @@ void AprilTagFieldLayout::SetOrigin(const Pose3d& origin) {
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
Pose3d AprilTagFieldLayout::GetOrigin() const {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
std::optional<frc::Pose3d> AprilTagFieldLayout::GetTagPose(int ID) const {
|
||||
const auto& it = m_apriltags.find(ID);
|
||||
if (it == m_apriltags.end()) {
|
||||
|
||||
@@ -62,6 +62,18 @@ class WPILIB_DLLEXPORT AprilTagFieldLayout {
|
||||
AprilTagFieldLayout(std::vector<AprilTag> apriltags,
|
||||
units::meter_t fieldLength, units::meter_t fieldWidth);
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing.
|
||||
* @return length
|
||||
*/
|
||||
units::meter_t GetFieldLength() const;
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing.
|
||||
* @return width
|
||||
*/
|
||||
units::meter_t GetFieldWidth() const;
|
||||
|
||||
/**
|
||||
* Sets the origin based on a predefined enumeration of coordinate frame
|
||||
* origins. The origins are calculated from the field dimensions.
|
||||
@@ -83,6 +95,12 @@ class WPILIB_DLLEXPORT AprilTagFieldLayout {
|
||||
*/
|
||||
void SetOrigin(const Pose3d& origin);
|
||||
|
||||
/**
|
||||
* Returns the origin used for tag pose transformation.
|
||||
* @return the origin
|
||||
*/
|
||||
Pose3d GetOrigin() const;
|
||||
|
||||
/**
|
||||
* Gets an AprilTag pose by its ID.
|
||||
*
|
||||
|
||||
@@ -28,7 +28,7 @@ public class WPIJREArtifact extends MavenArtifact {
|
||||
|
||||
private boolean checkJreVersion = true;
|
||||
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2023:17.0.5u7-1"
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2024:17.0.9u7-1"
|
||||
|
||||
@Inject
|
||||
public WPIJREArtifact(String name, RemoteTarget target) {
|
||||
|
||||
@@ -28,6 +28,22 @@ if (WITH_JAVA)
|
||||
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB CAMERASERVER_SOURCES src/main/java/edu/wpi/first/cameraserver/*.java)
|
||||
file(GLOB VISION_SOURCES src/main/java/edu/wpi/first/vision/*.java)
|
||||
add_jar(cameraserver_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/cameraserver" ${CAMERASERVER_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/vision" ${VISION_SOURCES}
|
||||
OUTPUT_NAME cameraserver-sources)
|
||||
|
||||
get_property(CAMERASERVER_SRC_JAR_FILE TARGET cameraserver_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CAMERASERVER_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET cameraserver_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE
|
||||
cameraserver_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(cameraserver ${cameraserver_native_src})
|
||||
|
||||
@@ -133,6 +133,22 @@ if (WITH_JAVA)
|
||||
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB CSCORE_SOURCES src/main/java/edu/wpi/first/cscore/*.java)
|
||||
file(GLOB CSCORE_RAW_SOURCES src/main/java/edu/wpi/first/cscore/raw/*.java)
|
||||
add_jar(cscore_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/cscore" ${CSCORE_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/cscore/raw" ${CSCORE_RAW_SOURCES}
|
||||
OUTPUT_NAME cscore-sources)
|
||||
|
||||
get_property(CSCORE_SRC_JAR_FILE TARGET cscore_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CSCORE_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET cscore_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
if (WITH_TESTS)
|
||||
wpilib_add_test(cscore src/test/native/cpp)
|
||||
target_link_libraries(cscore_test cscore gmock)
|
||||
|
||||
@@ -595,7 +595,7 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
}
|
||||
|
||||
if (m_connectVerbose) {
|
||||
SINFO("Connecting to USB camera on {}", m_path);
|
||||
SINFO("Attempting to connect to USB camera on {}", m_path);
|
||||
}
|
||||
|
||||
// Try to open the device
|
||||
@@ -606,6 +606,10 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
}
|
||||
m_fd = fd;
|
||||
|
||||
if (m_connectVerbose) {
|
||||
SINFO("Connected to USB camera on {}", m_path);
|
||||
}
|
||||
|
||||
// Get capabilities
|
||||
SDEBUG3("getting capabilities");
|
||||
struct v4l2_capability vcap;
|
||||
|
||||
@@ -554,7 +554,7 @@ static cs::VideoMode::PixelFormat FourCCToPixelFormat(FourCharCode fourcc) {
|
||||
}
|
||||
|
||||
std::string pathStr = [self.path UTF8String];
|
||||
OBJCINFO("Connecting to USB camera on {}", pathStr);
|
||||
OBJCINFO("Attempting to connect to USB camera on {}", pathStr);
|
||||
|
||||
self.videoDevice = [AVCaptureDevice deviceWithUniqueID:self.path];
|
||||
if (self.videoDevice == nil) {
|
||||
@@ -594,6 +594,8 @@ static cs::VideoMode::PixelFormat FourCCToPixelFormat(FourCharCode fourcc) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
OBJCINFO("Connected to USB camera on {}", pathStr);
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(sessionRuntimeError:)
|
||||
|
||||
@@ -499,7 +499,7 @@ bool UsbCameraImpl::DeviceConnect() {
|
||||
}
|
||||
|
||||
if (m_connectVerbose) {
|
||||
SINFO("Connecting to USB camera on {}", m_path);
|
||||
SINFO("Attempting to connect to USB camera on {}", m_path);
|
||||
}
|
||||
|
||||
SDEBUG3("opening device");
|
||||
@@ -526,6 +526,10 @@ bool UsbCameraImpl::DeviceConnect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_connectVerbose) {
|
||||
SINFO("Connected to USB camera on {}", m_path);
|
||||
}
|
||||
|
||||
CS_Status st = 0;
|
||||
auto devices = EnumerateUsbCameras(&st);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class UsbCameraTest {
|
||||
|
||||
assertTimeoutPreemptively(
|
||||
Duration.ofSeconds(5),
|
||||
() -> assertTrue(result.get().contains("Connecting to USB camera on ")));
|
||||
() -> assertTrue(result.get().contains("Attempting to connect to USB camera on ")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +235,7 @@ task generateJavaDocs(type: Javadoc) {
|
||||
source project(':wpilibj').sourceSets.main.java
|
||||
source project(':wpimath').sourceSets.main.java
|
||||
source project(':wpinet').sourceSets.main.java
|
||||
source project(':wpiunits').sourceSets.main.java
|
||||
source project(':wpiutil').sourceSets.main.java
|
||||
source configurations.javaSource.collect { zipTree(it) }
|
||||
include '**/*.java'
|
||||
|
||||
@@ -9,7 +9,7 @@ include(LinkMacOSGUI)
|
||||
#
|
||||
file(GLOB_RECURSE libglass_src src/lib/native/cpp/*.cpp)
|
||||
|
||||
add_library(libglass STATIC ${libglass_src})
|
||||
add_library(libglass ${libglass_src})
|
||||
set_target_properties(libglass PROPERTIES DEBUG_POSTFIX "d" OUTPUT_NAME "glass")
|
||||
set_property(TARGET libglass PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
@@ -30,7 +30,7 @@ install(DIRECTORY src/lib/native/include/ DESTINATION "${include_dest}/glass")
|
||||
#
|
||||
file(GLOB_RECURSE libglassnt_src src/libnt/native/cpp/*.cpp)
|
||||
|
||||
add_library(libglassnt STATIC ${libglassnt_src})
|
||||
add_library(libglassnt ${libglassnt_src})
|
||||
set_target_properties(libglassnt PROPERTIES DEBUG_POSTFIX "d" OUTPUT_NAME "glassnt")
|
||||
set_property(TARGET libglassnt PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
using namespace glass;
|
||||
|
||||
static const char* stations[] = {"Red 1", "Red 2", "Red 3",
|
||||
"Blue 1", "Blue 2", "Blue 3"};
|
||||
static const char* stations[] = {"Invalid", "Red 1", "Red 2", "Red 3",
|
||||
"Blue 1", "Blue 2", "Blue 3"};
|
||||
|
||||
void glass::DisplayFMS(FMSModel* model) {
|
||||
if (!model->Exists() || model->IsReadOnly()) {
|
||||
@@ -41,7 +41,7 @@ void glass::DisplayFMS(FMSModel* model) {
|
||||
if (auto data = model->GetAllianceStationIdData()) {
|
||||
int val = data->GetValue();
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
|
||||
if (ImGui::Combo("Alliance Station", &val, stations, 6)) {
|
||||
if (ImGui::Combo("Alliance Station", &val, stations, 7)) {
|
||||
model->SetAllianceStationId(val);
|
||||
}
|
||||
data->EmitDrag();
|
||||
|
||||
@@ -895,12 +895,16 @@ void NetworkTablesModel::Update() {
|
||||
entry->info.type_str == "proto:FileDescriptorProto") {
|
||||
// protobuf descriptor handling
|
||||
auto filename = wpi::drop_front(entry->info.name, 15);
|
||||
m_protoDb.Add(filename, entry->value.GetRaw());
|
||||
// loop over all protobuf entries and update (conservatively)
|
||||
for (auto&& entryPair : m_entries) {
|
||||
auto ts = entryPair.second->info.type_str;
|
||||
if (wpi::starts_with(ts, "proto:")) {
|
||||
entryPair.second->UpdateFromValue(*this);
|
||||
if (!m_protoDb.Add(filename, entry->value.GetRaw())) {
|
||||
fmt::print("could not decode protobuf '{}' filename '{}'\n",
|
||||
entry->info.name, filename);
|
||||
} else {
|
||||
// loop over all protobuf entries and update (conservatively)
|
||||
for (auto&& entryPair : m_entries) {
|
||||
auto& ts = entryPair.second->info.type_str;
|
||||
if (wpi::starts_with(ts, "proto:")) {
|
||||
entryPair.second->UpdateFromValue(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1067,7 +1071,7 @@ void NetworkTablesModel::UpdateClients(std::span<const uint8_t> data) {
|
||||
m_clients = std::move(newClients);
|
||||
}
|
||||
|
||||
static bool SimplifyTypeString(std::string_view* ts) {
|
||||
static bool GetHeadingTypeString(std::string_view* ts) {
|
||||
if (wpi::starts_with(*ts, "proto:")) {
|
||||
*ts = wpi::drop_front(*ts, 6);
|
||||
auto lastdot = ts->rfind('.');
|
||||
@@ -1085,24 +1089,71 @@ static bool SimplifyTypeString(std::string_view* ts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* GetShortTypeString(std::string_view ts) {
|
||||
if (wpi::starts_with(ts, "proto:")) {
|
||||
return "protobuf";
|
||||
} else if (wpi::starts_with(ts, "struct:")) {
|
||||
return "struct";
|
||||
} else {
|
||||
return ts.data();
|
||||
}
|
||||
}
|
||||
|
||||
static const char* GetTypeString(NT_Type type, const char* overrideTypeStr) {
|
||||
if (overrideTypeStr) {
|
||||
return GetShortTypeString(overrideTypeStr);
|
||||
}
|
||||
switch (type) {
|
||||
case NT_BOOLEAN:
|
||||
return "boolean";
|
||||
case NT_INTEGER:
|
||||
return "int";
|
||||
case NT_FLOAT:
|
||||
return "float";
|
||||
case NT_DOUBLE:
|
||||
return "double";
|
||||
case NT_STRING:
|
||||
return "string";
|
||||
case NT_BOOLEAN_ARRAY:
|
||||
return "boolean[]";
|
||||
case NT_INTEGER_ARRAY:
|
||||
return "int[]";
|
||||
case NT_FLOAT_ARRAY:
|
||||
return "float[]";
|
||||
case NT_DOUBLE_ARRAY:
|
||||
return "double[]";
|
||||
case NT_STRING_ARRAY:
|
||||
return "string[]";
|
||||
case NT_RAW:
|
||||
return "raw";
|
||||
case NT_RPC:
|
||||
return "rpc";
|
||||
default:
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitEntryValueReadonly(const NetworkTablesModel::ValueSource& entry,
|
||||
const char* typeStr,
|
||||
const char* overrideTypeStr,
|
||||
NetworkTablesFlags flags) {
|
||||
auto& val = entry.value;
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* typeStr = GetTypeString(val.type(), overrideTypeStr);
|
||||
ImGui::SetNextItemWidth(
|
||||
-1 * (ImGui::CalcTextSize(typeStr).x + ImGui::GetStyle().FramePadding.x));
|
||||
|
||||
switch (val.type()) {
|
||||
case NT_BOOLEAN:
|
||||
ImGui::LabelText(typeStr ? typeStr : "boolean", "%s",
|
||||
val.GetBoolean() ? "true" : "false");
|
||||
ImGui::LabelText(typeStr, "%s", val.GetBoolean() ? "true" : "false");
|
||||
break;
|
||||
case NT_INTEGER:
|
||||
ImGui::LabelText(typeStr ? typeStr : "int", "%" PRId64, val.GetInteger());
|
||||
ImGui::LabelText(typeStr, "%" PRId64, val.GetInteger());
|
||||
break;
|
||||
case NT_FLOAT:
|
||||
ImGui::LabelText(typeStr ? typeStr : "double", "%.6f", val.GetFloat());
|
||||
ImGui::LabelText(typeStr, "%.6f", val.GetFloat());
|
||||
break;
|
||||
case NT_DOUBLE: {
|
||||
unsigned char precision = (flags & NetworkTablesFlags_Precision) >>
|
||||
@@ -1111,8 +1162,7 @@ static void EmitEntryValueReadonly(const NetworkTablesModel::ValueSource& entry,
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
ImGui::LabelText(typeStr ? typeStr : "double",
|
||||
fmt::format("%.{}f", precision).c_str(),
|
||||
ImGui::LabelText(typeStr, fmt::format("%.{}f", precision).c_str(),
|
||||
val.GetDouble());
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -1120,33 +1170,22 @@ static void EmitEntryValueReadonly(const NetworkTablesModel::ValueSource& entry,
|
||||
break;
|
||||
}
|
||||
case NT_STRING: {
|
||||
ImGui::LabelText(typeStr ? typeStr : "string", "%s",
|
||||
entry.valueStr.c_str());
|
||||
ImGui::LabelText(typeStr, "%s", entry.valueStr.c_str());
|
||||
break;
|
||||
}
|
||||
case NT_BOOLEAN_ARRAY:
|
||||
ImGui::LabelText(typeStr ? typeStr : "boolean[]", "[]");
|
||||
break;
|
||||
case NT_INTEGER_ARRAY:
|
||||
ImGui::LabelText(typeStr ? typeStr : "int[]", "[]");
|
||||
break;
|
||||
case NT_FLOAT_ARRAY:
|
||||
ImGui::LabelText(typeStr ? typeStr : "float[]", "[]");
|
||||
break;
|
||||
case NT_DOUBLE_ARRAY:
|
||||
ImGui::LabelText(typeStr ? typeStr : "double[]", "[]");
|
||||
break;
|
||||
case NT_STRING_ARRAY:
|
||||
ImGui::LabelText(typeStr ? typeStr : "string[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
break;
|
||||
case NT_RAW: {
|
||||
std::string_view ts = typeStr ? typeStr : "raw";
|
||||
bool partial = SimplifyTypeString(&ts);
|
||||
ImGui::LabelText(val.GetRaw().empty() ? "[]" : "[...]", "%s", ts.data());
|
||||
ImGui::LabelText(typeStr, val.GetRaw().empty() ? "[]" : "[...]");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
if (partial) {
|
||||
ImGui::TextUnformatted(typeStr);
|
||||
if (overrideTypeStr) {
|
||||
ImGui::TextUnformatted(overrideTypeStr);
|
||||
}
|
||||
ImGui::Text("%u bytes", static_cast<unsigned int>(val.GetRaw().size()));
|
||||
ImGui::EndTooltip();
|
||||
@@ -1154,7 +1193,7 @@ static void EmitEntryValueReadonly(const NetworkTablesModel::ValueSource& entry,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ImGui::LabelText(typeStr ? typeStr : "other", "?");
|
||||
ImGui::LabelText(typeStr, "?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1316,14 +1355,18 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
return;
|
||||
}
|
||||
|
||||
const char* typeStr =
|
||||
entry.info.type_str.empty() ? nullptr : entry.info.type_str.c_str();
|
||||
const char* typeStr = GetTypeString(
|
||||
val.type(),
|
||||
entry.info.type_str.empty() ? nullptr : entry.info.type_str.c_str());
|
||||
ImGui::SetNextItemWidth(
|
||||
-1 * (ImGui::CalcTextSize(typeStr).x + ImGui::GetStyle().FramePadding.x));
|
||||
|
||||
ImGui::PushID(entry.info.name.c_str());
|
||||
switch (val.type()) {
|
||||
case NT_BOOLEAN: {
|
||||
static const char* boolOptions[] = {"false", "true"};
|
||||
int v = val.GetBoolean() ? 1 : 0;
|
||||
if (ImGui::Combo(typeStr ? typeStr : "boolean", &v, boolOptions, 2)) {
|
||||
if (ImGui::Combo(typeStr, &v, boolOptions, 2)) {
|
||||
if (entry.publisher == 0) {
|
||||
entry.publisher =
|
||||
nt::Publish(entry.info.topic, NT_BOOLEAN, "boolean");
|
||||
@@ -1334,9 +1377,8 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
case NT_INTEGER: {
|
||||
int64_t v = val.GetInteger();
|
||||
if (ImGui::InputScalar(typeStr ? typeStr : "int", ImGuiDataType_S64, &v,
|
||||
nullptr, nullptr, nullptr,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (ImGui::InputScalar(typeStr, ImGuiDataType_S64, &v, nullptr, nullptr,
|
||||
nullptr, ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (entry.publisher == 0) {
|
||||
entry.publisher = nt::Publish(entry.info.topic, NT_INTEGER, "int");
|
||||
}
|
||||
@@ -1346,7 +1388,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
case NT_FLOAT: {
|
||||
float v = val.GetFloat();
|
||||
if (ImGui::InputFloat(typeStr ? typeStr : "float", &v, 0, 0, "%.6f",
|
||||
if (ImGui::InputFloat(typeStr, &v, 0, 0, "%.6f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (entry.publisher == 0) {
|
||||
entry.publisher = nt::Publish(entry.info.topic, NT_FLOAT, "float");
|
||||
@@ -1363,7 +1405,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
if (ImGui::InputDouble(typeStr ? typeStr : "double", &v, 0, 0,
|
||||
if (ImGui::InputDouble(typeStr, &v, 0, 0,
|
||||
fmt::format("%.{}f", precision).c_str(),
|
||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (entry.publisher == 0) {
|
||||
@@ -1378,7 +1420,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
case NT_STRING: {
|
||||
char* v = GetTextBuffer(entry.valueStr);
|
||||
if (ImGui::InputText(typeStr ? typeStr : "string", v, kTextBufferSize,
|
||||
if (ImGui::InputText(typeStr, v, kTextBufferSize,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (v[0] == '"') {
|
||||
if (entry.publisher == 0) {
|
||||
@@ -1393,7 +1435,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
break;
|
||||
}
|
||||
case NT_BOOLEAN_ARRAY:
|
||||
ImGui::LabelText("boolean[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
if (ImGui::BeginPopupContextItem("boolean[]")) {
|
||||
if (ImGui::Selectable("Edit Array")) {
|
||||
gArrayEditor =
|
||||
@@ -1406,7 +1448,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
break;
|
||||
case NT_INTEGER_ARRAY:
|
||||
ImGui::LabelText("int[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
if (ImGui::BeginPopupContextItem("int[]")) {
|
||||
if (ImGui::Selectable("Edit Array")) {
|
||||
gArrayEditor =
|
||||
@@ -1419,7 +1461,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
break;
|
||||
case NT_FLOAT_ARRAY:
|
||||
ImGui::LabelText("float[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
if (ImGui::BeginPopupContextItem("float[]")) {
|
||||
if (ImGui::Selectable("Edit Array")) {
|
||||
gArrayEditor =
|
||||
@@ -1431,7 +1473,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
break;
|
||||
case NT_DOUBLE_ARRAY:
|
||||
ImGui::LabelText("double[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
if (ImGui::BeginPopupContextItem("double[]")) {
|
||||
if (ImGui::Selectable("Edit Array")) {
|
||||
gArrayEditor =
|
||||
@@ -1443,7 +1485,7 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
break;
|
||||
case NT_STRING_ARRAY:
|
||||
ImGui::LabelText("string[]", "[]");
|
||||
ImGui::LabelText(typeStr, "[]");
|
||||
if (ImGui::BeginPopupContextItem("string[]")) {
|
||||
if (ImGui::Selectable("Edit Array")) {
|
||||
gArrayEditor =
|
||||
@@ -1456,13 +1498,11 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
}
|
||||
break;
|
||||
case NT_RAW: {
|
||||
std::string_view ts = typeStr ? typeStr : "raw";
|
||||
bool partial = SimplifyTypeString(&ts);
|
||||
ImGui::LabelText(val.GetRaw().empty() ? "[]" : "[...]", "%s", ts.data());
|
||||
ImGui::LabelText(typeStr, val.GetRaw().empty() ? "[]" : "[...]");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
if (partial) {
|
||||
ImGui::TextUnformatted(typeStr);
|
||||
if (!entry.info.type_str.empty()) {
|
||||
ImGui::TextUnformatted(entry.info.type_str.c_str());
|
||||
}
|
||||
ImGui::Text("%u bytes", static_cast<unsigned int>(val.GetRaw().size()));
|
||||
ImGui::EndTooltip();
|
||||
@@ -1470,10 +1510,10 @@ static void EmitEntryValueEditable(NetworkTablesModel* model,
|
||||
break;
|
||||
}
|
||||
case NT_RPC:
|
||||
ImGui::LabelText(typeStr ? typeStr : "rpc", "[...]");
|
||||
ImGui::LabelText(typeStr, "[...]");
|
||||
break;
|
||||
default:
|
||||
ImGui::LabelText(typeStr ? typeStr : "other", "?");
|
||||
ImGui::LabelText(typeStr, "?");
|
||||
break;
|
||||
}
|
||||
ImGui::PopID();
|
||||
@@ -1610,7 +1650,7 @@ static void EmitValueTree(
|
||||
auto pos = ImGui::GetCursorPos();
|
||||
char label[128];
|
||||
std::string_view ts = child.typeStr;
|
||||
bool havePopup = SimplifyTypeString(&ts);
|
||||
bool havePopup = GetHeadingTypeString(&ts);
|
||||
wpi::format_to_n_c_str(label, sizeof(label), "{}##v_{}", ts.data(),
|
||||
child.name.c_str());
|
||||
bool valueChildrenOpen =
|
||||
@@ -1652,7 +1692,7 @@ static void EmitEntry(NetworkTablesModel* model,
|
||||
auto pos = ImGui::GetCursorPos();
|
||||
char label[128];
|
||||
std::string_view ts = entry.info.type_str;
|
||||
bool havePopup = SimplifyTypeString(&ts);
|
||||
bool havePopup = GetHeadingTypeString(&ts);
|
||||
wpi::format_to_n_c_str(label, sizeof(label), "{}##v_{}", ts.data(),
|
||||
entry.info.name.c_str());
|
||||
valueChildrenOpen =
|
||||
@@ -1666,8 +1706,13 @@ static void EmitEntry(NetworkTablesModel* model,
|
||||
}
|
||||
}
|
||||
// make it look like a normal label w/type
|
||||
const char* typeStr = GetTypeString(
|
||||
NT_RAW,
|
||||
entry.info.type_str.empty() ? nullptr : entry.info.type_str.c_str());
|
||||
ImGui::SetCursorPos(pos);
|
||||
ImGui::LabelText(entry.info.type_str.c_str(), "%s", "");
|
||||
ImGui::SetNextItemWidth(-1 * (ImGui::CalcTextSize(typeStr).x +
|
||||
ImGui::GetStyle().FramePadding.x));
|
||||
ImGui::LabelText(typeStr, "%s", "");
|
||||
if ((entry.value.IsBooleanArray() || entry.value.IsFloatArray() ||
|
||||
entry.value.IsDoubleArray() || entry.value.IsIntegerArray() ||
|
||||
entry.value.IsStringArray()) &&
|
||||
|
||||
@@ -80,12 +80,10 @@ if (WITH_JAVA)
|
||||
|
||||
file(GLOB_RECURSE hal_shared_jni_src src/main/native/cpp/jni/*.cpp)
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FRCNetComm.java
|
||||
src/main/java/*.java)
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
set(CMAKE_JNI_TARGET true)
|
||||
|
||||
add_jar(hal_jar ${JAVA_SOURCES} INCLUDE_JARS wpiutil_jar OUTPUT_NAME wpiHal GENERATE_NATIVE_HEADERS hal_jni_headers)
|
||||
add_jar(hal_jar ${JAVA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/FRCNetComm.java INCLUDE_JARS wpiutil_jar OUTPUT_NAME wpiHal GENERATE_NATIVE_HEADERS hal_jni_headers)
|
||||
|
||||
get_property(HAL_JAR_FILE TARGET hal_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${HAL_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
@@ -112,6 +110,27 @@ if (WITH_JAVA)
|
||||
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB HAL_SOURCES src/main/java/edu/wpi/first/hal/*.java ${CMAKE_CURRENT_BINARY_DIR}/FRCNetComm.java)
|
||||
file(GLOB HAL_CAN_SOURCES src/main/java/edu/wpi/first/hal/can/*.java)
|
||||
file(GLOB HAL_SIMULATION_SOURCES src/main/java/edu/wpi/first/hal/simulation/*.java)
|
||||
file(GLOB HAL_UTIL_SOURCES src/main/java/edu/wpi/first/hal/util/*.java)
|
||||
add_jar(hal_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/hal" ${HAL_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/hal/can" ${HAL_CAN_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/hal/communication" src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
|
||||
NAMESPACE "edu/wpi/first/hal/simulation" ${HAL_SIMULATION_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/hal/util" ${HAL_UTIL_SOURCES}
|
||||
OUTPUT_NAME wpiHal-sources)
|
||||
|
||||
get_property(HAL_SRC_JAR_FILE TARGET hal_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${HAL_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET hal_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
if (WITH_TESTS)
|
||||
wpilib_add_test(hal src/test/native/cpp)
|
||||
target_link_libraries(hal_test hal gtest)
|
||||
|
||||
@@ -92,4 +92,11 @@ kResourceType_TrapezoidProfile = 90
|
||||
kResourceType_DutyCycle = 91
|
||||
kResourceType_AddressableLEDs = 92
|
||||
kResourceType_FusionVenom = 93
|
||||
kResourceType_PS4Controller = 94
|
||||
kResourceType_CTRE_future7 = 94
|
||||
kResourceType_CTRE_future8 = 95
|
||||
kResourceType_CTRE_future9 = 96
|
||||
kResourceType_CTRE_future10 = 97
|
||||
kResourceType_CTRE_future11 = 98
|
||||
kResourceType_CTRE_future12 = 99
|
||||
kResourceType_CTRE_future13 = 100
|
||||
kResourceType_CTRE_future14 = 101
|
||||
|
||||
@@ -102,8 +102,11 @@ void JoystickDataCache::Update() {
|
||||
HAL_GetJoystickPOVsInternal(i, &povs[i]);
|
||||
HAL_GetJoystickButtonsInternal(i, &buttons[i]);
|
||||
}
|
||||
FRC_NetworkCommunication_getAllianceStation(
|
||||
reinterpret_cast<AllianceStationID_t*>(&allianceStation));
|
||||
AllianceStationID_t alliance = kAllianceStationID_red1;
|
||||
FRC_NetworkCommunication_getAllianceStation(&alliance);
|
||||
int allianceInt = alliance;
|
||||
allianceInt += 1;
|
||||
allianceStation = static_cast<HAL_AllianceStationID>(allianceInt);
|
||||
FRC_NetworkCommunication_getMatchTime(&matchTime);
|
||||
FRC_NetworkCommunication_getControlWord(
|
||||
reinterpret_cast<ControlWord_t*>(&controlWord));
|
||||
|
||||
@@ -56,7 +56,9 @@ HAL_ENUM(HAL_CANManufacturer) {
|
||||
HAL_CAN_Man_kPWF = 11,
|
||||
HAL_CAN_Man_kStudica = 12,
|
||||
HAL_CAN_Man_kTheThriftyBot = 13,
|
||||
HAL_CAN_Man_kReduxRobotics = 14
|
||||
HAL_CAN_Man_kReduxRobotics = 14,
|
||||
HAL_CAN_Man_kAndyMark = 15,
|
||||
HAL_CAN_Man_kVividHosting = 16
|
||||
};
|
||||
// clang-format on
|
||||
/** @} */
|
||||
|
||||
@@ -205,7 +205,7 @@ void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Sets the PWM output to be a continous high signal while enabled.
|
||||
* Sets the PWM output to be a continuous high signal while enabled.
|
||||
*
|
||||
* @param[in] pwmPortHandle the PWM handle.
|
||||
* @param[out] status Error status variable. 0 on success.
|
||||
|
||||
@@ -194,7 +194,7 @@ int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
|
||||
|
||||
HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
|
||||
if (gShutdown) {
|
||||
return HAL_AllianceStationID_kRed1;
|
||||
return HAL_AllianceStationID_kUnknown;
|
||||
}
|
||||
std::scoped_lock lock{driverStation->cacheMutex};
|
||||
return currentRead->allianceStation;
|
||||
|
||||
@@ -69,15 +69,19 @@ endif()
|
||||
file(GLOB imgui_sources ${imgui_SOURCE_DIR}/*.cpp ${imgui_SOURCE_DIR}/misc/cpp/*.cpp)
|
||||
file(GLOB implot_sources ${implot_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB fonts_sources ${fonts_SOURCE_DIR}/src/*.cpp)
|
||||
add_library(imgui STATIC
|
||||
set(imgui_all_sources
|
||||
${imgui_sources}
|
||||
${implot_sources}
|
||||
${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
||||
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
|
||||
${gl3w_BINARY_DIR}/src/gl3w.c
|
||||
${fonts_sources}
|
||||
src/stb_image.cpp
|
||||
)
|
||||
src/stb_image.cpp)
|
||||
if (MSVC)
|
||||
add_library(imgui STATIC ${imgui_all_sources})
|
||||
else()
|
||||
add_library(imgui ${imgui_all_sources})
|
||||
endif()
|
||||
target_compile_definitions(imgui PUBLIC IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
if (MSVC)
|
||||
target_sources(imgui PRIVATE ${imgui_SOURCE_DIR}/backends/imgui_impl_dx11.cpp)
|
||||
|
||||
@@ -90,6 +90,20 @@ if (WITH_JAVA)
|
||||
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB NTCORE_SOURCES src/main/java/edu/wpi/first/networktables/*.java ${WPILIB_BINARY_DIR}/ntcore/generated/*.java)
|
||||
add_jar(ntcore_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/networktables" ${NTCORE_SOURCES}
|
||||
OUTPUT_NAME ntcore-sources)
|
||||
|
||||
get_property(NTCORE_SRC_JAR_FILE TARGET ntcore_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${NTCORE_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET ntcore_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
add_executable(ntcoredev src/dev/native/cpp/main.cpp)
|
||||
wpilib_target_warnings(ntcoredev)
|
||||
target_link_libraries(ntcoredev ntcore)
|
||||
|
||||
@@ -858,14 +858,14 @@ LocalStorage::PublisherData* LocalStorage::Impl::PublishEntry(EntryData* entry,
|
||||
if (entry->publisher) {
|
||||
return entry->publisher;
|
||||
}
|
||||
auto typeStr = TypeToString(type);
|
||||
if (entry->subscriber->config.type == NT_UNASSIGNED) {
|
||||
auto typeStr = TypeToString(type);
|
||||
entry->subscriber->config.type = type;
|
||||
entry->subscriber->config.typeStr = typeStr;
|
||||
} else if (entry->subscriber->config.type != type ||
|
||||
entry->subscriber->config.typeStr != typeStr) {
|
||||
} else if (entry->subscriber->config.type != type) {
|
||||
if (!IsNumericCompatible(type, entry->subscriber->config.type)) {
|
||||
// don't allow dynamically changing the type of an entry
|
||||
auto typeStr = TypeToString(type);
|
||||
ERR("cannot publish entry {} as type {}, previously subscribed as {}",
|
||||
entry->topic->name, typeStr, entry->subscriber->config.typeStr);
|
||||
return nullptr;
|
||||
|
||||
@@ -401,6 +401,7 @@ void NetworkClient::WsConnected(wpi::WebSocket& ws, uv::Tcp& tcp,
|
||||
|
||||
m_wire =
|
||||
std::make_shared<net::WebSocketConnection>(ws, connInfo.protocol_version);
|
||||
m_wire->Start();
|
||||
m_clientImpl = std::make_unique<net::ClientImpl>(
|
||||
m_loop.Now().count(), m_inst, *m_wire, m_logger, m_timeSyncUpdated,
|
||||
[this](uint32_t repeatMs) {
|
||||
@@ -417,9 +418,13 @@ void NetworkClient::WsConnected(wpi::WebSocket& ws, uv::Tcp& tcp,
|
||||
ws.closed.connect([this, &ws](uint16_t, std::string_view reason) {
|
||||
if (!ws.GetStream().IsLoopClosing()) {
|
||||
// we could be in the middle of sending data, so defer disconnect
|
||||
// capture a shared_ptr copy of ws to make sure it doesn't get destroyed
|
||||
// until after DoDisconnect returns
|
||||
uv::Timer::SingleShot(
|
||||
m_loop, uv::Timer::Time{0},
|
||||
[this, reason = std::string{reason}] { DoDisconnect(reason); });
|
||||
[this, reason = std::string{reason}, keepws = ws.shared_from_this()] {
|
||||
DoDisconnect(reason);
|
||||
});
|
||||
}
|
||||
});
|
||||
ws.text.connect([this](std::string_view data, bool) {
|
||||
|
||||
@@ -280,6 +280,7 @@ void NetworkServer::ServerConnection4::ProcessWsUpgrade() {
|
||||
INFO("CONNECTED NT4 client '{}' (from {})", dedupName, m_connInfo);
|
||||
m_info.remote_id = dedupName;
|
||||
m_server.AddConnection(this, m_info);
|
||||
m_wire->Start();
|
||||
m_websocket->closed.connect([this](uint16_t, std::string_view reason) {
|
||||
auto realReason = m_wire->GetDisconnectReason();
|
||||
INFO("DISCONNECTED NT4 client '{}' (from {}): {}", m_info.remote_id,
|
||||
|
||||
@@ -1887,12 +1887,16 @@ void ServerImpl::SetLocal(LocalInterface* local) {
|
||||
}
|
||||
|
||||
void ServerImpl::ProcessIncomingText(int clientId, std::string_view data) {
|
||||
m_clients[clientId]->ProcessIncomingText(data);
|
||||
if (auto client = m_clients[clientId].get()) {
|
||||
client->ProcessIncomingText(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerImpl::ProcessIncomingBinary(int clientId,
|
||||
std::span<const uint8_t> data) {
|
||||
m_clients[clientId]->ProcessIncomingBinary(data);
|
||||
if (auto client = m_clients[clientId].get()) {
|
||||
client->ProcessIncomingBinary(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerImpl::ConnectionsChanged(const std::vector<ConnectionInfo>& conns) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "WebSocketConnection.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
#include <wpi/Endian.h>
|
||||
@@ -30,7 +31,8 @@ class WebSocketConnection::Stream final : public wpi::raw_ostream {
|
||||
public:
|
||||
explicit Stream(WebSocketConnection& conn) : m_conn{conn} {
|
||||
auto& buf = conn.m_bufs.back();
|
||||
SetBuffer(buf.base + buf.len, kAllocSize - buf.len);
|
||||
SetBuffer(buf.base, kAllocSize);
|
||||
SetNumBytesInBuffer(buf.len);
|
||||
}
|
||||
|
||||
~Stream() final {
|
||||
@@ -48,51 +50,47 @@ class WebSocketConnection::Stream final : public wpi::raw_ostream {
|
||||
};
|
||||
|
||||
void WebSocketConnection::Stream::write_impl(const char* data, size_t len) {
|
||||
if (len > kAllocSize) {
|
||||
// only called by raw_ostream::write() when the buffer is empty and a large
|
||||
// thing is being written; called with a length that's a multiple of the
|
||||
// alloc size
|
||||
assert((len % kAllocSize) == 0);
|
||||
assert(m_conn.m_bufs.back().len == 0);
|
||||
while (len > 0) {
|
||||
auto& buf = m_conn.m_bufs.back();
|
||||
std::memcpy(buf.base, data, kAllocSize);
|
||||
buf.len = kAllocSize;
|
||||
m_conn.m_framePos += kAllocSize;
|
||||
m_conn.m_written += kAllocSize;
|
||||
data += kAllocSize;
|
||||
len -= kAllocSize;
|
||||
if (data == m_conn.m_bufs.back().base) {
|
||||
// flush_nonempty() case
|
||||
m_conn.m_bufs.back().len = len;
|
||||
if (!m_disableAlloc) {
|
||||
m_conn.m_frames.back().opcode &= ~wpi::WebSocket::kFlagFin;
|
||||
m_conn.StartFrame(wpi::WebSocket::Frame::kFragment);
|
||||
SetBuffer(m_conn.m_bufs.back().base, kAllocSize);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool updateBuffer = false;
|
||||
while (len > 0) {
|
||||
auto& buf = m_conn.m_bufs.back();
|
||||
assert(buf.len <= kAllocSize);
|
||||
size_t amt = (std::min)(static_cast<int>(kAllocSize - buf.len),
|
||||
static_cast<int>(len));
|
||||
if (amt > 0) {
|
||||
std::memcpy(buf.base + buf.len, data, amt);
|
||||
buf.len += amt;
|
||||
m_conn.m_framePos += amt;
|
||||
m_conn.m_written += amt;
|
||||
data += amt;
|
||||
len -= amt;
|
||||
}
|
||||
if (buf.len >= kAllocSize && (len > 0 || !m_disableAlloc)) {
|
||||
// fragment the current frame and start a new one
|
||||
m_conn.m_frames.back().opcode &= ~wpi::WebSocket::kFlagFin;
|
||||
m_conn.StartFrame(wpi::WebSocket::Frame::kFragment);
|
||||
updateBuffer = true;
|
||||
}
|
||||
SetBuffer(m_conn.m_bufs.back().base, kAllocSize);
|
||||
[[unlikely]] return;
|
||||
}
|
||||
|
||||
auto& buf = m_conn.m_bufs.back();
|
||||
buf.len += len;
|
||||
m_conn.m_framePos += len;
|
||||
m_conn.m_written += len;
|
||||
if (!m_disableAlloc && buf.len >= kAllocSize) {
|
||||
// fragment the current frame and start a new one
|
||||
[[unlikely]] m_conn.m_frames.back().opcode &= ~wpi::WebSocket::kFlagFin;
|
||||
m_conn.StartFrame(wpi::WebSocket::Frame::kFragment);
|
||||
if (updateBuffer) {
|
||||
SetBuffer(m_conn.m_bufs.back().base, kAllocSize);
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketConnection::WebSocketConnection(wpi::WebSocket& ws,
|
||||
unsigned int version)
|
||||
: m_ws{ws}, m_version{version} {
|
||||
m_ws.pong.connect([this](auto data) {
|
||||
if (data.size() != 8) {
|
||||
return;
|
||||
}
|
||||
m_lastPingResponse =
|
||||
wpi::support::endian::read64<wpi::support::native>(data.data());
|
||||
});
|
||||
}
|
||||
: m_ws{ws}, m_version{version} {}
|
||||
|
||||
WebSocketConnection::~WebSocketConnection() {
|
||||
for (auto&& buf : m_bufs) {
|
||||
@@ -103,6 +101,18 @@ WebSocketConnection::~WebSocketConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketConnection::Start() {
|
||||
m_ws.pong.connect([selfweak = weak_from_this()](auto data) {
|
||||
if (data.size() != 8) {
|
||||
return;
|
||||
}
|
||||
if (auto self = selfweak.lock()) {
|
||||
self->m_lastPingResponse =
|
||||
wpi::support::endian::read64<wpi::support::native>(data.data());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WebSocketConnection::SendPing(uint64_t time) {
|
||||
auto buf = AllocBuf();
|
||||
buf.len = 8;
|
||||
@@ -128,7 +138,7 @@ void WebSocketConnection::StartFrame(uint8_t opcode) {
|
||||
void WebSocketConnection::FinishText() {
|
||||
assert(!m_bufs.empty());
|
||||
auto& buf = m_bufs.back();
|
||||
assert(buf.len < kAllocSize + 1); // safe because we alloc one more byte
|
||||
assert(buf.len < (kAllocSize + 1)); // safe because we alloc one more byte
|
||||
buf.base[buf.len++] = ']';
|
||||
}
|
||||
|
||||
@@ -256,8 +266,12 @@ wpi::uv::Buffer WebSocketConnection::AllocBuf() {
|
||||
}
|
||||
|
||||
void WebSocketConnection::ReleaseBufs(std::span<wpi::uv::Buffer> bufs) {
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
size_t numToPool = 0;
|
||||
#else
|
||||
size_t numToPool = (std::min)(bufs.size(), kMaxPoolSize - m_buf_pool.size());
|
||||
m_buf_pool.insert(m_buf_pool.end(), bufs.begin(), bufs.begin() + numToPool);
|
||||
#endif
|
||||
for (auto&& buf : bufs.subspan(numToPool)) {
|
||||
buf.Deallocate();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ class WebSocketConnection final
|
||||
WebSocketConnection(const WebSocketConnection&) = delete;
|
||||
WebSocketConnection& operator=(const WebSocketConnection&) = delete;
|
||||
|
||||
void Start();
|
||||
|
||||
unsigned int GetVersion() const final { return m_version; }
|
||||
|
||||
void SendPing(uint64_t time) final;
|
||||
|
||||
@@ -28,10 +28,14 @@ void UvStreamConnection3::Flush() {
|
||||
++m_sendsActive;
|
||||
m_stream.Write(m_buffers, [selfweak = weak_from_this()](auto bufs, auto) {
|
||||
if (auto self = selfweak.lock()) {
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
size_t numToPool = 0;
|
||||
#else
|
||||
size_t numToPool =
|
||||
(std::min)(bufs.size(), kMaxPoolSize - self->m_buf_pool.size());
|
||||
self->m_buf_pool.insert(self->m_buf_pool.end(), bufs.begin(),
|
||||
bufs.begin() + numToPool);
|
||||
#endif
|
||||
for (auto&& buf : bufs.subspan(numToPool)) {
|
||||
buf.Deallocate();
|
||||
}
|
||||
|
||||
@@ -264,12 +264,18 @@ Thread::~Thread() {
|
||||
void Thread::Main() {
|
||||
// based on free disk space, scan for "old" FRC_*.wpilog files and remove
|
||||
{
|
||||
uintmax_t freeSpace = fs::space(m_logDir).free;
|
||||
std::error_code ec;
|
||||
uintmax_t freeSpace;
|
||||
auto freeSpaceInfo = fs::space(m_logDir, ec);
|
||||
if (!ec) {
|
||||
freeSpace = freeSpaceInfo.available;
|
||||
} else {
|
||||
freeSpace = UINTMAX_MAX;
|
||||
}
|
||||
if (freeSpace < kFreeSpaceThreshold) {
|
||||
// Delete oldest FRC_*.wpilog files (ignore FRC_TBD_*.wpilog as we just
|
||||
// created one)
|
||||
std::vector<fs::directory_entry> entries;
|
||||
std::error_code ec;
|
||||
for (auto&& entry : fs::directory_iterator{m_logDir, ec}) {
|
||||
auto stem = entry.path().stem().string();
|
||||
if (wpi::starts_with(stem, "FRC_") &&
|
||||
@@ -462,6 +468,9 @@ static Instance& GetInstance(std::string_view dir = "",
|
||||
std::string_view filename = "",
|
||||
double period = 0.25) {
|
||||
static Instance instance(dir, filename, period);
|
||||
if (!instance.owner) {
|
||||
instance.owner.Start(MakeLogDir(dir), filename, period);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -470,6 +479,12 @@ void DataLogManager::Start(std::string_view dir, std::string_view filename,
|
||||
GetInstance(dir, filename, period);
|
||||
}
|
||||
|
||||
void DataLogManager::Stop() {
|
||||
auto& inst = GetInstance();
|
||||
inst.owner.GetThread()->m_log.Stop();
|
||||
inst.owner.Stop();
|
||||
}
|
||||
|
||||
void DataLogManager::Log(std::string_view message) {
|
||||
GetInstance().owner.GetThread()->m_messageLog.Append(message);
|
||||
fmt::print("{}\n", message);
|
||||
@@ -503,6 +518,10 @@ void DLM_Start(const char* dir, const char* filename, double period) {
|
||||
DataLogManager::Start(dir, filename, period);
|
||||
}
|
||||
|
||||
void DLM_Stop(void) {
|
||||
DataLogManager::Stop();
|
||||
}
|
||||
|
||||
void DLM_Log(const char* message) {
|
||||
DataLogManager::Log(message);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ class DataLogManager final {
|
||||
static void Start(std::string_view dir = "", std::string_view filename = "",
|
||||
double period = 0.25);
|
||||
|
||||
/**
|
||||
* Stop data log manager.
|
||||
*/
|
||||
static void Stop();
|
||||
|
||||
/**
|
||||
* Log a message to the "messages" entry. The message is also printed to
|
||||
* standard output (followed by a newline).
|
||||
@@ -110,6 +115,11 @@ struct WPI_DataLog;
|
||||
*/
|
||||
void DLM_Start(const char* dir, const char* filename, double period);
|
||||
|
||||
/**
|
||||
* Stop data log manager.
|
||||
*/
|
||||
void DLM_Stop(void);
|
||||
|
||||
/**
|
||||
* Log a message to the "messages" entry. The message is also printed to
|
||||
* standard output (followed by a newline).
|
||||
|
||||
@@ -4,6 +4,7 @@ DLM_Log
|
||||
DLM_LogNetworkTables
|
||||
DLM_SignalNewDSDataOccur
|
||||
DLM_Start
|
||||
DLM_Stop
|
||||
NT_AddListener
|
||||
NT_AddListenerMultiple
|
||||
NT_AddListenerSingle
|
||||
@@ -245,6 +246,7 @@ WPI_DataLog_Resume
|
||||
WPI_DataLog_SetFilename
|
||||
WPI_DataLog_SetMetadata
|
||||
WPI_DataLog_Start
|
||||
WPI_DataLog_Stop
|
||||
WPI_DestroyEvent
|
||||
WPI_DestroySemaphore
|
||||
WPI_DestroySignalObject
|
||||
|
||||
@@ -24,6 +24,20 @@ if (WITH_JAVA)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB_RECURSE ROMIVENDORDEP_SOURCES src/main/java/*.java)
|
||||
add_jar(romiVendordep_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/wpilibj/romi" ${ROMIVENDORDEP_SOURCES}
|
||||
OUTPUT_NAME romiVendordep-sources)
|
||||
|
||||
get_property(ROMIVENDORDEP_SRC_JAR_FILE TARGET romiVendordep_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${ROMIVENDORDEP_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET romiVendordep_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE romiVendordep_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(romiVendordep ${romiVendordep_native_src})
|
||||
set_target_properties(romiVendordep PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
@@ -16,7 +16,7 @@ nativeUtils {
|
||||
opencvYear = "frc2024"
|
||||
googleTestYear = "frc2024"
|
||||
niLibVersion = "2024.1.1"
|
||||
opencvVersion = "4.8.0-1"
|
||||
opencvVersion = "4.8.0-2"
|
||||
googleTestVersion = "1.14.0-1"
|
||||
}
|
||||
}
|
||||
|
||||
7
shared/cppJavaDesktopTestTask.gradle
Normal file
7
shared/cppJavaDesktopTestTask.gradle
Normal file
@@ -0,0 +1,7 @@
|
||||
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
|
||||
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
|
||||
|
||||
tasks.register('testDesktop') {
|
||||
dependsOn testDesktopJava
|
||||
dependsOn testDesktopCpp
|
||||
}
|
||||
@@ -77,7 +77,7 @@ def tagList = [
|
||||
"Digital Output",
|
||||
|
||||
/* --- HID --- */
|
||||
"XboxController", "PS4Controller", "Joystick",
|
||||
"XboxController", "PS4Controller", "PS5Controller", "Joystick",
|
||||
|
||||
/* --- Misc --- */
|
||||
/* (try to keep this section minimal) */
|
||||
|
||||
@@ -182,8 +182,7 @@ model {
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
|
||||
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
|
||||
apply from: "${rootDir}/shared/cppJavaDesktopTestTask.gradle"
|
||||
|
||||
tasks.withType(RunTestExecutable) {
|
||||
args "--gtest_output=xml:test_detail.xml"
|
||||
|
||||
@@ -327,8 +327,7 @@ model {
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
|
||||
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
|
||||
apply from: "${rootDir}/shared/cppJavaDesktopTestTask.gradle"
|
||||
|
||||
ext.getJniSpecClass = {
|
||||
return JniNativeLibrarySpec
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
def opencvVersion = '4.8.0-1'
|
||||
def opencvVersion = '4.8.0-2'
|
||||
|
||||
if (project.hasProperty('useCpp') && project.useCpp) {
|
||||
model {
|
||||
|
||||
@@ -146,7 +146,9 @@ void DSCommPacket::DecodeUDP(std::span<const uint8_t> packet) {
|
||||
m_lo = packet[1];
|
||||
// Comm Version is packet 2, ignore
|
||||
SetControl(packet[3], packet[4]);
|
||||
SetAlliance(packet[5]);
|
||||
// DS sends values 0, 1, and 2 for Red, but kUnknown is 0, so the value needs
|
||||
// to be offset by one
|
||||
SetAlliance(packet[5] + 1);
|
||||
|
||||
// Return if packet finished
|
||||
if (packet.size() == 6) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <string_view>
|
||||
|
||||
#include <DSCommPacket.h>
|
||||
@@ -124,33 +125,45 @@ static void SetupUdp(wpi::uv::Loop& loop) {
|
||||
});
|
||||
});
|
||||
simLoopTimer->Start(Timer::Time{100}, Timer::Time{100});
|
||||
// DS Timeout
|
||||
int timeoutMs = 100;
|
||||
if (auto envTimeout = std::getenv("DS_TIMEOUT_MS")) {
|
||||
try {
|
||||
timeoutMs = std::stoi(envTimeout);
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error parsing DS_TIMEOUT_MS: {}\n", e.what());
|
||||
}
|
||||
}
|
||||
auto autoDisableTimer = Timer::Create(loop);
|
||||
autoDisableTimer->timeout.connect([] { HALSIM_SetDriverStationEnabled(0); });
|
||||
|
||||
// UDP Receive then send
|
||||
udp->received.connect([udpLocal = udp.get()](Buffer& buf, size_t len,
|
||||
const sockaddr& recSock,
|
||||
unsigned int port) {
|
||||
auto ds = udpLocal->GetLoop()->GetData<halsim::DSCommPacket>();
|
||||
ds->DecodeUDP({reinterpret_cast<uint8_t*>(buf.base), len});
|
||||
udp->received.connect(
|
||||
[udpLocal = udp.get(), autoDisableTimer, timeoutMs](
|
||||
Buffer& buf, size_t len, const sockaddr& recSock, unsigned int port) {
|
||||
autoDisableTimer->Start(Timer::Time(timeoutMs));
|
||||
auto ds = udpLocal->GetLoop()->GetData<halsim::DSCommPacket>();
|
||||
ds->DecodeUDP({reinterpret_cast<uint8_t*>(buf.base), len});
|
||||
|
||||
struct sockaddr_in outAddr;
|
||||
std::memcpy(&outAddr, &recSock, sizeof(sockaddr_in));
|
||||
outAddr.sin_family = PF_INET;
|
||||
outAddr.sin_port = htons(1150);
|
||||
struct sockaddr_in outAddr;
|
||||
std::memcpy(&outAddr, &recSock, sizeof(sockaddr_in));
|
||||
outAddr.sin_family = PF_INET;
|
||||
outAddr.sin_port = htons(1150);
|
||||
|
||||
wpi::SmallVector<wpi::uv::Buffer, 4> sendBufs;
|
||||
wpi::raw_uv_ostream stream{sendBufs,
|
||||
[] { return GetBufferPool().Allocate(); }};
|
||||
ds->SetupSendBuffer(stream);
|
||||
wpi::SmallVector<wpi::uv::Buffer, 4> sendBufs;
|
||||
wpi::raw_uv_ostream stream{sendBufs,
|
||||
[] { return GetBufferPool().Allocate(); }};
|
||||
ds->SetupSendBuffer(stream);
|
||||
|
||||
udpLocal->Send(outAddr, sendBufs, [](auto bufs, Error err) {
|
||||
GetBufferPool().Release(bufs);
|
||||
if (err) {
|
||||
fmt::print(stderr, "{}\n", err.str());
|
||||
std::fflush(stderr);
|
||||
}
|
||||
});
|
||||
ds->SendUDPToHALSim();
|
||||
});
|
||||
udpLocal->Send(outAddr, sendBufs, [](auto bufs, Error err) {
|
||||
GetBufferPool().Release(bufs);
|
||||
if (err) {
|
||||
fmt::print(stderr, "{}\n", err.str());
|
||||
std::fflush(stderr);
|
||||
}
|
||||
});
|
||||
ds->SendUDPToHALSim();
|
||||
});
|
||||
|
||||
udp->StartRecv();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class HALSimWSClientConnection;
|
||||
|
||||
class HALSimWS : public std::enable_shared_from_this<HALSimWS> {
|
||||
public:
|
||||
using LoopFunc = std::function<void(void)>;
|
||||
using LoopFunc = std::function<void()>;
|
||||
using UvExecFunc = wpi::uv::Async<LoopFunc>;
|
||||
|
||||
HALSimWS(wpi::uv::Loop& loop, ProviderContainer& providers,
|
||||
|
||||
@@ -87,7 +87,7 @@ class HALSimWSProviderSimDevice : public HALSimWSBaseProvider {
|
||||
|
||||
class HALSimWSProviderSimDevices {
|
||||
public:
|
||||
using LoopFn = std::function<void(void)>;
|
||||
using LoopFn = std::function<void()>;
|
||||
using UvExecFn = wpi::uv::AsyncFunction<void(LoopFn)>;
|
||||
|
||||
explicit HALSimWSProviderSimDevices(ProviderContainer& providers)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace wpilibws {
|
||||
|
||||
class HALSimWeb : public std::enable_shared_from_this<HALSimWeb> {
|
||||
public:
|
||||
using LoopFunc = std::function<void(void)>;
|
||||
using LoopFunc = std::function<void()>;
|
||||
using UvExecFunc = wpi::uv::Async<LoopFunc>;
|
||||
|
||||
HALSimWeb(wpi::uv::Loop& loop, ProviderContainer& providers,
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace wpilibws {
|
||||
class WebServerClientTest {
|
||||
public:
|
||||
using BufferPool = wpi::uv::SimpleBufferPool<4>;
|
||||
using LoopFunc = std::function<void(void)>;
|
||||
using LoopFunc = std::function<void()>;
|
||||
using UvExecFunc = wpi::uv::AsyncFunction<void(LoopFunc)>;
|
||||
|
||||
explicit WebServerClientTest(wpi::uv::Loop& loop) : m_loop(loop) {}
|
||||
|
||||
@@ -35,7 +35,7 @@ __declspec(dllexport)
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::puts("HALSim XRP Extention Initialized");
|
||||
std::puts("HALSim XRP Extension Initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace wpilibxrp {
|
||||
class HALSimXRP : public wpilibws::HALSimBaseWebSocketConnection,
|
||||
public std::enable_shared_from_this<HALSimXRP> {
|
||||
public:
|
||||
using LoopFunc = std::function<void(void)>;
|
||||
using LoopFunc = std::function<void()>;
|
||||
using UvExecFunc = wpi::uv::Async<LoopFunc>;
|
||||
|
||||
HALSimXRP(wpi::uv::Loop& loop, wpilibws::ProviderContainer& providers,
|
||||
|
||||
@@ -6,10 +6,10 @@ suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
<suppress files=".*test.*" checks="MissingJavadocMethod" />
|
||||
<suppress files=".*wpilibjIntegrationTests.*"
|
||||
checks="MissingJavadocMethod" />
|
||||
<suppress files="wpimath/*"
|
||||
<suppress files="wpimath.*"
|
||||
checks="(LocalVariableName|MemberName|MethodName|MethodTypeParameterName|ParameterName)" />
|
||||
<suppress files=".*JNI.*"
|
||||
checks="(EmptyLineSeparator|LineLength|MissingJavadocMethod|ParameterName)" />
|
||||
<suppress files=".*/quickbuf/.*"
|
||||
<suppress files=".*quickbuf.*"
|
||||
checks="(CustomImportOrder|EmptyLineSeparator|LineLength|JavadocParagraph|MissingJavadocMethod|OverloadMethodsDeclarationOrder|SummaryJavadoc|UnnecessaryParentheses|OperatorWrap|JavadocMethod|JavadocTagContinuationIndentation)" />
|
||||
</suppressions>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
namespace sysid {
|
||||
/**
|
||||
* This class is reponsible for collecting data from the robot and storing it
|
||||
* This class is responsible for collecting data from the robot and storing it
|
||||
* inside a JSON.
|
||||
*/
|
||||
class TelemetryManager {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Hall <bhallctre@gmail.com>
|
||||
Date: Mon, 23 Oct 2023 21:36:40 -0400
|
||||
Subject: [PATCH 32/32] Fix compilation of MathExtras.h on Windows with /sdl
|
||||
|
||||
See https://github.com/llvm/llvm-project/pull/68978
|
||||
---
|
||||
llvm/include/llvm/Support/MathExtras.h | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
|
||||
index 5f034b694989d8ef24e0b249abd12a5c20146b97..03db6e4d92cb3b62ac3d8b3cbd97783817c6326b 100644
|
||||
--- a/llvm/include/llvm/Support/MathExtras.h
|
||||
+++ b/llvm/include/llvm/Support/MathExtras.h
|
||||
@@ -356,7 +356,10 @@ inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
|
||||
inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
|
||||
assert(Align != 0 && (Align & (Align - 1)) == 0 &&
|
||||
"Align must be a power of 2");
|
||||
- return (Value + Align - 1) & -Align;
|
||||
+ // Replace unary minus to avoid compilation error on Windows:
|
||||
+ // "unary minus operator applied to unsigned type, result still unsigned"
|
||||
+ uint64_t negAlign = (~Align) + 1;
|
||||
+ return (Value + Align - 1) & negAlign;
|
||||
}
|
||||
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal integer
|
||||
@@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Johnson <johnson.peter@gmail.com>
|
||||
Date: Sun, 29 Oct 2023 23:00:08 -0700
|
||||
Subject: [PATCH 33/33] raw_ostream: Add SetNumBytesInBuffer
|
||||
|
||||
---
|
||||
llvm/include/llvm/Support/raw_ostream.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
|
||||
index 9a9a1f688313a5784a58a70f2cb4cc0d6ec70e79..39f98e4e7696e28587779e90a03995463767b02d 100644
|
||||
--- a/llvm/include/llvm/Support/raw_ostream.h
|
||||
+++ b/llvm/include/llvm/Support/raw_ostream.h
|
||||
@@ -356,6 +356,11 @@ protected:
|
||||
SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
|
||||
}
|
||||
|
||||
+ /// Force-set the number of bytes in the raw_ostream buffer.
|
||||
+ void SetNumBytesInBuffer(size_t Size) {
|
||||
+ OutBufCur = OutBufStart + Size;
|
||||
+ }
|
||||
+
|
||||
/// Return an efficient buffer size for the underlying output mechanism.
|
||||
virtual size_t preferred_buffer_size() const;
|
||||
|
||||
@@ -171,7 +171,7 @@ def overwrite_tests(wpiutil_root, llvm_root):
|
||||
|
||||
|
||||
def main():
|
||||
upstream_root = clone_repo("https://github.com/llvm/llvm-project", "llvmorg-17.0.3")
|
||||
upstream_root = clone_repo("https://github.com/llvm/llvm-project", "llvmorg-17.0.4")
|
||||
wpilib_root = get_repo_root()
|
||||
wpiutil = os.path.join(wpilib_root, "wpiutil")
|
||||
|
||||
@@ -209,6 +209,8 @@ def main():
|
||||
"0029-Use-C-20-bit-header.patch",
|
||||
"0030-Remove-DenseMap-GTest-printer-test.patch",
|
||||
"0031-Replace-deprecated-std-aligned_storage_t.patch",
|
||||
"0032-Fix-compilation-of-MathExtras.h-on-Windows-with-sdl.patch",
|
||||
"0033-raw_ostream-Add-SetNumBytesInBuffer.patch",
|
||||
]:
|
||||
git_am(
|
||||
os.path.join(wpilib_root, "upstream_utils/llvm_patches", f),
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"opencv",
|
||||
"eigen3",
|
||||
"fmt",
|
||||
"libuv"
|
||||
]
|
||||
"libuv",
|
||||
"protobuf"
|
||||
],
|
||||
"builtin-baseline": "78b61582c9e093fda56a01ebb654be15a0033897"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ file(GLOB wpigui_windows_src src/main/native/directx11/*.cpp)
|
||||
file(GLOB wpigui_mac_src src/main/native/metal/*.mm)
|
||||
file(GLOB wpigui_unix_src src/main/native/opengl3/*.cpp)
|
||||
|
||||
add_library(wpigui STATIC ${wpigui_src})
|
||||
if (MSVC)
|
||||
add_library(wpigui STATIC ${wpigui_src})
|
||||
else()
|
||||
add_library(wpigui ${wpigui_src})
|
||||
endif()
|
||||
set_target_properties(wpigui PROPERTIES DEBUG_POSTFIX "d")
|
||||
set_property(TARGET wpigui PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
@@ -24,6 +24,22 @@ if (WITH_JAVA)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB WPILIBNEWCOMMANDS_SOURCES src/main/java/edu/wpi/first/wpilibj2/command/*.java)
|
||||
file(GLOB WPILIBNEWCOMMANDS_BUTTON_SOURCES src/main/java/edu/wpi/first/wpilibj2/command/button*.java)
|
||||
add_jar(wpilibNewCommands_src_jar
|
||||
RESOURCES NAMESPACE "edu/wpi/first/wpilibj2/command" ${WPILIBNEWCOMMANDS_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/wpilibj2/command/button" ${WPILIBNEWCOMMANDS_BUTTON_SOURCES}
|
||||
OUTPUT_NAME wpilibNewCommands-sources)
|
||||
|
||||
get_property(WPILIBNEWCOMMANDS_SRC_JAR_FILE TARGET wpilibNewCommands_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${WPILIBNEWCOMMANDS_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET wpilibNewCommands_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE wpilibNewCommands_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(wpilibNewCommands ${wpilibNewCommands_native_src})
|
||||
set_target_properties(wpilibNewCommands PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
@@ -423,6 +423,18 @@ public abstract class Command implements Sendable {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt or end, following the command's
|
||||
* inherent {@link #end(boolean)} method. The provided lambda will run identically in both
|
||||
* interrupt and end cases.
|
||||
*
|
||||
* @param end a lambda to run when the command ends, whether or not it was interrupted.
|
||||
* @return the decorated command
|
||||
*/
|
||||
public WrapperCommand finallyDo(Runnable end) {
|
||||
return finallyDo(interrupted -> end.run());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt, following the command's inherent
|
||||
* {@link #end(boolean)} method.
|
||||
|
||||
@@ -7,6 +7,7 @@ package edu.wpi.first.wpilibj2.command;
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -143,13 +144,26 @@ public final class Commands {
|
||||
/**
|
||||
* Runs one of several commands, based on the selector function.
|
||||
*
|
||||
* @param <K> The type of key used to select the command
|
||||
* @param selector the selector function
|
||||
* @param commands map of commands to select from
|
||||
* @return the command
|
||||
* @see SelectCommand
|
||||
*/
|
||||
public static Command select(Map<Object, Command> commands, Supplier<Object> selector) {
|
||||
return new SelectCommand(commands, selector);
|
||||
public static <K> Command select(Map<K, Command> commands, Supplier<? extends K> selector) {
|
||||
return new SelectCommand<>(commands, selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command supplied by the supplier.
|
||||
*
|
||||
* @param supplier the command supplier
|
||||
* @param requirements the set of requirements for this command
|
||||
* @return the command
|
||||
* @see DeferredCommand
|
||||
*/
|
||||
public static Command defer(Supplier<Command> supplier, Set<Subsystem> requirements) {
|
||||
return new DeferredCommand(supplier, requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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.wpilibj2.command;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Defers Command construction to runtime. Runs the command returned by the supplier when this
|
||||
* command is initialized, and ends when it ends. Useful for performing runtime tasks before
|
||||
* creating a new command. If this command is interrupted, it will cancel the command.
|
||||
*
|
||||
* <p>Note that the supplier <i>must</i> create a new Command each call. For selecting one of a
|
||||
* preallocated set of commands, use {@link SelectCommand}.
|
||||
*
|
||||
* <p>This class is provided by the NewCommands VendorDep
|
||||
*/
|
||||
public class DeferredCommand extends Command {
|
||||
private final Command m_nullCommand =
|
||||
new PrintCommand("[DeferredCommand] Supplied command was null!");
|
||||
|
||||
private final Supplier<Command> m_supplier;
|
||||
private Command m_command = m_nullCommand;
|
||||
|
||||
/**
|
||||
* Creates a new DeferredCommand that runs the supplied command when initialized, and ends when it
|
||||
* ends. Useful for lazily creating commands at runtime. The {@link Supplier} will be called each
|
||||
* time this command is initialized. The Supplier <i>must</i> create a new Command each call.
|
||||
*
|
||||
* @param supplier The command supplier
|
||||
* @param requirements The command requirements. This is a {@link Set} to prevent accidental
|
||||
* omission of command requirements. Use {@link Set#of()} to easily construct a requirement
|
||||
* set.
|
||||
*/
|
||||
public DeferredCommand(Supplier<Command> supplier, Set<Subsystem> requirements) {
|
||||
m_supplier = requireNonNullParam(supplier, "supplier", "DeferredCommand");
|
||||
addRequirements(requirements.toArray(new Subsystem[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
var cmd = m_supplier.get();
|
||||
if (cmd != null) {
|
||||
m_command = cmd;
|
||||
CommandScheduler.getInstance().registerComposedCommands(m_command);
|
||||
}
|
||||
m_command.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
m_command.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return m_command.isFinished();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
m_command.end(interrupted);
|
||||
m_command = m_nullCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
super.initSendable(builder);
|
||||
builder.addStringProperty(
|
||||
"deferred", () -> m_command == m_nullCommand ? "null" : m_command.getName(), null);
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,12 @@ import java.util.function.Supplier;
|
||||
* subsystems its components require.
|
||||
*
|
||||
* <p>This class is provided by the NewCommands VendorDep
|
||||
*
|
||||
* @param <K> The type of key used to select the command
|
||||
*/
|
||||
public class SelectCommand extends Command {
|
||||
private final Map<Object, Command> m_commands;
|
||||
private final Supplier<Object> m_selector;
|
||||
public class SelectCommand<K> extends Command {
|
||||
private final Map<K, Command> m_commands;
|
||||
private final Supplier<? extends K> m_selector;
|
||||
private Command m_selectedCommand;
|
||||
private boolean m_runsWhenDisabled = true;
|
||||
private InterruptionBehavior m_interruptBehavior = InterruptionBehavior.kCancelIncoming;
|
||||
@@ -36,7 +38,7 @@ public class SelectCommand extends Command {
|
||||
* @param commands the map of commands to choose from
|
||||
* @param selector the selector to determine which command to run
|
||||
*/
|
||||
public SelectCommand(Map<Object, Command> commands, Supplier<Object> selector) {
|
||||
public SelectCommand(Map<K, Command> commands, Supplier<? extends K> selector) {
|
||||
m_commands = requireNonNullParam(commands, "commands", "SelectCommand");
|
||||
m_selector = requireNonNullParam(selector, "selector", "SelectCommand");
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
package edu.wpi.first.wpilibj2.command;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A robot subsystem. Subsystems are the basic unit of robot organization in the Command-based
|
||||
* framework; they encapsulate low-level hardware objects (motor controllers, sensors, etc.) and
|
||||
@@ -133,4 +136,16 @@ public interface Subsystem {
|
||||
default Command runEnd(Runnable run, Runnable end) {
|
||||
return Commands.runEnd(run, end, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link DeferredCommand} with the provided supplier. This subsystem is added as a
|
||||
* requirement.
|
||||
*
|
||||
* @param supplier the command supplier.
|
||||
* @return the command.
|
||||
* @see DeferredCommand
|
||||
*/
|
||||
default Command defer(Supplier<Command> supplier) {
|
||||
return Commands.defer(supplier, Set.of(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
// 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.wpilibj2.command.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.PS5Controller;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import edu.wpi.first.wpilibj2.command.CommandScheduler;
|
||||
|
||||
/**
|
||||
* A version of {@link PS5Controller} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see PS5Controller
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class CommandPS5Controller extends CommandGenericHID {
|
||||
private final PS5Controller m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a device.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the device is plugged into.
|
||||
*/
|
||||
public CommandPS5Controller(int port) {
|
||||
super(port);
|
||||
m_hid = new PS5Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public PS5Controller getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L2 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the L2 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger L2() {
|
||||
return L2(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L2 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger L2(EventLoop loop) {
|
||||
return m_hid.L2(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R2 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the R2 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger R2() {
|
||||
return R2(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R2 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger R2(EventLoop loop) {
|
||||
return m_hid.R2(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L1 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the L1 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger L1() {
|
||||
return L1(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L1 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger L1(EventLoop loop) {
|
||||
return m_hid.L1(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R1 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the R1 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger R1() {
|
||||
return R1(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R1 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger R1(EventLoop loop) {
|
||||
return m_hid.R1(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L3 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the L3 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger L3() {
|
||||
return L3(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L3 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger L3(EventLoop loop) {
|
||||
return m_hid.L3(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R3 button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the R3 button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger R3() {
|
||||
return R3(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R3 button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger R3(EventLoop loop) {
|
||||
return m_hid.R3(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the square button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the square button's digital signal attached to the
|
||||
* {@link CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger square() {
|
||||
return square(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the square button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the square button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger square(EventLoop loop) {
|
||||
return m_hid.square(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the cross button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the cross button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger cross() {
|
||||
return cross(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the cross button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the cross button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger cross(EventLoop loop) {
|
||||
return m_hid.cross(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the triangle button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the triangle button's digital signal attached to the
|
||||
* {@link CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger triangle() {
|
||||
return triangle(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the triangle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the triangle button's digital signal attached to the
|
||||
* given loop.
|
||||
*/
|
||||
public Trigger triangle(EventLoop loop) {
|
||||
return m_hid.triangle(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the circle button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the circle button's digital signal attached to the
|
||||
* {@link CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger circle() {
|
||||
return circle(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the circle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the circle button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger circle(EventLoop loop) {
|
||||
return m_hid.circle(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the create button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the create button's digital signal attached to the
|
||||
* {@link CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger create() {
|
||||
return create(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the create button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the create button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger create(EventLoop loop) {
|
||||
return m_hid.create(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the PS button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the PS button's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger PS() {
|
||||
return PS(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the PS button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the PS button's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger PS(EventLoop loop) {
|
||||
return m_hid.PS(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the options button's digital signal.
|
||||
*
|
||||
* @return an event instance representing the options button's digital signal attached to the
|
||||
* {@link CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger options() {
|
||||
return options(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the options button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the options button's digital signal attached to the
|
||||
* given loop.
|
||||
*/
|
||||
public Trigger options(EventLoop loop) {
|
||||
return m_hid.options(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the touchpad's digital signal.
|
||||
*
|
||||
* @return an event instance representing the touchpad's digital signal attached to the {@link
|
||||
* CommandScheduler#getDefaultButtonLoop() default scheduler button loop}.
|
||||
*/
|
||||
public Trigger touchpad() {
|
||||
return touchpad(CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the touchpad's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the touchpad's digital signal attached to the given
|
||||
* loop.
|
||||
*/
|
||||
public Trigger touchpad(EventLoop loop) {
|
||||
return m_hid.touchpad(loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getLeftX() {
|
||||
return m_hid.getLeftX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getRightX() {
|
||||
return m_hid.getRightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getLeftY() {
|
||||
return m_hid.getLeftY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getRightY() {
|
||||
return m_hid.getRightY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the L2 axis value of the controller. Note that this axis is bound to the range of [0, 1] as
|
||||
* opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getL2Axis() {
|
||||
return m_hid.getL2Axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the R2 axis value of the controller. Note that this axis is bound to the range of [0, 1] as
|
||||
* opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
public double getR2Axis() {
|
||||
return m_hid.getR2Axis();
|
||||
}
|
||||
}
|
||||
@@ -261,13 +261,13 @@ public class CommandXboxController extends CommandGenericHID {
|
||||
* Constructs a Trigger instance around the axis value of the left trigger. The returned trigger
|
||||
* will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param loop the event loop instance to attach the Trigger to.
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @param loop the event loop instance to attach the Trigger to.
|
||||
* @return a Trigger instance that is true when the left trigger's axis exceeds the provided
|
||||
* threshold, attached to the given event loop
|
||||
*/
|
||||
public Trigger leftTrigger(EventLoop loop, double threshold) {
|
||||
public Trigger leftTrigger(double threshold, EventLoop loop) {
|
||||
return m_hid.leftTrigger(threshold, loop).castTo(Trigger::new);
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ public class CommandXboxController extends CommandGenericHID {
|
||||
* button loop}.
|
||||
*/
|
||||
public Trigger leftTrigger(double threshold) {
|
||||
return leftTrigger(CommandScheduler.getInstance().getDefaultButtonLoop(), threshold);
|
||||
return leftTrigger(threshold, CommandScheduler.getInstance().getDefaultButtonLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,7 +123,11 @@ CommandPtr Command::FinallyDo(std::function<void(bool)> end) && {
|
||||
return std::move(*this).ToPtr().FinallyDo(std::move(end));
|
||||
}
|
||||
|
||||
CommandPtr Command::HandleInterrupt(std::function<void(void)> handler) && {
|
||||
CommandPtr Command::FinallyDo(std::function<void()> end) && {
|
||||
return std::move(*this).ToPtr().FinallyDo(std::move(end));
|
||||
}
|
||||
|
||||
CommandPtr Command::HandleInterrupt(std::function<void()> handler) && {
|
||||
return std::move(*this).ToPtr().HandleInterrupt(std::move(handler));
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,13 @@ CommandPtr CommandPtr::FinallyDo(std::function<void(bool)> end) && {
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
CommandPtr CommandPtr::HandleInterrupt(std::function<void(void)> handler) && {
|
||||
CommandPtr CommandPtr::FinallyDo(std::function<void()> end) && {
|
||||
AssertValid();
|
||||
return std::move(*this).FinallyDo(
|
||||
[endHandler = std::move(end)](bool interrupted) { endHandler(); });
|
||||
}
|
||||
|
||||
CommandPtr CommandPtr::HandleInterrupt(std::function<void()> handler) && {
|
||||
AssertValid();
|
||||
return std::move(*this).FinallyDo(
|
||||
[handler = std::move(handler)](bool interrupted) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "frc2/command/Commands.h"
|
||||
|
||||
#include "frc2/command/ConditionalCommand.h"
|
||||
#include "frc2/command/DeferredCommand.h"
|
||||
#include "frc2/command/FunctionalCommand.h"
|
||||
#include "frc2/command/InstantCommand.h"
|
||||
#include "frc2/command/ParallelCommandGroup.h"
|
||||
@@ -82,6 +83,11 @@ CommandPtr cmd::Either(CommandPtr&& onTrue, CommandPtr&& onFalse,
|
||||
.ToPtr();
|
||||
}
|
||||
|
||||
CommandPtr cmd::Defer(wpi::unique_function<CommandPtr()> supplier,
|
||||
Requirements requirements) {
|
||||
return DeferredCommand(std::move(supplier), requirements).ToPtr();
|
||||
}
|
||||
|
||||
CommandPtr cmd::Sequence(std::vector<CommandPtr>&& commands) {
|
||||
return SequentialCommandGroup(CommandPtr::UnwrapVector(std::move(commands)))
|
||||
.ToPtr();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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 "frc2/command/DeferredCommand.h"
|
||||
|
||||
#include <wpi/sendable/SendableBuilder.h>
|
||||
|
||||
#include "frc2/command/Commands.h"
|
||||
|
||||
using namespace frc2;
|
||||
|
||||
DeferredCommand::DeferredCommand(wpi::unique_function<CommandPtr()> supplier,
|
||||
Requirements requirements)
|
||||
: m_supplier{std::move(supplier)} {
|
||||
AddRequirements(requirements);
|
||||
}
|
||||
|
||||
void DeferredCommand::Initialize() {
|
||||
m_command = m_supplier().Unwrap();
|
||||
CommandScheduler::GetInstance().RequireUngrouped(m_command.get());
|
||||
m_command->SetComposed(true);
|
||||
m_command->Initialize();
|
||||
}
|
||||
|
||||
void DeferredCommand::Execute() {
|
||||
m_command->Execute();
|
||||
}
|
||||
|
||||
void DeferredCommand::End(bool interrupted) {
|
||||
m_command->End(interrupted);
|
||||
m_command =
|
||||
cmd::Print("[DeferredCommand] Lifecycle function called out-of-order!")
|
||||
.WithName("none")
|
||||
.Unwrap();
|
||||
}
|
||||
|
||||
bool DeferredCommand::IsFinished() {
|
||||
return m_command->IsFinished();
|
||||
}
|
||||
|
||||
void DeferredCommand::InitSendable(wpi::SendableBuilder& builder) {
|
||||
Command::InitSendable(builder);
|
||||
builder.AddStringProperty(
|
||||
"deferred", [this] { return m_command->GetName(); }, nullptr);
|
||||
}
|
||||
@@ -54,3 +54,7 @@ CommandPtr Subsystem::RunEnd(std::function<void()> run,
|
||||
std::function<void()> end) {
|
||||
return cmd::RunEnd(std::move(run), std::move(end), {this});
|
||||
}
|
||||
|
||||
CommandPtr Subsystem::Defer(wpi::unique_function<CommandPtr()> supplier) {
|
||||
return cmd::Defer(std::move(supplier), {this});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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 "frc2/command/button/CommandPS5Controller.h"
|
||||
|
||||
using namespace frc2;
|
||||
|
||||
Trigger CommandPS5Controller::Button(int button, frc::EventLoop* loop) const {
|
||||
return GenericHID::Button(button, loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Square(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Square(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Cross(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Cross(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Circle(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Circle(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Triangle(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Triangle(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::L1(frc::EventLoop* loop) const {
|
||||
return PS5Controller::L1(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::R1(frc::EventLoop* loop) const {
|
||||
return PS5Controller::R1(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::L2(frc::EventLoop* loop) const {
|
||||
return PS5Controller::L2(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::R2(frc::EventLoop* loop) const {
|
||||
return PS5Controller::R2(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Options(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Options(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::L3(frc::EventLoop* loop) const {
|
||||
return PS5Controller::L3(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::R3(frc::EventLoop* loop) const {
|
||||
return PS5Controller::R3(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::PS(frc::EventLoop* loop) const {
|
||||
return PS5Controller::PS(loop).CastTo<Trigger>();
|
||||
}
|
||||
|
||||
Trigger CommandPS5Controller::Touchpad(frc::EventLoop* loop) const {
|
||||
return PS5Controller::Touchpad(loop).CastTo<Trigger>();
|
||||
}
|
||||
@@ -318,6 +318,18 @@ class Command : public wpi::Sendable, public wpi::SendableHelper<Command> {
|
||||
[[nodiscard]]
|
||||
CommandPtr FinallyDo(std::function<void(bool)> end) &&;
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt or end, following
|
||||
* the command's inherent Command::End(bool) method. The provided lambda will
|
||||
* run identically in both interrupt and end cases.
|
||||
*
|
||||
* @param end a lambda to run when the command ends, whether or not it was
|
||||
* interrupted.
|
||||
* @return the decorated command
|
||||
*/
|
||||
[[nodiscard]]
|
||||
CommandPtr FinallyDo(std::function<void()> end) &&;
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt, following the
|
||||
* command's inherent Command::End(bool) method.
|
||||
|
||||
@@ -223,6 +223,18 @@ class CommandPtr final {
|
||||
[[nodiscard]]
|
||||
CommandPtr FinallyDo(std::function<void(bool)> end) &&;
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt or end, following
|
||||
* the command's inherent Command::End(bool) method. The provided lambda will
|
||||
* run identically in both interrupt and end cases.
|
||||
*
|
||||
* @param end a lambda to run when the command ends, whether or not it was
|
||||
* interrupted.
|
||||
* @return the decorated command
|
||||
*/
|
||||
[[nodiscard]]
|
||||
CommandPtr FinallyDo(std::function<void()> end) &&;
|
||||
|
||||
/**
|
||||
* Decorates this command with a lambda to call on interrupt, following the
|
||||
* command's inherent Command::End(bool) method.
|
||||
|
||||
@@ -142,6 +142,16 @@ CommandPtr Select(std::function<Key()> selector,
|
||||
return SelectCommand(std::move(selector), std::move(vec)).ToPtr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command supplied by the supplier.
|
||||
*
|
||||
* @param supplier the command supplier
|
||||
* @param requirements the set of requirements for this command
|
||||
*/
|
||||
[[nodiscard]]
|
||||
CommandPtr Defer(wpi::unique_function<CommandPtr()> supplier,
|
||||
Requirements requirements);
|
||||
|
||||
/**
|
||||
* Constructs a command that schedules the command returned from the supplier
|
||||
* when initialized, and ends when it is no longer scheduled. The supplier is
|
||||
|
||||
@@ -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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include <wpi/FunctionExtras.h>
|
||||
|
||||
#include "frc2/command/Command.h"
|
||||
#include "frc2/command/CommandHelper.h"
|
||||
#include "frc2/command/PrintCommand.h"
|
||||
#include "frc2/command/Requirements.h"
|
||||
|
||||
namespace frc2 {
|
||||
/**
|
||||
* Defers Command construction to runtime. Runs the command returned by the
|
||||
* supplier when this command is initialized, and ends when it ends. Useful for
|
||||
* performing runtime tasks before creating a new command. If this command is
|
||||
* interrupted, it will cancel the command.
|
||||
*
|
||||
* Note that the supplier <i>must</i> create a new Command each call. For
|
||||
* selecting one of a preallocated set of commands, use SelectCommand.
|
||||
*
|
||||
* <p>This class is provided by the NewCommands VendorDep
|
||||
*/
|
||||
class DeferredCommand : public CommandHelper<Command, DeferredCommand> {
|
||||
public:
|
||||
/**
|
||||
* Creates a new DeferredCommand that runs the supplied command when
|
||||
* initialized, and ends when it ends. Useful for lazily
|
||||
* creating commands at runtime. The supplier will be called each time this
|
||||
* command is initialized. The supplier <i>must</i> create a new Command each
|
||||
* call.
|
||||
*
|
||||
* @param supplier The command supplier
|
||||
* @param requirements The command requirements.
|
||||
*
|
||||
*/
|
||||
DeferredCommand(wpi::unique_function<CommandPtr()> supplier,
|
||||
Requirements requirements);
|
||||
|
||||
DeferredCommand(DeferredCommand&& other) = default;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
void Execute() override;
|
||||
|
||||
void End(bool interrupted) override;
|
||||
|
||||
bool IsFinished() override;
|
||||
|
||||
void InitSendable(wpi::SendableBuilder& builder) override;
|
||||
|
||||
private:
|
||||
wpi::unique_function<CommandPtr()> m_supplier;
|
||||
std::unique_ptr<Command> m_command;
|
||||
};
|
||||
} // namespace frc2
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/FunctionExtras.h>
|
||||
|
||||
#include "frc2/command/CommandScheduler.h"
|
||||
|
||||
namespace frc2 {
|
||||
@@ -148,5 +150,15 @@ class Subsystem {
|
||||
*/
|
||||
[[nodiscard]]
|
||||
CommandPtr RunEnd(std::function<void()> run, std::function<void()> end);
|
||||
|
||||
/**
|
||||
* Constructs a DeferredCommand with the provided supplier. This subsystem is
|
||||
* added as a requirement.
|
||||
*
|
||||
* @param supplier the command supplier.
|
||||
* @return the command.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
CommandPtr Defer(wpi::unique_function<CommandPtr()> supplier);
|
||||
};
|
||||
} // namespace frc2
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// 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 <frc/PS5Controller.h>
|
||||
|
||||
#include "Trigger.h"
|
||||
#include "frc2/command/CommandScheduler.h"
|
||||
|
||||
namespace frc2 {
|
||||
/**
|
||||
* A version of {@link PS5Controller} with {@link Trigger} factories for
|
||||
* command-based.
|
||||
*
|
||||
* @see PS5Controller
|
||||
*/
|
||||
class CommandPS5Controller : public frc::PS5Controller {
|
||||
public:
|
||||
using PS5Controller::PS5Controller;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around this button's digital signal.
|
||||
*
|
||||
* @param button the button index
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
Trigger Button(int button,
|
||||
frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the square button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the square button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Square(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the cross button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the cross button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Cross(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the circle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the circle button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Circle(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the triangle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the triangle button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Triangle(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the L1 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger L1(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the R1 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger R1(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the L2 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger L2(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the R2 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger R2(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the options button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the options button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Options(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the L3 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger L3(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the R3 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger R3(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the PS button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the PS button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger PS(frc::EventLoop* loop =
|
||||
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the touchpad's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to. Defaults to the
|
||||
* CommandScheduler's default loop.
|
||||
* @return an event instance representing the touchpad's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
Trigger Touchpad(frc::EventLoop* loop = CommandScheduler::GetInstance()
|
||||
.GetDefaultButtonLoop()) const;
|
||||
};
|
||||
} // namespace frc2
|
||||
@@ -0,0 +1,85 @@
|
||||
// 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.wpilibj2.command;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.only;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class DeferredCommandTest extends CommandTestBase {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void deferredFunctionsTest(boolean interrupted) {
|
||||
MockCommandHolder innerCommand = new MockCommandHolder(false);
|
||||
DeferredCommand command = new DeferredCommand(innerCommand::getMock, Set.of());
|
||||
|
||||
command.initialize();
|
||||
verify(innerCommand.getMock()).initialize();
|
||||
|
||||
command.execute();
|
||||
verify(innerCommand.getMock()).execute();
|
||||
|
||||
assertFalse(command.isFinished());
|
||||
verify(innerCommand.getMock()).isFinished();
|
||||
|
||||
innerCommand.setFinished(true);
|
||||
assertTrue(command.isFinished());
|
||||
verify(innerCommand.getMock(), times(2)).isFinished();
|
||||
|
||||
command.end(interrupted);
|
||||
verify(innerCommand.getMock()).end(interrupted);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void deferredSupplierOnlyCalledDuringInit() {
|
||||
try (CommandScheduler scheduler = new CommandScheduler()) {
|
||||
Supplier<Command> supplier = (Supplier<Command>) mock(Supplier.class);
|
||||
when(supplier.get()).thenReturn(Commands.none(), Commands.none());
|
||||
|
||||
DeferredCommand command = new DeferredCommand(supplier, Set.of());
|
||||
verify(supplier, never()).get();
|
||||
|
||||
scheduler.schedule(command);
|
||||
verify(supplier, only()).get();
|
||||
scheduler.run();
|
||||
|
||||
scheduler.schedule(command);
|
||||
verify(supplier, times(2)).get();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredRequirementsTest() {
|
||||
Subsystem subsystem = new Subsystem() {};
|
||||
DeferredCommand command = new DeferredCommand(Commands::none, Set.of(subsystem));
|
||||
|
||||
assertTrue(command.getRequirements().contains(subsystem));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredNullCommandTest() {
|
||||
DeferredCommand command = new DeferredCommand(() -> null, Set.of());
|
||||
assertDoesNotThrow(
|
||||
() -> {
|
||||
command.initialize();
|
||||
command.execute();
|
||||
command.isFinished();
|
||||
command.end(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -141,8 +141,8 @@ class RobotDisabledCommandTest extends CommandTestBase {
|
||||
MockCommandHolder command4Holder = new MockCommandHolder(false);
|
||||
Command command4 = command4Holder.getMock();
|
||||
|
||||
Command runWhenDisabled = new SelectCommand(Map.of(1, command1, 2, command2), () -> 1);
|
||||
Command dontRunWhenDisabled = new SelectCommand(Map.of(1, command3, 2, command4), () -> 1);
|
||||
Command runWhenDisabled = new SelectCommand<>(Map.of(1, command1, 2, command2), () -> 1);
|
||||
Command dontRunWhenDisabled = new SelectCommand<>(Map.of(1, command3, 2, command4), () -> 1);
|
||||
|
||||
try (CommandScheduler scheduler = new CommandScheduler()) {
|
||||
scheduler.schedule(runWhenDisabled, dontRunWhenDisabled);
|
||||
|
||||
@@ -13,7 +13,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SelectCommandTest extends CommandTestBase implements MultiCompositionTestBase<SelectCommand> {
|
||||
class SelectCommandTest extends CommandTestBase
|
||||
implements MultiCompositionTestBase<SelectCommand<Integer>> {
|
||||
@Test
|
||||
void selectCommandTest() {
|
||||
try (CommandScheduler scheduler = new CommandScheduler()) {
|
||||
@@ -25,8 +26,8 @@ class SelectCommandTest extends CommandTestBase implements MultiCompositionTestB
|
||||
MockCommandHolder command3Holder = new MockCommandHolder(true);
|
||||
Command command3 = command3Holder.getMock();
|
||||
|
||||
SelectCommand selectCommand =
|
||||
new SelectCommand(
|
||||
SelectCommand<String> selectCommand =
|
||||
new SelectCommand<>(
|
||||
Map.ofEntries(
|
||||
Map.entry("one", command1),
|
||||
Map.entry("two", command2),
|
||||
@@ -61,8 +62,8 @@ class SelectCommandTest extends CommandTestBase implements MultiCompositionTestB
|
||||
MockCommandHolder command3Holder = new MockCommandHolder(true);
|
||||
Command command3 = command3Holder.getMock();
|
||||
|
||||
SelectCommand selectCommand =
|
||||
new SelectCommand(
|
||||
SelectCommand<String> selectCommand =
|
||||
new SelectCommand<>(
|
||||
Map.ofEntries(
|
||||
Map.entry("one", command1),
|
||||
Map.entry("two", command2),
|
||||
@@ -88,8 +89,8 @@ class SelectCommandTest extends CommandTestBase implements MultiCompositionTestB
|
||||
MockCommandHolder command3Holder = new MockCommandHolder(true, system3, system4);
|
||||
Command command3 = command3Holder.getMock();
|
||||
|
||||
SelectCommand selectCommand =
|
||||
new SelectCommand(
|
||||
SelectCommand<String> selectCommand =
|
||||
new SelectCommand<>(
|
||||
Map.ofEntries(
|
||||
Map.entry("one", command1),
|
||||
Map.entry("two", command2),
|
||||
@@ -108,11 +109,11 @@ class SelectCommandTest extends CommandTestBase implements MultiCompositionTestB
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectCommand compose(Command... members) {
|
||||
var map = new HashMap<Object, Command>();
|
||||
public SelectCommand<Integer> compose(Command... members) {
|
||||
var map = new HashMap<Integer, Command>();
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
map.put(i, members[i]);
|
||||
}
|
||||
return new SelectCommand(map, () -> 0);
|
||||
return new SelectCommand<>(map, () -> 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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 "CommandTestBase.h"
|
||||
#include "frc2/command/Commands.h"
|
||||
#include "frc2/command/DeferredCommand.h"
|
||||
#include "frc2/command/FunctionalCommand.h"
|
||||
|
||||
using namespace frc2;
|
||||
|
||||
class DeferredFunctionsTest : public CommandTestBaseWithParam<bool> {};
|
||||
|
||||
TEST_P(DeferredFunctionsTest, DeferredFunctions) {
|
||||
int initializeCount = 0;
|
||||
int executeCount = 0;
|
||||
int isFinishedCount = 0;
|
||||
int endCount = 0;
|
||||
bool finished = false;
|
||||
|
||||
DeferredCommand deferred{[&] {
|
||||
return FunctionalCommand{
|
||||
[&] { initializeCount++; },
|
||||
[&] { executeCount++; },
|
||||
[&](bool interrupted) {
|
||||
EXPECT_EQ(interrupted, GetParam());
|
||||
endCount++;
|
||||
},
|
||||
[&] {
|
||||
isFinishedCount++;
|
||||
return finished;
|
||||
}}
|
||||
.ToPtr();
|
||||
},
|
||||
{}};
|
||||
|
||||
deferred.Initialize();
|
||||
EXPECT_EQ(1, initializeCount);
|
||||
deferred.Execute();
|
||||
EXPECT_EQ(1, executeCount);
|
||||
EXPECT_FALSE(deferred.IsFinished());
|
||||
EXPECT_EQ(1, isFinishedCount);
|
||||
finished = true;
|
||||
EXPECT_TRUE(deferred.IsFinished());
|
||||
EXPECT_EQ(2, isFinishedCount);
|
||||
deferred.End(GetParam());
|
||||
EXPECT_EQ(1, endCount);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DeferredCommandTests, DeferredFunctionsTest,
|
||||
testing::Values(true, false));
|
||||
|
||||
TEST(DeferredCommandTest, DeferredSupplierOnlyCalledDuringInit) {
|
||||
int count = 0;
|
||||
DeferredCommand command{[&count] {
|
||||
count++;
|
||||
return cmd::None();
|
||||
},
|
||||
{}};
|
||||
|
||||
EXPECT_EQ(0, count);
|
||||
command.Initialize();
|
||||
EXPECT_EQ(1, count);
|
||||
command.Execute();
|
||||
command.IsFinished();
|
||||
command.End(false);
|
||||
EXPECT_EQ(1, count);
|
||||
}
|
||||
|
||||
TEST(DeferredCommandTest, DeferredRequirements) {
|
||||
TestSubsystem subsystem;
|
||||
DeferredCommand command{cmd::None, {&subsystem}};
|
||||
|
||||
EXPECT_TRUE(command.GetRequirements().contains(&subsystem));
|
||||
}
|
||||
@@ -111,12 +111,18 @@ Thread::~Thread() {
|
||||
void Thread::Main() {
|
||||
// based on free disk space, scan for "old" FRC_*.wpilog files and remove
|
||||
{
|
||||
uintmax_t freeSpace = fs::space(m_logDir).available;
|
||||
std::error_code ec;
|
||||
uintmax_t freeSpace;
|
||||
auto freeSpaceInfo = fs::space(m_logDir, ec);
|
||||
if (!ec) {
|
||||
freeSpace = freeSpaceInfo.available;
|
||||
} else {
|
||||
freeSpace = UINTMAX_MAX;
|
||||
}
|
||||
if (freeSpace < kFreeSpaceThreshold) {
|
||||
// Delete oldest FRC_*.wpilog files (ignore FRC_TBD_*.wpilog as we just
|
||||
// created one)
|
||||
std::vector<fs::directory_entry> entries;
|
||||
std::error_code ec;
|
||||
for (auto&& entry : fs::directory_iterator{m_logDir, ec}) {
|
||||
auto stem = entry.path().stem().string();
|
||||
if (wpi::starts_with(stem, "FRC_") &&
|
||||
@@ -308,6 +314,9 @@ static Instance& GetInstance(std::string_view dir = "",
|
||||
std::string_view filename = "",
|
||||
double period = 0.25) {
|
||||
static Instance instance(dir, filename, period);
|
||||
if (!instance.owner) {
|
||||
instance.owner.Start(MakeLogDir(dir), filename, period);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -316,6 +325,12 @@ void DataLogManager::Start(std::string_view dir, std::string_view filename,
|
||||
GetInstance(dir, filename, period);
|
||||
}
|
||||
|
||||
void DataLogManager::Stop() {
|
||||
auto& inst = GetInstance();
|
||||
inst.owner.GetThread()->m_log.Stop();
|
||||
inst.owner.Stop();
|
||||
}
|
||||
|
||||
void DataLogManager::Log(std::string_view message) {
|
||||
GetInstance().owner.GetThread()->m_messageLog.Append(message);
|
||||
fmt::print("{}\n", message);
|
||||
|
||||
@@ -129,6 +129,7 @@ double Joystick::GetDirectionRadians() const {
|
||||
double Joystick::GetDirectionDegrees() const {
|
||||
WPI_IGNORE_DEPRECATED
|
||||
return (180 / std::numbers::pi) * GetDirectionRadians();
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
}
|
||||
|
||||
units::radian_t Joystick::GetDirection() const {
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
using namespace frc;
|
||||
|
||||
PS4Controller::PS4Controller(int port) : GenericHID(port) {
|
||||
HAL_Report(HALUsageReporting::kResourceType_PS4Controller, port + 1);
|
||||
// re-enable when PS4Controller is added to Usage Reporting
|
||||
// HAL_Report(HALUsageReporting::kResourceType_PS4Controller, port + 1);
|
||||
}
|
||||
|
||||
double PS4Controller::GetLeftX() const {
|
||||
|
||||
263
wpilibc/src/main/native/cpp/PS5Controller.cpp
Normal file
263
wpilibc/src/main/native/cpp/PS5Controller.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// 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 "frc/PS5Controller.h"
|
||||
|
||||
#include <hal/FRCUsageReporting.h>
|
||||
|
||||
#include "frc/event/BooleanEvent.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
PS5Controller::PS5Controller(int port) : GenericHID(port) {
|
||||
// HAL_Report(HALUsageReporting::kResourceType_PS5Controller, port + 1);
|
||||
}
|
||||
|
||||
double PS5Controller::GetLeftX() const {
|
||||
return GetRawAxis(Axis::kLeftX);
|
||||
}
|
||||
|
||||
double PS5Controller::GetRightX() const {
|
||||
return GetRawAxis(Axis::kRightX);
|
||||
}
|
||||
|
||||
double PS5Controller::GetLeftY() const {
|
||||
return GetRawAxis(Axis::kLeftY);
|
||||
}
|
||||
|
||||
double PS5Controller::GetRightY() const {
|
||||
return GetRawAxis(Axis::kRightY);
|
||||
}
|
||||
|
||||
double PS5Controller::GetL2Axis() const {
|
||||
return GetRawAxis(Axis::kL2);
|
||||
}
|
||||
|
||||
double PS5Controller::GetR2Axis() const {
|
||||
return GetRawAxis(Axis::kR2);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetSquareButton() const {
|
||||
return GetRawButton(Button::kSquare);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetSquareButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kSquare);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetSquareButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kSquare);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Square(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetSquareButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCrossButton() const {
|
||||
return GetRawButton(Button::kCross);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCrossButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kCross);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCrossButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kCross);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Cross(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetCrossButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCircleButton() const {
|
||||
return GetRawButton(Button::kCircle);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCircleButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kCircle);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCircleButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kCircle);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Circle(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetCircleButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTriangleButton() const {
|
||||
return GetRawButton(Button::kTriangle);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTriangleButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kTriangle);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTriangleButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kTriangle);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Triangle(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetTriangleButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL1Button() const {
|
||||
return GetRawButton(Button::kL1);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL1ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kL1);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL1ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kL1);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::L1(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetL1Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR1Button() const {
|
||||
return GetRawButton(Button::kR1);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR1ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kR1);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR1ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kR1);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::R1(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetR1Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL2Button() const {
|
||||
return GetRawButton(Button::kL2);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL2ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kL2);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL2ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kL2);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::L2(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetL2Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR2Button() const {
|
||||
return GetRawButton(Button::kR2);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR2ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kR2);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR2ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kR2);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::R2(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetR2Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCreateButton() const {
|
||||
return GetRawButton(Button::kCreate);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCreateButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kCreate);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetCreateButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kCreate);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Create(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetCreateButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetOptionsButton() const {
|
||||
return GetRawButton(Button::kOptions);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetOptionsButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kOptions);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetOptionsButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kOptions);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Options(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetOptionsButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL3Button() const {
|
||||
return GetRawButton(Button::kL3);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL3ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kL3);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetL3ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kL3);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::L3(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetL3Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR3Button() const {
|
||||
return GetRawButton(Button::kR3);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR3ButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kR3);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetR3ButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kR3);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::R3(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetR3Button(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetPSButton() const {
|
||||
return GetRawButton(Button::kPS);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetPSButtonPressed() {
|
||||
return GetRawButtonPressed(Button::kPS);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetPSButtonReleased() {
|
||||
return GetRawButtonReleased(Button::kPS);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::PS(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetPSButton(); });
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTouchpad() const {
|
||||
return GetRawButton(Button::kTouchpad);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTouchpadPressed() {
|
||||
return GetRawButtonPressed(Button::kTouchpad);
|
||||
}
|
||||
|
||||
bool PS5Controller::GetTouchpadReleased() {
|
||||
return GetRawButtonReleased(Button::kTouchpad);
|
||||
}
|
||||
|
||||
BooleanEvent PS5Controller::Touchpad(EventLoop* loop) const {
|
||||
return BooleanEvent(loop, [this]() { return this->GetTouchpad(); });
|
||||
}
|
||||
@@ -13,17 +13,14 @@ using namespace frc;
|
||||
using namespace frc::sim;
|
||||
|
||||
ElevatorSim::ElevatorSim(const LinearSystem<2, 1, 1>& plant,
|
||||
const DCMotor& gearbox, double gearing,
|
||||
units::meter_t drumRadius, units::meter_t minHeight,
|
||||
const DCMotor& gearbox, units::meter_t minHeight,
|
||||
units::meter_t maxHeight, bool simulateGravity,
|
||||
units::meter_t startingHeight,
|
||||
const std::array<double, 1>& measurementStdDevs)
|
||||
: LinearSystemSim(plant, measurementStdDevs),
|
||||
m_gearbox(gearbox),
|
||||
m_drumRadius(drumRadius),
|
||||
m_minHeight(minHeight),
|
||||
m_maxHeight(maxHeight),
|
||||
m_gearing(gearing),
|
||||
m_simulateGravity(simulateGravity) {
|
||||
SetState(startingHeight, 0_mps);
|
||||
}
|
||||
@@ -36,8 +33,21 @@ ElevatorSim::ElevatorSim(const DCMotor& gearbox, double gearing,
|
||||
const std::array<double, 1>& measurementStdDevs)
|
||||
: ElevatorSim(LinearSystemId::ElevatorSystem(gearbox, carriageMass,
|
||||
drumRadius, gearing),
|
||||
gearbox, gearing, drumRadius, minHeight, maxHeight,
|
||||
simulateGravity, startingHeight, measurementStdDevs) {}
|
||||
gearbox, minHeight, maxHeight, simulateGravity,
|
||||
startingHeight, measurementStdDevs) {}
|
||||
|
||||
template <typename Distance>
|
||||
requires std::same_as<units::meter, Distance> ||
|
||||
std::same_as<units::radian, Distance>
|
||||
ElevatorSim::ElevatorSim(decltype(1_V / Velocity_t<Distance>(1)) kV,
|
||||
decltype(1_V / Acceleration_t<Distance>(1)) kA,
|
||||
const DCMotor& gearbox, units::meter_t minHeight,
|
||||
units::meter_t maxHeight, bool simulateGravity,
|
||||
units::meter_t startingHeight,
|
||||
const std::array<double, 1>& measurementStdDevs)
|
||||
: ElevatorSim(LinearSystemId::IdentifyPositionSystem(kV, kA), gearbox,
|
||||
minHeight, maxHeight, simulateGravity, startingHeight,
|
||||
measurementStdDevs) {}
|
||||
|
||||
void ElevatorSim::SetState(units::meter_t position,
|
||||
units::meters_per_second_t velocity) {
|
||||
@@ -74,10 +84,12 @@ units::ampere_t ElevatorSim::GetCurrentDraw() const {
|
||||
// Reductions are greater than 1, so a reduction of 10:1 would mean the motor
|
||||
// is spinning 10x faster than the output.
|
||||
|
||||
// v = r w, so w = v / r
|
||||
double kA = 1.0 / m_plant.B(1, 0);
|
||||
using Kv_t = units::unit_t<units::compound_unit<
|
||||
units::volt, units::inverse<units::meters_per_second>>>;
|
||||
Kv_t Kv = Kv_t{kA * m_plant.A(1, 1)};
|
||||
units::meters_per_second_t velocity{m_x(1)};
|
||||
units::radians_per_second_t motorVelocity =
|
||||
velocity / m_drumRadius * m_gearing * 1_rad;
|
||||
units::radians_per_second_t motorVelocity = velocity * Kv * m_gearbox.Kv;
|
||||
|
||||
// Perform calculation and return.
|
||||
return m_gearbox.Current(motorVelocity, units::volt_t{m_u(0)}) *
|
||||
|
||||
103
wpilibc/src/main/native/cpp/simulation/PS5ControllerSim.cpp
Normal file
103
wpilibc/src/main/native/cpp/simulation/PS5ControllerSim.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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 "frc/simulation/PS5ControllerSim.h"
|
||||
|
||||
#include "frc/PS5Controller.h"
|
||||
|
||||
using namespace frc;
|
||||
using namespace frc::sim;
|
||||
|
||||
PS5ControllerSim::PS5ControllerSim(const PS5Controller& joystick)
|
||||
: GenericHIDSim{joystick} {
|
||||
SetAxisCount(6);
|
||||
SetButtonCount(14);
|
||||
SetPOVCount(1);
|
||||
}
|
||||
|
||||
PS5ControllerSim::PS5ControllerSim(int port) : GenericHIDSim{port} {
|
||||
SetAxisCount(6);
|
||||
SetButtonCount(14);
|
||||
SetPOVCount(1);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetLeftX(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kLeftX, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetRightX(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kRightX, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetLeftY(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kLeftY, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetRightY(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kRightY, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetL2Axis(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kL2, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetR2Axis(double value) {
|
||||
SetRawAxis(PS5Controller::Axis::kR2, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetSquareButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kSquare, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetCrossButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kCross, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetCircleButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kCircle, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetTriangleButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kTriangle, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetL1Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kL1, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetR1Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kR1, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetL2Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kL2, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetR2Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kR2, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetCreateButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kCreate, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetOptionsButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kOptions, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetL3Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kL3, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetR3Button(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kR3, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetPSButton(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kPS, value);
|
||||
}
|
||||
|
||||
void PS5ControllerSim::SetTouchpad(bool value) {
|
||||
SetRawButton(PS5Controller::Button::kTouchpad, value);
|
||||
}
|
||||
@@ -49,6 +49,11 @@ class DataLogManager final {
|
||||
static void Start(std::string_view dir = "", std::string_view filename = "",
|
||||
double period = 0.25);
|
||||
|
||||
/**
|
||||
* Stop data log manager.
|
||||
*/
|
||||
static void Stop();
|
||||
|
||||
/**
|
||||
* Log a message to the "messages" entry. The message is also printed to
|
||||
* standard output (followed by a newline).
|
||||
|
||||
529
wpilibc/src/main/native/include/frc/PS5Controller.h
Normal file
529
wpilibc/src/main/native/include/frc/PS5Controller.h
Normal file
@@ -0,0 +1,529 @@
|
||||
// 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 "frc/GenericHID.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
* Handle input from PS5 controllers connected to the Driver Station.
|
||||
*
|
||||
* <p>This class handles PS5 input that comes from the Driver Station. Each time
|
||||
* a value is requested the most recent value is returned. There is a single
|
||||
* class instance for each controller and the mapping of ports to hardware
|
||||
* buttons depends on the code in the Driver Station.
|
||||
*/
|
||||
class PS5Controller : public GenericHID {
|
||||
public:
|
||||
/**
|
||||
* Construct an instance of an PS5 controller.
|
||||
*
|
||||
* The controller index is the USB port on the Driver Station.
|
||||
*
|
||||
* @param port The port on the Driver Station that the controller is plugged
|
||||
* into (0-5).
|
||||
*/
|
||||
explicit PS5Controller(int port);
|
||||
|
||||
~PS5Controller() override = default;
|
||||
|
||||
PS5Controller(PS5Controller&&) = default;
|
||||
PS5Controller& operator=(PS5Controller&&) = default;
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetLeftX() const;
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetRightX() const;
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetLeftY() const;
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller.
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetRightY() const;
|
||||
|
||||
/**
|
||||
* Get the L2 axis value of the controller. Note that this axis is bound to
|
||||
* the range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetL2Axis() const;
|
||||
|
||||
/**
|
||||
* Get the R2 axis value of the controller. Note that this axis is bound to
|
||||
* the range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return the axis value.
|
||||
*/
|
||||
double GetR2Axis() const;
|
||||
|
||||
/**
|
||||
* Read the value of the Square button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetSquareButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Square button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetSquareButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Square button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetSquareButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the square button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the square button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Square(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the Cross button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetCrossButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Cross button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetCrossButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Cross button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetCrossButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the cross button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the cross button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Cross(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the Circle button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetCircleButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Circle button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetCircleButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Circle button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetCircleButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the circle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the circle button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Circle(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the Triangle button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetTriangleButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Triangle button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetTriangleButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Triangle button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetTriangleButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the triangle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the triangle button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Triangle(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the L1 button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetL1Button() const;
|
||||
|
||||
/**
|
||||
* Whether the L1 button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetL1ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the L1 button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetL1ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L1 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent L1(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the R1 button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetR1Button() const;
|
||||
|
||||
/**
|
||||
* Whether the R1 button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetR1ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the R1 button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetR1ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R1 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent R1(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the L2 button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetL2Button() const;
|
||||
|
||||
/**
|
||||
* Whether the L2 button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetL2ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the L2 button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetL2ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L2 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent L2(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the R2 button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetR2Button() const;
|
||||
|
||||
/**
|
||||
* Whether the R2 button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetR2ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the R2 button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetR2ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R2 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent R2(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the Create button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetCreateButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Create button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetCreateButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Create button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetCreateButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the Create button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the Create button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Create(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the Options button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetOptionsButton() const;
|
||||
|
||||
/**
|
||||
* Whether the Options button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetOptionsButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the Options button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetOptionsButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the options button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the options button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Options(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the L3 button (pressing the left analog stick) on the
|
||||
* controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetL3Button() const;
|
||||
|
||||
/**
|
||||
* Whether the L3 (left stick) button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetL3ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the L3 (left stick) button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetL3ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the L3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the L3 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent L3(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the R3 button (pressing the right analog stick) on the
|
||||
* controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetR3Button() const;
|
||||
|
||||
/**
|
||||
* Whether the R3 (right stick) button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetR3ButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the R3 (right stick) button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetR3ButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the R3 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the R3 button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent R3(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the PS button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetPSButton() const;
|
||||
|
||||
/**
|
||||
* Whether the PS button was pressed since the last check.
|
||||
*
|
||||
* @return Whether the button was pressed since the last check.
|
||||
*/
|
||||
bool GetPSButtonPressed();
|
||||
|
||||
/**
|
||||
* Whether the PS button was released since the last check.
|
||||
*
|
||||
* @return Whether the button was released since the last check.
|
||||
*/
|
||||
bool GetPSButtonReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the PS button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the PS button's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent PS(EventLoop* loop) const;
|
||||
|
||||
/**
|
||||
* Read the value of the touchpad button on the controller.
|
||||
*
|
||||
* @return The state of the button.
|
||||
*/
|
||||
bool GetTouchpad() const;
|
||||
|
||||
/**
|
||||
* Whether the touchpad was pressed since the last check.
|
||||
*
|
||||
* @return Whether the touchpad was pressed since the last check.
|
||||
*/
|
||||
bool GetTouchpadPressed();
|
||||
|
||||
/**
|
||||
* Whether the touchpad was released since the last check.
|
||||
*
|
||||
* @return Whether the touchpad was released since the last check.
|
||||
*/
|
||||
bool GetTouchpadReleased();
|
||||
|
||||
/**
|
||||
* Constructs an event instance around the touchpad's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return an event instance representing the touchpad's digital signal
|
||||
* attached to the given loop.
|
||||
*/
|
||||
BooleanEvent Touchpad(EventLoop* loop) const;
|
||||
|
||||
struct Button {
|
||||
static constexpr int kSquare = 3;
|
||||
static constexpr int kCross = 1;
|
||||
static constexpr int kCircle = 2;
|
||||
static constexpr int kTriangle = 4;
|
||||
static constexpr int kL1 = 5;
|
||||
static constexpr int kR1 = 6;
|
||||
static constexpr int kL2 = 7;
|
||||
static constexpr int kR2 = 8;
|
||||
static constexpr int kCreate = 9;
|
||||
static constexpr int kOptions = 10;
|
||||
static constexpr int kL3 = 12;
|
||||
static constexpr int kR3 = 13;
|
||||
static constexpr int kPS = 11;
|
||||
static constexpr int kTouchpad = 14;
|
||||
};
|
||||
|
||||
struct Axis {
|
||||
static constexpr int kLeftX = 0;
|
||||
static constexpr int kLeftY = 1;
|
||||
static constexpr int kRightX = 3;
|
||||
static constexpr int kRightY = 4;
|
||||
static constexpr int kL2 = 2;
|
||||
static constexpr int kR2 = 5;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
@@ -19,6 +19,15 @@ namespace frc::sim {
|
||||
*/
|
||||
class ElevatorSim : public LinearSystemSim<2, 1, 1> {
|
||||
public:
|
||||
template <typename Distance>
|
||||
using Velocity_t = units::unit_t<
|
||||
units::compound_unit<Distance, units::inverse<units::seconds>>>;
|
||||
|
||||
template <typename Distance>
|
||||
using Acceleration_t = units::unit_t<units::compound_unit<
|
||||
units::compound_unit<Distance, units::inverse<units::seconds>>,
|
||||
units::inverse<units::seconds>>>;
|
||||
|
||||
/**
|
||||
* Constructs a simulated elevator mechanism.
|
||||
*
|
||||
@@ -27,10 +36,6 @@ class ElevatorSim : public LinearSystemSim<2, 1, 1> {
|
||||
* LinearSystemId::ElevatorSystem().
|
||||
* @param gearbox The type of and number of motors in your
|
||||
* elevator gearbox.
|
||||
* @param gearing The gearing of the elevator (numbers greater
|
||||
* than 1 represent reductions).
|
||||
* @param drumRadius The radius of the drum that your cable is
|
||||
* wrapped around.
|
||||
* @param minHeight The minimum allowed height of the elevator.
|
||||
* @param maxHeight The maximum allowed height of the elevator.
|
||||
* @param simulateGravity Whether gravity should be simulated or not.
|
||||
@@ -38,7 +43,6 @@ class ElevatorSim : public LinearSystemSim<2, 1, 1> {
|
||||
* @param measurementStdDevs The standard deviation of the measurements.
|
||||
*/
|
||||
ElevatorSim(const LinearSystem<2, 1, 1>& plant, const DCMotor& gearbox,
|
||||
double gearing, units::meter_t drumRadius,
|
||||
units::meter_t minHeight, units::meter_t maxHeight,
|
||||
bool simulateGravity, units::meter_t startingHeight,
|
||||
const std::array<double, 1>& measurementStdDevs = {0.0});
|
||||
@@ -65,6 +69,28 @@ class ElevatorSim : public LinearSystemSim<2, 1, 1> {
|
||||
bool simulateGravity, units::meter_t startingHeight,
|
||||
const std::array<double, 1>& measurementStdDevs = {0.0});
|
||||
|
||||
/**
|
||||
* Constructs a simulated elevator mechanism.
|
||||
*
|
||||
* @param kV The velocity gain.
|
||||
* @param kA The acceleration gain.
|
||||
* @param gearbox The type of and number of motors in your
|
||||
* elevator gearbox.
|
||||
* @param minHeight The minimum allowed height of the elevator.
|
||||
* @param maxHeight The maximum allowed height of the elevator.
|
||||
* @param simulateGravity Whether gravity should be simulated or not.
|
||||
* @param startingHeight The starting height of the elevator.
|
||||
* @param measurementStdDevs The standard deviation of the measurements.
|
||||
*/
|
||||
template <typename Distance>
|
||||
requires std::same_as<units::meter, Distance> ||
|
||||
std::same_as<units::radian, Distance>
|
||||
ElevatorSim(decltype(1_V / Velocity_t<Distance>(1)) kV,
|
||||
decltype(1_V / Acceleration_t<Distance>(1)) kA,
|
||||
const DCMotor& gearbox, units::meter_t minHeight,
|
||||
units::meter_t maxHeight, bool simulateGravity,
|
||||
units::meter_t startingHeight,
|
||||
const std::array<double, 1>& measurementStdDevs = {0.0});
|
||||
using LinearSystemSim::SetState;
|
||||
|
||||
/**
|
||||
@@ -146,10 +172,8 @@ class ElevatorSim : public LinearSystemSim<2, 1, 1> {
|
||||
|
||||
private:
|
||||
DCMotor m_gearbox;
|
||||
units::meter_t m_drumRadius;
|
||||
units::meter_t m_minHeight;
|
||||
units::meter_t m_maxHeight;
|
||||
double m_gearing;
|
||||
bool m_simulateGravity;
|
||||
};
|
||||
} // namespace frc::sim
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
// 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 "frc/simulation/GenericHIDSim.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
class PS5Controller;
|
||||
|
||||
namespace sim {
|
||||
|
||||
/**
|
||||
* Class to control a simulated PS5 controller.
|
||||
*/
|
||||
class PS5ControllerSim : public GenericHIDSim {
|
||||
public:
|
||||
/**
|
||||
* Constructs from a PS5Controller object.
|
||||
*
|
||||
* @param joystick controller to simulate
|
||||
*/
|
||||
explicit PS5ControllerSim(const PS5Controller& joystick);
|
||||
|
||||
/**
|
||||
* Constructs from a joystick port number.
|
||||
*
|
||||
* @param port port number
|
||||
*/
|
||||
explicit PS5ControllerSim(int port);
|
||||
|
||||
/**
|
||||
* Change the X axis value of the controller's left stick.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetLeftX(double value);
|
||||
|
||||
/**
|
||||
* Change the X axis value of the controller's right stick.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetRightX(double value);
|
||||
|
||||
/**
|
||||
* Change the Y axis value of the controller's left stick.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetLeftY(double value);
|
||||
|
||||
/**
|
||||
* Change the Y axis value of the controller's right stick.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetRightY(double value);
|
||||
|
||||
/**
|
||||
* Change the L2 axis axis value of the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetL2Axis(double value);
|
||||
|
||||
/**
|
||||
* Change the R2 axis value of the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetR2Axis(double value);
|
||||
|
||||
/**
|
||||
* Change the value of the Square button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetSquareButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the Cross button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetCrossButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the Circle button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetCircleButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the Triangle button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetTriangleButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the L1 button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetL1Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the R1 button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetR1Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the L2 button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetL2Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the R2 button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetR2Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the Create button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetCreateButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the Options button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetOptionsButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the L3 (left stick) button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetL3Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the R3 (right stick) button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetR3Button(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the PS button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetPSButton(bool value);
|
||||
|
||||
/**
|
||||
* Change the value of the touchpad button on the controller.
|
||||
*
|
||||
* @param value the new value
|
||||
*/
|
||||
void SetTouchpad(bool value);
|
||||
};
|
||||
|
||||
} // namespace sim
|
||||
} // namespace frc
|
||||
@@ -16,6 +16,7 @@ class SolenoidSim {
|
||||
SolenoidSim(std::shared_ptr<PneumaticsBaseSim> moduleSim, int channel);
|
||||
SolenoidSim(int module, PneumaticsModuleType type, int channel);
|
||||
SolenoidSim(PneumaticsModuleType type, int channel);
|
||||
virtual ~SolenoidSim() = default;
|
||||
|
||||
bool GetOutput() const;
|
||||
void SetOutput(bool output);
|
||||
|
||||
38
wpilibc/src/test/native/cpp/PS5ControllerTest.cpp
Normal file
38
wpilibc/src/test/native/cpp/PS5ControllerTest.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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 "frc/PS5Controller.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "JoystickTestMacros.h"
|
||||
#include "frc/simulation/PS5ControllerSim.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
BUTTON_TEST(PS5Controller, SquareButton)
|
||||
BUTTON_TEST(PS5Controller, CrossButton)
|
||||
BUTTON_TEST(PS5Controller, CircleButton)
|
||||
BUTTON_TEST(PS5Controller, TriangleButton)
|
||||
|
||||
BUTTON_TEST(PS5Controller, L1Button)
|
||||
BUTTON_TEST(PS5Controller, R1Button)
|
||||
BUTTON_TEST(PS5Controller, L2Button)
|
||||
BUTTON_TEST(PS5Controller, R2Button)
|
||||
|
||||
BUTTON_TEST(PS5Controller, CreateButton)
|
||||
BUTTON_TEST(PS5Controller, OptionsButton)
|
||||
|
||||
BUTTON_TEST(PS5Controller, L3Button)
|
||||
BUTTON_TEST(PS5Controller, R3Button)
|
||||
|
||||
BUTTON_TEST(PS5Controller, PSButton)
|
||||
BUTTON_TEST(PS5Controller, Touchpad)
|
||||
|
||||
AXIS_TEST(PS5Controller, LeftX)
|
||||
AXIS_TEST(PS5Controller, RightX)
|
||||
AXIS_TEST(PS5Controller, LeftY)
|
||||
AXIS_TEST(PS5Controller, RightY)
|
||||
AXIS_TEST(PS5Controller, L2Axis)
|
||||
AXIS_TEST(PS5Controller, R2Axis)
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
#include <networktables/StringTopic.h>
|
||||
@@ -21,11 +22,14 @@ TEST_P(SendableChooserTest, ReturnsSelected) {
|
||||
}
|
||||
chooser.SetDefaultOption("0", 0);
|
||||
|
||||
auto pub = nt::NetworkTableInstance::GetDefault()
|
||||
.GetStringTopic("/SmartDashboard/chooser/selected")
|
||||
.Publish();
|
||||
auto pub =
|
||||
nt::NetworkTableInstance::GetDefault()
|
||||
.GetStringTopic(fmt::format(
|
||||
"/SmartDashboard/ReturnsSelectedChooser{}/selected", GetParam()))
|
||||
.Publish();
|
||||
|
||||
frc::SmartDashboard::PutData("chooser", &chooser);
|
||||
frc::SmartDashboard::PutData(
|
||||
fmt::format("ReturnsSelectedChooser{}", GetParam()), &chooser);
|
||||
frc::SmartDashboard::UpdateValues();
|
||||
pub.Set(std::to_string(GetParam()));
|
||||
frc::SmartDashboard::UpdateValues();
|
||||
@@ -65,9 +69,9 @@ TEST(SendableChooserTest, ChangeListener) {
|
||||
int currentVal = 0;
|
||||
chooser.OnChange([&](int val) { currentVal = val; });
|
||||
|
||||
frc::SmartDashboard::PutData("chooser", &chooser);
|
||||
frc::SmartDashboard::PutData("ChangeListenerChooser", &chooser);
|
||||
frc::SmartDashboard::UpdateValues();
|
||||
frc::SmartDashboard::PutString("chooser/selected", "3");
|
||||
frc::SmartDashboard::PutString("ChangeListenerChooser/selected", "3");
|
||||
frc::SmartDashboard::UpdateValues();
|
||||
|
||||
EXPECT_EQ(3, currentVal);
|
||||
|
||||
@@ -22,6 +22,10 @@ task cppExamplesZip(type: Zip) {
|
||||
from('src/main/cpp/examples') {
|
||||
into 'examples'
|
||||
}
|
||||
|
||||
from('src/test/cpp/examples') {
|
||||
into 'examples_test'
|
||||
}
|
||||
}
|
||||
|
||||
task cppTemplatesZip(type: Zip) {
|
||||
@@ -35,6 +39,10 @@ task cppTemplatesZip(type: Zip) {
|
||||
from('src/main/cpp/templates') {
|
||||
into 'templates'
|
||||
}
|
||||
|
||||
from('src/test/cpp/templates') {
|
||||
into 'templates_test'
|
||||
}
|
||||
}
|
||||
|
||||
task cppCommandsZip(type: Zip) {
|
||||
@@ -48,6 +56,10 @@ task cppCommandsZip(type: Zip) {
|
||||
from('src/main/cpp/commands') {
|
||||
into 'commands'
|
||||
}
|
||||
|
||||
from('src/test/cpp/commands') {
|
||||
into 'commands_test'
|
||||
}
|
||||
}
|
||||
|
||||
build.dependsOn cppTemplatesZip
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user