Compare commits

...

55 Commits

Author SHA1 Message Date
Peter Johnson
f1a82828fe [wpiutil] Add DataLog and DataLogManager Stop() (#5860)
Restarting a stopped log results in creating a new log file with fresh copies of the same start records and schema data records.

Also check to see if the file has been deleted or if the log file exceeds 1.8 GB, and start a new one.
2023-11-03 20:34:43 -07:00
Ryan Blue
2a04e12c6f [apriltag] AprilTagFieldLayout: Add accessors for origin and field dimensions (#5869) 2023-11-03 20:24:23 -07:00
Ryan Blue
33e0089afb Cleanup usages of std::function<void(void)> (#5864) 2023-11-03 18:22:47 -07:00
Ryan Blue
d06fa633d5 [build] Fix protobuf generation when building with make (#5867) 2023-11-03 18:22:34 -07:00
Ryan Blue
049732afb8 [cscore] Make camera connection logging clearer (#5866) 2023-11-03 16:03:23 -07:00
Bryce Roethel
87f7c19f90 [wpimath] Make InterpolatingDoubleTreeMap constructor public (#5865) 2023-11-03 15:34:14 -07:00
Tyler Veness
6b53ef47cf [wpimath] Don't recreate TrapezoidProfile in ProfiledPIDController calculate() (#5863) 2023-11-03 15:21:58 -07:00
shueja-personal
8a3a268ae6 [commands] Add finallyDo with zero-arg lambda (#5862) 2023-11-03 15:21:21 -07:00
Tyler Veness
1c35d42cd0 [wpilib] Pop diagnostic for deprecated function use (#5859) 2023-11-03 08:34:08 -07:00
narmstro2020
ddc8db6c26 [wpimath] Add feedforward constant constructor to ElevatorSim (#5823)
Adds a subclass of ElevatorSim that uses kG, kV, and kA from sysId to simulate an Elevator.
2023-11-02 09:10:57 -07:00
Tyler Veness
c6aff2c431 [upstream_utils] Update to LLVM 17.0.4 (#5855) 2023-11-01 16:45:32 -07:00
Peter Johnson
a9c5b18a39 [build] Update OpenCV to 2024-4.8.0-2 (#5854)
This fixes rpath on cross-build targets to properly include $ORIGIN.
2023-11-01 09:45:40 -07:00
Kevin-OConnor
9540b6922d [hal] Add CAN IDs for AndyMark and Vivid Hosting (#5852) 2023-10-31 15:59:42 -07:00
Peter Johnson
83a7d33c47 [glass] Improve display of protobuf/struct type strings (#5850) 2023-10-30 20:29:29 -07:00
Ryan Blue
a4a8ad9c75 [commands] Make Java SelectCommand generic (#5849)
This allows users to use any type of map and selector without needing to explicitly match
Map<Object, Command>
2023-10-30 11:09:14 -07:00
Gold856
9eecf2a456 [build] Add CMake option to build Java sources jars (#5768) 2023-10-30 09:57:28 -07:00
David Baucum
9536a311cb [wpilib] Add support for the PS5 DualSense controller (#5257)
Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2023-10-30 08:25:16 -07:00
Dustin Spicuzza
8d5e6737fc [wpilibc] SolenoidSim: Add virtual destructor (#5848) 2023-10-30 08:24:11 -07:00
Peter Johnson
07e13d60a2 [ntcore] Fix write_impl (#5847)
The previous fix didn't handle all cases correctly. Instead, add a new
function to raw_ostream (SetNumBytesInBuffer) to allow always using the
full buffer size, and revamp write_impl to more cleanly handle all
cases.
2023-10-30 08:23:33 -07:00
Peter Johnson
1713386869 [wpiutil] ProtobufMessageDatabase: Fix out-of-order Add() rebuild (#5845) 2023-10-29 16:50:01 -07:00
Peter Johnson
35472f5fc9 [ntcore] Fix a use-after-free in client close (#5844) 2023-10-29 16:49:45 -07:00
Peter Johnson
ed168b522c [ntcore] Disable buf pool when asan is enabled (#5843)
This helps asan catch more errors.
2023-10-29 16:49:31 -07:00
Peter Johnson
3e7ba2cc6f [wpinet] WebSocket: Fix write behavior (#5841)
On Windows, TryWrite will always return 0 if there is a Write in progress. The previous behavior for SendFrames and SendControl just used a normal Write, which caused issues with code that combined these with TrySendFrames. Instead, have SendFrames and SendControl also use TryWrite under the hood if possible, and create write requests if not. The implementation preserves the priority of SendControl against an existing write request with multiple frames.
2023-10-29 16:48:25 -07:00
Gold856
80c47da237 [sim] Disable the robot program when DS disconnects (#5818) 2023-10-28 10:10:23 -07:00
sciencewhiz
abe1cec90c [wpilib] Update Usage Reporting ResourceType from NI Libraries (#5842)
Disable PS4 controller reporting until added by NI
2023-10-27 20:21:46 -07:00
Oliver
cdf981abba [glass] Fix position of data type in NT view (#5840) 2023-10-27 17:41:42 -07:00
Thad House
04dcd80adb [build] Publish unit tests for examples (#5838) 2023-10-27 16:57:38 -07:00
Jordan McMichael
49920234ac [build] Fix checkstyle rules to allow Windows paths (#5839) 2023-10-27 16:56:58 -07:00
Ryan Blue
366b715942 [wpilib] Fix SendableChooser test (#5835)
Using unique NT keys for each test seems to resolve the failure on Linux. Changed Java as well, for completeness.
2023-10-26 20:47:04 -07:00
Ryan Blue
3ba501f947 [commands] Java: Fix CommandXboxController.leftTrigger() parameter order (#5831) 2023-10-26 19:18:36 -07:00
Tyler Veness
ec569a58ef [wpimath] Make KalmanTypeFilter interface public (#5830) 2023-10-26 19:18:02 -07:00
Peter Johnson
b91317fd36 [wpiutil] DataLog.addSchema(): Don't add into a set view (#5829) 2023-10-26 19:17:47 -07:00
Peter Johnson
2ab4fcbc24 [wpiutil] ProtobufMessageDatabase: Clear messages first (#5827)
The message destructor appears to call something on the descriptor.
2023-10-26 19:17:29 -07:00
Tyler Veness
98c14f1692 [wpimath] Add EKF/UKF u-y-R correct overload (#5832)
Also clean up comments on other overloads and fix a typo.
2023-10-26 19:17:15 -07:00
Ryan Blue
60bcdeded9 [ci] Disable java in sanitizer builds (#5833) 2023-10-26 19:16:58 -07:00
Ryan Blue
c87f8fd538 [commands] Add DeferredCommand (#5566)
Allows commands to be constructed at runtime without proxying.
2023-10-26 19:16:33 -07:00
Ryan Blue
ad80eb3a0b [ci] Update actions for comment-command (#5824) 2023-10-25 14:33:22 -07:00
Peter Johnson
c7d6ad5a0b [ntcore] WebSocketConnection: Use weak capture (#5822)
Fixes a potential use-after-free on connection close.
2023-10-25 10:22:43 -07:00
Zhiquan Yeo
8a8e220792 [simgui] Add 'Invalid' option for AllianceStation (#5820) 2023-10-24 11:51:39 -07:00
Gold856
cfc6a47f76 [sim] DS plugin: Fix off-by-one error when setting alliance station (#5819) 2023-10-24 09:15:40 -07:00
Peter Johnson
8efa586ace [ntcore] Don't check type string on publishing an entry (#5816)
Only check the raw type value.
2023-10-24 00:12:02 -07:00
Peter Johnson
23ea188e60 [glass] Add protobuf decode error log message (#5812) 2023-10-23 23:36:23 -07:00
Ryan Blue
928e87b4f4 [build] Add combined test meta-task (#5813) 2023-10-23 23:35:44 -07:00
Benjamin Hall
63ef585d4b [wpiutil] Fix compilation of MathExtras.h on Windows with /sdl (#5809)
Fix copied from the LLVM main branch.
2023-10-23 21:35:13 -07:00
Ryan Blue
b03a7668f9 [build] Windows CMake/vcpkg fixes (#5807)
- Add builtin registry baseline (fixes building locally with msvc builtin vcpkg)
- Add protobuf as an explicit dependency (previously was installed as a dependency of opencv)
- In windows CI, checkout repository before running vcpkg (silences warning that vcpkg.json was not found)
2023-10-23 21:33:28 -07:00
Thad House
3f08bcde54 [hal] Fix HAL AllianceStation on rio (#5811) 2023-10-23 21:32:21 -07:00
Peter Johnson
196d963dc4 [ntcore] Fix off-by-one error in stream write (#5810) 2023-10-23 21:31:36 -07:00
sciencewhiz
f4cbcbc984 Fix typos (NFC) (#5804) 2023-10-23 09:15:58 -07:00
Thad House
ec0f7fefb0 [myrobot] Update the myRobot JRE (#5805) 2023-10-23 09:14:50 -07:00
Jonah
3d618bdbfd [wpiutil] Fix Java struct array unpacking (#5801) 2023-10-21 20:13:50 -07:00
Peter Johnson
1fa7445667 [ntcore] Check for valid client in incoming text and binary (#5799) 2023-10-20 23:25:05 -07:00
Ryan Blue
269b9647da [ci] Update JDK for combine step (#5794)
Also frees disk space from the combiner step.
2023-10-20 18:18:04 -07:00
Tyler Veness
bee32f080e [docs] Add wpiunits to JavaDocs (#5793)
Co-authored-by: Sam Carlberg <sam.carlberg@gmail.com>
2023-10-20 18:14:14 -07:00
Peter Johnson
25dad5a531 [wpinet] TCPConnector_parallel: Don't use thread_local (#5791)
Thread_local causes issues with LabVIEW, which makes calls on a thread
pool.
2023-10-20 16:45:07 -07:00
Tyler Veness
4a93581f1a [build] cmake: use default library type for libglassnt, libglass, wpigui, and imgui (#5797)
On Windows, imgui and wpigui need to be static.  On Mac, they must be dynamic.
2023-10-20 16:44:26 -07:00
153 changed files with 4831 additions and 537 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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' &&

View File

@@ -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"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.

View File

@@ -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)

View File

@@ -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.
*

View File

@@ -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()) {

View File

@@ -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.
*

View File

@@ -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) {

View File

@@ -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})

View File

@@ -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)

View File

@@ -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;

View File

@@ -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:)

View File

@@ -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);

View File

@@ -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 ")));
}
}

View File

@@ -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'

View File

@@ -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)

View File

@@ -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();

View File

@@ -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()) &&

View File

@@ -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)

View File

@@ -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

View File

@@ -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));

View File

@@ -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
/** @} */

View File

@@ -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.

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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).

View File

@@ -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

View File

@@ -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")

View File

@@ -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"
}
}

View File

@@ -0,0 +1,7 @@
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
tasks.register('testDesktop') {
dependsOn testDesktopJava
dependsOn testDesktopCpp
}

View File

@@ -77,7 +77,7 @@ def tagList = [
"Digital Output",
/* --- HID --- */
"XboxController", "PS4Controller", "Joystick",
"XboxController", "PS4Controller", "PS5Controller", "Joystick",
/* --- Misc --- */
/* (try to keep this section minimal) */

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +1,4 @@
def opencvVersion = '4.8.0-1'
def opencvVersion = '4.8.0-2'
if (project.hasProperty('useCpp') && project.useCpp) {
model {

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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) {}

View File

@@ -35,7 +35,7 @@ __declspec(dllexport)
return -1;
}
std::puts("HALSim XRP Extention Initialized");
std::puts("HALSim XRP Extension Initialized");
return 0;
}

View File

@@ -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,

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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

View File

@@ -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;

View File

@@ -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),

View File

@@ -5,6 +5,8 @@
"opencv",
"eigen3",
"fmt",
"libuv"
]
"libuv",
"protobuf"
],
"builtin-baseline": "78b61582c9e093fda56a01ebb654be15a0033897"
}

View File

@@ -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)

View File

@@ -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")

View File

@@ -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.

View File

@@ -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);
}
/**

View File

@@ -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);
}
}

View File

@@ -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");

View File

@@ -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));
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
/**

View File

@@ -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));
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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});
}

View File

@@ -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>();
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -0,0 +1,61 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
});
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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 {

View 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(); });
}

View File

@@ -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)}) *

View 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);
}

View File

@@ -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).

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View 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)

View File

@@ -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);

View File

@@ -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