Squashed 'third_party/allwpilib/' changes from 83f1860047..f1a82828fe
f1a82828fe [wpiutil] Add DataLog and DataLogManager Stop() (#5860)
2a04e12c6f [apriltag] AprilTagFieldLayout: Add accessors for origin and field dimensions (#5869)
33e0089afb Cleanup usages of std::function<void(void)> (#5864)
d06fa633d5 [build] Fix protobuf generation when building with make (#5867)
049732afb8 [cscore] Make camera connection logging clearer (#5866)
87f7c19f90 [wpimath] Make InterpolatingDoubleTreeMap constructor public (#5865)
6b53ef47cf [wpimath] Don't recreate TrapezoidProfile in ProfiledPIDController calculate() (#5863)
8a3a268ae6 [commands] Add finallyDo with zero-arg lambda (#5862)
1c35d42cd0 [wpilib] Pop diagnostic for deprecated function use (#5859)
ddc8db6c26 [wpimath] Add feedforward constant constructor to ElevatorSim (#5823)
c6aff2c431 [upstream_utils] Update to LLVM 17.0.4 (#5855)
a9c5b18a39 [build] Update OpenCV to 2024-4.8.0-2 (#5854)
9540b6922d [hal] Add CAN IDs for AndyMark and Vivid Hosting (#5852)
83a7d33c47 [glass] Improve display of protobuf/struct type strings (#5850)
a4a8ad9c75 [commands] Make Java SelectCommand generic (#5849)
9eecf2a456 [build] Add CMake option to build Java sources jars (#5768)
9536a311cb [wpilib] Add support for the PS5 DualSense controller (#5257)
8d5e6737fc [wpilibc] SolenoidSim: Add virtual destructor (#5848)
07e13d60a2 [ntcore] Fix write_impl (#5847)
1713386869 [wpiutil] ProtobufMessageDatabase: Fix out-of-order Add() rebuild (#5845)
35472f5fc9 [ntcore] Fix a use-after-free in client close (#5844)
ed168b522c [ntcore] Disable buf pool when asan is enabled (#5843)
3e7ba2cc6f [wpinet] WebSocket: Fix write behavior (#5841)
80c47da237 [sim] Disable the robot program when DS disconnects (#5818)
abe1cec90c [wpilib] Update Usage Reporting ResourceType from NI Libraries (#5842)
cdf981abba [glass] Fix position of data type in NT view (#5840)
04dcd80adb [build] Publish unit tests for examples (#5838)
49920234ac [build] Fix checkstyle rules to allow Windows paths (#5839)
366b715942 [wpilib] Fix SendableChooser test (#5835)
3ba501f947 [commands] Java: Fix CommandXboxController.leftTrigger() parameter order (#5831)
ec569a58ef [wpimath] Make KalmanTypeFilter interface public (#5830)
b91317fd36 [wpiutil] DataLog.addSchema(): Don't add into a set view (#5829)
2ab4fcbc24 [wpiutil] ProtobufMessageDatabase: Clear messages first (#5827)
98c14f1692 [wpimath] Add EKF/UKF u-y-R correct overload (#5832)
60bcdeded9 [ci] Disable java in sanitizer builds (#5833)
c87f8fd538 [commands] Add DeferredCommand (#5566)
ad80eb3a0b [ci] Update actions for comment-command (#5824)
c7d6ad5a0b [ntcore] WebSocketConnection: Use weak capture (#5822)
8a8e220792 [simgui] Add 'Invalid' option for AllianceStation (#5820)
cfc6a47f76 [sim] DS plugin: Fix off-by-one error when setting alliance station (#5819)
8efa586ace [ntcore] Don't check type string on publishing an entry (#5816)
23ea188e60 [glass] Add protobuf decode error log message (#5812)
928e87b4f4 [build] Add combined test meta-task (#5813)
63ef585d4b [wpiutil] Fix compilation of MathExtras.h on Windows with /sdl (#5809)
b03a7668f9 [build] Windows CMake/vcpkg fixes (#5807)
3f08bcde54 [hal] Fix HAL AllianceStation on rio (#5811)
196d963dc4 [ntcore] Fix off-by-one error in stream write (#5810)
f4cbcbc984 Fix typos (NFC) (#5804)
ec0f7fefb0 [myrobot] Update the myRobot JRE (#5805)
3d618bdbfd [wpiutil] Fix Java struct array unpacking (#5801)
1fa7445667 [ntcore] Check for valid client in incoming text and binary (#5799)
269b9647da [ci] Update JDK for combine step (#5794)
bee32f080e [docs] Add wpiunits to JavaDocs (#5793)
25dad5a531 [wpinet] TCPConnector_parallel: Don't use thread_local (#5791)
4a93581f1a [build] cmake: use default library type for libglassnt, libglass, wpigui, and imgui (#5797)
abb2857e03 [wpilib] Counter: Fix default distance per pulse, add distance and rate to C++ (#5796)
b14a61e1c0 [readme] Add link to QuickBuffers release page (#5795)
cf54d9ccb7 [wpiutil, ntcore] Add structured data support (#5391)
ecb7cfa9ef [wpimath] Add Exponential motion profile (#5720)
7c6fe56cf2 [ntcore] Fix crash on disconnect (#5788)
85147bf69e [wpinet] WebSocketSerializer: Fix UB (#5787)
244163acad [wpinet] uv::Stream::TryWrite(): Return 0 on EAGAIN (#5784)
820728503d [hal] Remove extra semicolon in RoboRioData (#5786)
45f307d87e [upstream_utils] Upgrade to LLVM 17.0.3 (#5785)
4ce4d63efc [wpilibj] Fix RobotBase.isSimulation() (#5783)
579007ceb3 [commands] Add requirements parameter to Commands.idle() (#5774)
3f3a169149 [wpilib] Make physics sim setState() functions public (#5779)
7501e4ac88 [wpilib] Close sim device in ADIS IMUs (#5776)
99630d2e78 [wpimath] Upgrade to EJML 0.43.1 (#5778)
02cbbc997d [wpimath] Make Vector-Vector binary operators return Vector (#5772)
ed93889e17 [examples] Fix typo in TimesliceRobot example name (#5773)
da70e4c262 [docs] Add jinja2 to CMake prerequisites (#5771)
e814595ea7 [wpimath] Add ChassisSpeeds.fromRobotRelativeSpeeds() (#5744)
f98c943445 [wpimath] LinearSystemId: Add DCMotorSystem overload (#5770)
b3eb64b0f7 [wpiutil] ct_string: Use inline namespace for literals (#5767)
7d9ba256c2 Revert "[build] Add CMake option to build Java source jars (#5756)" (#5766)
1f6492e3d8 [sysid] Update JSON library usage (#5765)
638f04f626 [wpiutil] Add protobuf to thirdparty sources (#5746)
210255bfff [wpiutil] Update json to 3.11.2 (#5680)
896772c750 [wpimath] Add DCMotor functions for Kraken X60 and Neo Vortex (#5759)
fd427f6c82 [wpimath] Fix hardcoded module count in SwerveDriveKinematics.resetHeading() (#5762)
c0b4c6cce6 [wpimath] Add overloads for Transform2d and Transform3d (#5757)
9a0aafd8ab [examples] Make swerve examples multiply desired module speeds by cosine of heading error (#5758)
1c724884ca [build] Add CMake option to build Java source jars (#5756)
5b0db6b93e [ci] Forward CI as well (#5755)
f8cbbbac12 [ci] Take 2 on passing GITHUB_REF (#5754)
b9944be09c [ci] Pass GITHUB_REF to docker container (#5753)
de5e4eda6c [build] Update apriltag, libssh, googletest for 2024 (#5752)
227e660e20 [upstream_utils] Upgrade to LLVM 17.0.2 (#5750)
36f94c9f21 [commands,romi,xrp] Add frcYear to vendordep (#5747)
741d166457 [glass] NT view: enhance array support (#5732)
1d23513945 [ntcore] Fix string array value comparison (#5745)
ff1849052e [commands] Make command scheduling order consistent (#5470)
58e8474368 [build] Disable armsimulation unit test (#5739)
fb07b0da49 [examples] Add XRP C++ Examples and Templates (#5743)
81893ad73d Run wpiformat with clang-format 17 (#5740)
faa1e665ba [wpimath] Add ElevatorFeedforward.calculate(currentV, nextV) overload (#5715)
a789632052 [build] Update to native utils 2024.3.1 (#5738)
8f60ab5182 [build] Update OpenCV to 2024-4.8.0-1 (#5737)
33243f982b [wpimath] Expand Quaternion class with additional operators (#5600)
420f2f7c80 [ntcore] Add RTT-only subprotocol (#5731)
2b63e35ded [ntcore] Fix moving outgoing queue to new period (#5735)
be939cb636 [ntcore] Fix notification of SetDefaultEntryValue (#5733)
69a54de202 [build] Update enterprise plugin (#5730)
fef03a3ff5 [commands] Clean up C++ includes after Requirements was added (#5719)
8b7c6852cf [ntcore] Networking improvements (#5659)
1d19e09ca9 [wpiutil] Set WPI_{UN}IGNORE_DEPRECATED to empty when all else fails (#5728)
58141d6eb5 [wpilib] Make BooleanEvent more consistent (#5436)
6576d9b474 [wpilib] SendableChooser: implement Sendable instead of NTSendable (#5718)
a4030c670f [build] Update to gradle 8.4, enable win arm builds (#5727)
0960f11eba [wpinet] Revert removal of uv_clock_gettime() (#5723)
cb1bd0a3be [wpiutil] Get more precise system time on Windows (#5722)
4831277ffe [wpigui] Fix loading a maximized window on second monitor (#5721)
3eb372c25a [wpiutil] SendableBuilder: Add PublishConst methods (#5158)
1fec8596a4 [ci] Fix -dirty version (#5716)
f7e47d03f3 [build] Remove unnecessary CMake config installs (#5714)
a331ed2374 [sysid] Add SysId (#5672)
8d2cbfce16 [wpiutil] DataLog: Stop logging if insufficient free space (#5699)
48facb9cef [ntcoreffi] Add DataLogManager (#5702)
aecbcb08fc [ntcore] Correctly start DataLog for existing publishers (#5703)
5e295dfbda [wpiutil] DataLog: Limit total buffer allocation (#5700)
c7c7e05d9d [ci] Unbreak combiner (#5698)
c92bad52cb [wpilib] DataLogManager: Use system time valid function (#5697)
d404af5f24 [wpilib] RobotController: Add isSystemTimeValid() (#5696)
e56f1a3632 [ci] Run combine but skip all steps (#5695)
8f5bcad244 [ci] Use sccache for cmake builds (#5692)
703dedc4a6 [ci] Upgrade get-cmake action to fix node12 deprecation warning (#5694)
c69a0d7504 [ci] Don't run example unit test that segfaults (#5693)
66358d103e Add menu items for online docs to GUI tools (#5689)
4be8384a76 [ci] Disable combine on PR builds (#5691)
90288f06a6 [ci] Fix Gradle disk space issues (#5688)
9e9583412e [wpigui] Make wpi::gui::OpenURL() fork the process first (#5687)
d4fcd80b7b [ci] Gradle: Use container only for build step (#5684)
7b70e66772 [outlineviewer] Fix thirdparty library include sorting (#5683)
5f651df5d5 [build] Clean up Gradle configs (#5685)
65b26738d5 Add CMakeSettings.json to gitignore (#5682)
d0305951ad Fix GitHub inline warnings (#5681)
e8d4a20331 [build][cmake] Fix windows tests and re-enable CI tests (#5674)
2b58bbde0b [xrp] Add Reflectance sensor and rangefinder classes (#5673)
dd5612fbee [json] Add forward definition header (#5676)
eab44534c3 [wpimath] Remove unused SmallString include (#5677)
5ab54ff760 Replace wpi::raw_istream with wpi::MemoryBuffer (#5675)
1b6ec5a95d [wpiutil] Upgrade to LLVM 17.0.1 (#5482)
07a0d22fe6 [build] Build examples in CMake CI (#5667)
97021f074a [build] Upgrade imgui and implot (#5668)
87ce1e3761 [build] Fix wpilibNewCommands CMake install (#5671)
6ef94de9b5 [wpimath] Add tests for ArmFeedforward and ElevatorFeedforward (#5663)
c395b29fb4 [wpinet] Add WebSocket::TrySendFrames() (#5607)
c4643ba047 [romi/xrp] Fix version typo in vendordep json (#5664)
51dcb8b55a [examples] Make Romi/XRP Examples use appropriate vendordeps (#5665)
daf7702007 [build] Test each example in a new environment (#5662)
e67df8c180 [wpilib] Const-qualify EncoderSim getters (#5660)
7be290147c [wpiutil] Refactor SpanMatcher and TestPrinters from ntcore (#5658)
9fe258427a [commands] Add proxy factory to Commands (#5603)
633c5a8a22 [commands] Add C++ Requirements struct (#5504)
b265a68eea [commands] Add interruptor parameter to onCommandInterrupt callbacks (#5461)
e93c233d60 [ntcore] Compute Value memory size when creating value (#5657)
5383589f99 [wpinet] uv::Request: Return shared_ptr from Release() (#5656)
40b552be4a [wpinet] uv::Stream: Return error from TryWrite() (#5655)
202a75fe08 [wpinet] RequestImpl: Avoid infinite loop in shared_from_this() (#5654)
8896515eb7 [wpinet] uv::Buffer: Add bytes() accessor (#5653)
ae59a2fba2 [wpinet] uv::Error: Change default error to 0 (#5652)
3b51ecc35b [wpiutil] SpanExtras: Add take_back and take_front (#5651)
17f1062885 Replace std::snprintf() with wpi::format_to_n_c_str() (#5645)
bb39900353 [romi/xrp] Add Romi and XRP Vendordeps (#5644)
cb99517838 [build] cmake: Use default install location on windows for dlls (#5580)
25b0622d4c [build] Add Windows CMake CI (#5516)
34e7849605 Add warning to development builds instructions (NFC) (#5646)
e9e611c9d8 [cameraserver] Remove CameraServer.SetSize() (#5650)
94f58cc536 [wpilib] Remove Compressor.Enabled() (#5649)
4da5aee88a [wpimath] Remove SlewRateLimiter 2 argument constructor (#5648)
2e3ddf5502 Update versions in development builds instructions to 2024 (#5647)
19a8850fb1 [examples] Add TimesliceRobot templates (#3683)
9047682202 [sim] Add XRP-specific plugin (#5631)
575348b81c [wpilib] Use IsSimulation() consistently (#3534)
12e2043b77 [wpilib] Clean up Notifier (#5630)
4bac4dd0f4 [wpimath] Move PIDController from frc2 to frc namespace (#5640)
494cfd78c1 [wpiutil] Fix deprecation warning in LLVM for C++23 (#5642)
43a727e868 [apriltag] Make loadAprilTagFieldLayout throw an unchecked exception instead (#5629)
ad4b017321 [ci] Use Ninja for faster builds (#5626)
4f2114d6f5 Fix warnings from GCC 13 release build (#5637)
e7e927fe26 [build] Also compress debug info for CMake RelWithDebInfo build type (#5638)
205a40c895 [build] Specify zlib for debug info compression (#5636)
707444f000 [apriltag] Suppress -Wtype-limits warning in asserts from GCC 13 (#5635)
3b79cb6ed3 [commands] Revert SubsystemBase deprecation/removal (#5634)
bc7f23a632 [build] Compress Linux debug info (#5633)
57b2d6f254 [build] Update to image 2024 v1.0 (#5625)
339ef1ea39 [wpilib] DataLogManager: Warn user if logging to RoboRIO 1 internal storage (#5617)
7a9a901a73 [build] Fix cmake config files (#5624)
298f8a6e33 [wpilib] Add Mechanism2d tests and make Java impl match C++ (#5527)
d7ef817bae [apriltag] Update apriltag library (#5619)
c3fb31fd0e [docs] Switch to Java 17 api docs (#5613)
bd64f81cf9 [build] Run Google tests in release mode in CI (#5615)
66e6bd81ea [wpimath] Cleanup wpimath/algorithms.md (NFC) (#5621)
4fa56fd884 [build] Add missing find_dependency call (#5623)
f63d958995 [build] Update to native utils 2024.2.0 (#5601)
a9ab08f48b [wpimath] Rename ChassisSpeeds.fromDiscreteSpeeds() to discretize() (#5616)
8e05983a4a [wpimath] Add math docs to plant inversion feedforward internals (NFC) (#5618)
3a33ce918b [ntcore] Add missing StringMap include (#5620)
a6157f184d [wpiutil] timestamp: Add ShutdownNowRio (#5610)
e9f612f581 [build] Guard policy setting for CMake versions below 3.24 (#5612)
1a6df6fec6 [wpimath] Fix DARE Q decomposition (#5611)
9b3f7fb548 [build] Exclude IntelliJ folders from spotless XML (#5602)
814f18c7f5 [wpimath] Fix computation of C for DARE (A, C) detectability check (#5609)
ac23f92451 [hal] Add GetTeamNumber (#5596)
a750bee54d [wpimath] Use std::norm() in IsStabilizable() (#5599)
8e2465f8a0 [wpimath] Add arithmetic functions to wheel speeds classes (#5465)
10d4f5b5df [wpimath] Clean up notation in DARE precondition docs (#5595)
b2dd59450b [hal] Fix unfinished/incorrect GetCPUTemp functions (#5598)
99f66b1e24 [wpimath] Replace frc/EigenCore.h typedefs with Eigen's where possible (#5597)
383289bc4b [build] Make custom CMake macros use lowercase (#5594)
45e7720ec1 [build] Add error message when downloading files in CMake (#5593)
4e0d785356 [wpimath] ChassisSpeeds: document that values aren't relative to the robot (NFC) (#5551)
3c04580a57 [commands] ProxyCommand: Use inner command name in unique_ptr constructor (#5570)
cf19102c4a [commands] SelectCommand: Fix leakage and multiple composition bug (#5571)
171375f440 [ntcoreffi] Link to NI libraries (#5589)
89add5d05b Disable flaky tests (#5591)
a8d4b162ab [ntcore] Remove RPC manual tests (#5590)
39a73b5b58 [commands] C++: Add CommandPtr supplier constructor to ProxyCommand (#5572)
36d514eae7 [commands] Refactor C++ ScheduleCommand to use SmallSet (#5568)
52297ffe29 [commands] Add idle command (#5555)
67043a8eeb [wpimath] Add angular jerk unit (#5582)
51b0fb1492 [wpimath] Fix incorrect header inclusion in angular_acceleration.h (#5587)
b7657a8e28 [wpimath] Split WPIMathJNI into logical chunks (#5552)
ea17f90f87 [build] Fix tool builds with multiple arm platforms installed (#5586)
f1d7b05723 [wpimath] Clean up unit formatter (#5584)
d7264ff597 Replace wpi::errs() usage with fmtlib (#5560)
ab3bf39e0e [wpiutil] Upgrade to fmt 10.1.1 (#5585)
165ebe4c79 Upgrade to fmt 10.1.0 (#5326)
8e2a7fd306 Include thirdparty libraries with angle brackets (#5578)
e322ab8e46 [wpimath] Fix docs for DARE ABQRN stabilizability check (NFC) (#5579)
360fb835f4 [upstream_utils] Handle edge case in filename matches (#5576)
9d86624c00 [build] Fix CMake configure warnings (#5577)
969979d6c7 [wpiutil] Update to foonathan memory 0.7-3 (#5573)
0d2d989e84 [wpimath] Update to gcem 1.17.0 (#5575)
cf86af7166 [wpiutil] Update to mpack 1.1.1 (#5574)
a0c029a35b [commands] Fix dangling SelectCommand documentation (NFC) (#5567)
349141b91b [upstream_utils] Document adding a patch (NFC) (#5432)
7889b35b67 [wpimath] Add RamseteController comparison to LTV controller docs (NFC) (#5559)
b3ef536677 [build] Ignore nt/sim json files in spotless (#5565)
ed895815b5 [build] Compile Java with UTF-8 encoding (#5564)
2e4ad35e36 [wpiutil] jni_util: Add JSpan and CriticalJSpan (#5554)
8f3d6a1d4b [wpimath] Remove discretizeAQTaylor() (#5562)
7c20fa1b18 [wpimath] Refactor DARE tests to reduce RAM usage at compile time (#5557)
89e738262c [ntcore] Limit buffer pool size to 64KB per connection (#5485)
96f7fa662e Upgrade Maven dependencies (#5553)
7a2d336d52 [wpinet] Leak multicast handles during windows shutdown (#5550)
f9e2757d8f [wpimath] Use JDoubleArrayRef in all JNI functions (#5546)
0cf6e37dc1 [wpimath] Make LTV controller constructors use faster DARE solver (#5543)
6953a303b3 [build] Fix the windows build with fmt (#5544)
7a37e3a496 [wpimath] Correct Rotation3d::RotateBy doc comment (NFC) (#5541)
186b409e16 [wpimath] Remove internal Eigen header include (#5539)
03764dfe93 [wpimath] Add static matrix support to DARE solver (#5536)
394cfeadbd [wpimath] Use SDA algorithm instead of SSCA for DARE solver (#5526)
a4b7fde767 [wpilib] Add mechanism specific SetState overloads to physics sims (#5534)
8121566258 [wpimath] Fix CoordinateSystem.convert() Transform3d overload (#5532)
b542e01a0b [glass] Fix array crash when clearing existing workspace (#5535)
e2e1b763b2 [wpigui] Fix PFD file dialogs not closing after window closing (#5530)
86d7bbc4e4 [examples] Add Java Examples and Templates for the XRP (#5529)
e8b5d44752 [wpimath] Make Java Quaternion use doubles instead of Vector (#5525)
38c198fa64 [myRobot] Add apriltags to myRobot build (#5528)
00450c3548 [wpimath] Upgrade to EJML 0.42 (#5531)
faf3cecd83 [wpimath] Don't copy Matrix and underlying storage in VecBuilder (#5524)
6b896a38dc [build] Don't enforce WITH_FLAT_INSTALL with MSVC (part 2) (#5517)
c01814b80e [wpiutil] Add C API for DataLog (#5509)
b5bd0771eb [wpimath] Document extrinsic vs intrinsic rotations (NFC) (#5508)
84ed8aec05 [build] Don't enforce WITH_FLAT_INSTALL with MSVC (#5515)
999f677d8c [ntcoreffi] Add WPI_Impl_SetupNowRio to exported symbols (#5510)
338f37d302 Fix header sorting of libssh (#5507)
75cbd9d6d0 [glass] Add background color selector to glass plots (#5506)
e2c190487b [examples] Add flywheel bang-bang controller example (#4071)
c52dad609e [wpinet] WebSocket: Send pong in response to ping (#5498)
e2d17a24a6 [hal] Expose power rail disable and cpu temp functionality (#5477)
3ad5d2e42d [hal,wpiutil] Use HMB for FPGA Timestamps (#5499)
b46a872494 [ntcore] Remove pImpl from implementation (#5480)
d8c59ccc71 [wpimath] Add tests for MathUtil clamp() and interpolate() (#5501)
0552c8621d [glass,ov] Improve Glass and OutlineViewer title bar message (#5502)
90e37a129f [wpiutil,wpimath] Add generic InterpolatingTreeMap (#5372)
d83a6edc20 [wpilib] Update GetMatchTime docs and units (#5232)
6db2c42966 [wpimath] Trajectory: Throw on empty lists of States (#5497)
21439b606c [wpimath] Disallow LTV controller max velocities above 15 m/s (#5495)
7496e0d208 [ntcore] Value: More efficiently store arrays (#5484)
0c93aded8a [wpimath] Change kinematics.ToTwist2d(end - start) to kinematics.ToTwist2d(start, end) (#5493)
815a8403e5 [wpimath] Give infeasible trajectory constraints a better exception message (#5492)
35a8b129d9 [wpimath] Add RotateBy() function to pose classes (#5491)
26d6e68c8f [upstream_utils] Add GCEM to CI (#5483)
6aa469ae45 [wpilib] Document how to create LinearSystem object for physics sim classes (NFC) (#5488)
a01b6467d3 [wpimath] Link to docs on LQR and KF tolerances (#5486)
d814f1d123 [wpimath] Fix copy-paste error from Pose2d docs (NFC) (#5490)
98f074b072 [wpimath] Add folder prefix to geometry includes (#5489)
e9858c10e9 [glass] Add tooltips for NT settings (#5476)
12dda24f06 [examples] Fix C robot template not correctly looping (#5474)
fc75d31755 [apriltag] Update apriltaglib (#5475)
a95994fff6 [wpiutil] timestamp: Call FPGA functions directly (#5235)
2ba8fbb6f4 [wpimath] Improve documentation for SwerveModulePosition::operator- (#5468)
b8cdf97621 [build] Prepare for Windows arm64 builds (#5390)
552f4b76b5 [wpimath] Add FOC-enabled Falcon constants to the DCMotor class (#5469)
1938251436 [examples] Add Feedforward to ElevatorProfiledPid (#5300)
873c2a6c10 [examples] Update ElevatorTrapezoidProfile example (#5466)
99b88be4f3 [wpilib] Reduce usage of NTSendable (#5434)
d125711023 [hal] Fix Java REVPH faults bitfield (take 2) (#5464)
c3fab7f1f2 [ntcore] Don't update timestamp when value is unchanged (#5356)
5ec7f18bdc [wpilib] EventLoop docs: Remove BooleanEvent references (NFC) (#5463)
c065ae1fcf [wpiunits] Add subproject for a Java typesafe unit system (#5371)
44acca7c00 [wpiutil] Add ClassPreloader (#5365)
88b11832ec [hal] Fix Java REVPH faults bitfield (#5148)
fb57d82e52 [ntcore] Enhance Java raw value support
3a6e40a44b [wpiutil] Enhance DataLog Java raw value support
8dae5af271 [wpiutil] Add compile-time string utilities (ct_string) (#5462)
fc56f8049a [wpilib] DriverStation: Change alliance station to use optional (#5229)
ef155438bd [build] Consume libuv via cmake config instead of via pkg-config (#5438)
86e91e6724 [wpimath] Refactor TrapezoidProfile API (#5457)
72a4543493 [wpilib] DutyCycleEncoderSim: Expand API (#5443)
657338715d [wpimath] Add ChassisSpeeds method to fix drifting during compound swerve drive maneuvers (#5425)
1af224c21b Add missing <functional> includes (#5459)
0b91ca6d5a [wpilib] SendableChooser: Add onChange listener (#5458)
6f7cdd460e [wpimath] Pose3d: Switch to JNI for exp and log (#5444)
c69e34c80c [wpimath] ChassisSpeeds: Add arithmetic functions (#5293)
335e7dd89d [wpilib] Simulation: Add ctor parameter to set starting state of mechanism sims (#5288)
14f30752ab [wpilib] Deprecate Accelerometer and Gyro interfaces (#5445)
70b60e3a74 [commands] Trigger: Fix method names in requireNonNullParam (#5454)
593767c8c7 [wpimath] Improve Euler angle calculations in gimbal lock (#5437)
daf022d3da [build] Make devImplementation inherit from implementation (#5450)
9b8d90b852 [examples] Convert the unitless joystick inputs to actual physical units (#5451)
1f6428ab63 [ntcore] Fix undefined comparison behavior when array is empty (#5448)
17eb9161cd Update code owners for removal of old commands (#5447)
3c4b58ae1e [wpinet] Upgrade to libuv 1.46.0 (#5446)
aaea85ff16 [commands] Merge CommandBase into Command and SubsystemBase into Subsystem (#5392)
7ac932996a [ci] Use PAT for workflow dispatch (#5442)
efe1987e8b [ci] Trigger pages repo workflow (#5441)
828bc5276f [wpiutil] Upgrade to LLVM 16.0.6 (#5435)
701df9eb87 [ci] Change documentation publish to single-commit (#5440)
e5452e3f69 [wpiutil] Add WPICleaner and an example how to use it (#4850)
7a099cb02a [commands] Remove deprecated classes and functions (#5409)
b250a03944 [wpilib] Add function to wait for DS Connection (#5230)
a6463ed761 [wpiutil] Fix unused variable warning in release build (#5430)
f031513470 [ntcore] NetworkTable::GetSubTables(): Remove duplicates (#5076)
f8e74e2f7c [hal] Unify PWM simulation Speed, Position, and Raw (#5277)
fd5699b240 Remove references to Drake (#5427)
e2d385d80a [build] cmake: Respect USE_SYSTEM_FMTLIB (#5429)
d37f990ce3 [hal] Fix HAL Relay/Main doc module (NFC) (#5422)
a7a8b874ac [docs] Expand HAL_ENUM in doxygen docs (#5421)
3a61deedde [wpimath] Rotation2d: Only use gcem::hypot when constexpr evaluated (#5419)
96145de7db [examples] Fix formatting (NFC) (#5420)
fffe6a7b9a [examples] Improve Pneumatics example coverage in Solenoid and RapidReactCmdBot examples (#4998)
6b5817836d [wpimath] Add tolerance for some tests (#5416)
3233883f3e [cscore] Fix warnings on macos arm (#5415)
c4fc21838f [commands] Add ConditionalCommand getInterruptionBehavior (#5161)
89fc51f0d4 Add tests for SendableChooser and Command Sendable functionality (#5179)
663bf25aaf [docs] Generate docs for symbols in __cplusplus (#5412)
fe32127ea8 [command] Clean up Command doc comments (NFC) (#5321)
c1a01569b4 [wpilib][hal] PWM Raw using microseconds (#5283)
1fca519fb4 [wpiutil] Remove remnants of ghc fs and tcb_span libraries (#5411)
90602cc135 [github] Update issue template to collect more project info (#5090)
34412ac57e [build] Exclude files in bin from Spotless (#5410)
61aa60f0e3 [wpilib] Add robot callback that is called when the DS is initially connected (#5231)
ebae341a91 [commands] Add test for subsystem registration and periodic (#5408)
5d3a133f9f Remove spaces in NOLINT comments (#5407)
3a0e484691 [wpimath] Fix clang-tidy warnings (#5403)
eb3810c765 [wpiutil] Fix clang-tidy warnings (#5406)
c4dc697192 [hal] WS Simulation: Add message filtering capability (#5395)
0eccc3f247 [ntcore] Fix clang-tidy warnings (#5405)
f4dda4bac0 [hal] Add javadocs for JNI (NFC) (#5298)
1c20c69793 [cscore] Fix clang-tidy warnings (#5404)
1501607e48 [commands] Fix clang-tidy warnings (#5402)
991f4b0f62 [wpimath] PIDController: Add IZone (#5315)
f5b0d1484b [wpimath] Add isNear method to MathUtil (#5353)
2ce248f66c [hal] Fix clang-tidy warnings (#5401)
5fc4aee2d2 [wpimath] SwerveDriveKinematics: Rename currentChassisSpeed to desiredChassisSpeed (#5393)
50b90ceb54 [wpimath] SwerveDriveKinematics: Add reset method (#5398)
316cd2a453 [commands] Notify DriverStationSim in CommandTestBaseWithParam (#5400)
d4ea5fa902 [cscore] VideoMode: Add equals override (Java) (#5397)
d6bd72d738 [wpimath] ProfiledPIDController: Add getConstraints (#5399)
25ad5017a9 [wpimath] Refactor kinematics, odometry, and pose estimator (#5355)
5c2addda0f [doc] Add missing pneumatics docs (NFC) (#5389)
c3e04a6ea2 Fix loading tests on macos 12 (#5388)
d5ed9fb859 [wpimath] Create separate archive with just units headers (#5383)
901ab693d4 [wpimath] Use UtilityClassTest for more utility classes (#5384)
9d53231b01 [wpilib] DataLogManager: Add warning for low storage space (#5364)
d466933963 [wpiutil] Group doxygen into MPack module (#5380)
652d1c44e3 [wpiutil] Upgrade to macOS 12 to remove concept shims (#5379)
6414be0e5d [wpimath] Group units doxygen modules (#5382)
7ab5800487 [wpiutil] Fix docs typo in SmallVector (#5381)
59905ea721 Replace WPI_DEPRECATED() macro with [[deprecated]] attribute (#5373)
753cb49a5e [ntcore] Fix doxygen module in generated C types (NFC) (#5374)
1c00a52b67 [hal] Expose CAN timestamp base clock (#5357)
91cbcea841 Replace SFINAE with concepts (#5361)
d57d1a4598 [wpimath] Remove unnecessary template argument from unit formatter (#5367)
5acc5e22aa [wpimath] Only compute eigenvalues with EigenSolvers (#5369)
d3c9316a97 extend shuffleboard test timeout (#5377)
1ea868081a [ci] Fix /format command (#5376)
5fac18ff4a Update formatting to clang-format 16 (#5370)
a94a998002 [wpimath] Generalize Eigen formatter (#5360)
125f6ea101 [wpimath] Make SwerveDriveKinematics::ToChassisSpeeds() take const-ref argument (#5363)
51066a5a8a [wpimath] Move unit formatters into units library (#5358)
282c032b60 [wpilibc] Add unit-aware Joystick.GetDirection() (#5319)
073d19cb69 [build] Fix CMake warning (#5359)
01490fc77b [wpiutil] DataLog: Add documentation for append methods (NFC) (#5348)
c9b612c986 [wpilibcExamples] Make C++ state-space elevator KF and LQR match Java (#5346)
eed1e6e3cb [wpimath] Replace DiscretizeAQTaylor() with DiscretizeAQ() (#5344)
c976f40364 [readme] Document how to run examples in simulation (#5340)
4d28bdc19e [ci] Update Github Pages deploy action parameters (#5343)
e0f851871f [ci] Fix github pages deploy version (#5342)
063c8cbedc Run wpiformat (NFC) (#5341)
96e41c0447 [ci] Update deploy and sshagent actions (#5338)
fd294bdd71 [build] Fix compilation with GCC 13 (#5322)
d223e4040b [dlt] Add delete without download functionality (#5329)
abc19bcb43 [upstream_utils] Zero out commit hashes and show 40 digits in index hashes (#5336)
e909f2e687 [build] Update gradle cache repo name (#5334)
52bd5b972d [wpimath] Rewrite DARE solver (#5328)
3876a2523a [wpimath] Remove unused MatrixImpl() function (#5330)
c82fcb1975 [wpiutil] Add reflection based cleanup helper (#4919)
15ba95df7e [wpiutil] Use std::filesystem (#4941)
77c2124fc5 [wpimath] Remove Eigen's custom STL types (#4945)
27fb47ab10 [glass] Field2D: Embed standard field images (#5159)
102e4f2566 [wpilib] Remove deprecated and broken SPI methods (#5249)
463a90f1df [wpilib, hal] Add function to read the RSL state (#5312)
7a90475eec [wpilib] Update RobotBase documentation (NFC) (#5320)
218cfea16b [wpilib] DutyCycleEncoder: Fix reset behavior (#5287)
91392823ff [build] Update to gradle 8.1 (#5303)
258b7cc48b [wpilibj] Filesystem.getDeployDirectory(): Strip JNI path from user.dir (#5317)
26cc43bee1 [wpilib] Add documentation to SPI mode enum (NFC) (#5324)
ac4da9b1cb [hal] Add HAL docs for Addressable LED (NFC) (#5304)
21d4244cf7 [wpimath] Fix DCMotor docs (NFC) (#5309)
1dff81bea7 [hal] Miscellaneous HAL doc fixes (NFC) (#5306)
7ce75574bf [wpimath] Upgrade to Drake v1.15.0 (#5310)
576bd646ae [hal] Add CANManufacturer for Redux Robotics (#5305)
ee3b4621e5 [commands] Add onlyWhile and onlyIf (#5291)
40ca094686 [commands] Fix RepeatCommand calling end() twice (#5261)
9cbeb841f5 [rtns] Match imaging tool capitalization (#5265)
a63d06ff77 [examples] Add constants to java gearsbot example (#5248)
b6c43322a3 [wpilibc] XboxController: Add return tag to docs (NFC) (#5246)
5162d0001c [hal] Fix and document addressable LED timings (#5272)
90fabe9651 [wpilibj] Use method references in drive class initSendable() (#5251)
24828afd11 [wpimath] Fix desaturateWheelSpeeds to account for negative speeds (#5269)
e099948a77 [wpimath] Clean up rank notation in docs (NFC) (#5274)
fd2d8cb9c1 [hal] Use std::log2() for base-2 logarithm (#5278)
ba8c64bcff [wpimath] Fix misspelled Javadoc parameters in pose estimators (NFC) (#5292)
f53c6813d5 [wpimath] Patch Eigen warnings (#5290)
663703d370 [gitattributes] Mark json files as lf text files (#5256)
aa34aacf6e [wpilib] Shuffleboard: Keep duplicates on SelectTab() (#5198)
63512bbbb8 [wpimath] Fix potential divide-by-zero in RKDP (#5242)
9227b2166e [wpilibj] DriverStation: Fix joystick data logs (#5240)
fbf92e9190 [wpinet] ParallelTcpConnector: don't connect to duplicate addresses (#5169)
2108a61362 [ntcore] NT4 client: close timed-out connections (#5175)
0a66479693 [ntcore] Optimize scan of outgoing messages (#5227)
b510c17ef6 [hal] Fix RobotController.getComments() mishandling quotes inside the comments string (#5197)
e7a7eb2e93 [commands] WaitCommand: Remove subclass doc note (NFC) (#5200)
a465f2d8f0 [examples] Shuffleboard: Correct parameter order (#5204)
a3364422fa LICENSE.md: Bump year to 2023 (#5195)
df3242a40a [wpimath] Fix NaN in C++ MakeCostMatrix() that takes an array (#5194)
00abb8c1e0 [commands] RamseteCommand: default-initialize m_prevSpeeds (#5188)
c886273fd7 [wpilibj] DutyCycleEncoder.setDistancePerRotation(): fix simulation (#5147)
53b5fd2ace [ntcore] Use int64 for datalog type string (#5186)
56b758320f [wpilib] DataLogManager: increase time for datetime to be valid (#5185)
08f298e4cd [wpimath] Fix Pose3d log returning Twist3d NaN for theta between 1E-8 and 1E-7 (#5168)
6d0c5b19db [commands] CommandScheduler.isComposed: Remove incorrect throws clause (NFC) (#5183)
0d22cf5ff7 [wpilib] Fix enableLiveWindowInTest crashing in disabled (#5173)
32ec5b3f75 [wpilib] Add isTestEnabled and minor docs cleanup (#5172)
e5c4c6b1a7 [wpimath] Fix invalid iterator access in TimeInterpolatableBuffer (#5138)
099d048d9e [wpimath] Fix Pose3d log returning Twist3d NaN for theta between 1E-9 and 1E-8 (#5143)
4af84a1c12 Fix Typos (NFC) (#5137)
ce3686b80d [wpimath] Check LTV controller max velocity precondition (#5142)
4b0eecaee0 [commands] Subsystem: Add default command removal method (#5064)
edf4ded412 [wpilib] PH: Revert to 5V rail being fixed 5V (#5122)
4c46b6aff9 [wpilibc] Fix DataLogManager crash on exit in sim (#5125)
490ca4a68a [wpilibc] Fix XboxController::GetBackButton doc (NFC) (#5131)
cbb5b0b802 [hal] Simulation: Fix REV PH solenoids 8+ (#5132)
bb7053d9ee [hal] Fix HAL_GetRuntimeType being slow on the roboRIO (#5130)
9efed9a533 Update .clang-format to c++20 (#5121)
dbbfe1aed2 [wpilib] Use PH voltage to calc Analog pressure switch threshold (#5115)
de65a135c3 [wpilib] DutyCycleEncoderSim: Add channel number constructor (#5118)
3e9788cdff [docs] Strip path from generated NT docs (#5119)
ecb072724d [ntcore] Client::Disconnect(): actually close connection (#5113)
0d462a4561 [glass] NT view: Change string/string array to quoted (#5111)
ba37986561 [ntcore] NetworkClient::Disconnect: Add null check (#5112)
25ab9cda92 [glass,ov] Provide menu item to create topic from root (#5110)
2f6251d4a6 [glass] Set default value when publishing new topic (#5109)
e9a7bed988 [wpimath] Add timestamp getter to MathShared (#5091)
9cc14bbb43 [ntcore] Add stress test to dev executable (#5107)
8068369542 [wpinet] uv: Stop creating handles when closing loop (#5102)
805c837a42 [ntcore] Fix use-after-free in server (#5101)
fd18577ba0 [commands] Improve documentation of addRequirements (NFC) (#5103)
74dea9f05e [wpimath] Fix exception for empty pose buffer in pose estimators (#5106)
9eef79d638 [wpilib] PneumaticHub: Document range of enableCompressorAnalog (NFC) (#5099)
843574a810 [ntcore] Use wpi::Now instead of loop time for transmit time
226ef35212 [wpinet] WebSocket: Reduce server send frame overhead
b30664d630 [ntcore] Reduce initial connection overhead
804e5ce236 [examples] MecanumDrive: Fix axis comment in C++ example (NFC) (#5096)
49af88f2bb [examples] ArmSimulation: Fix flaky test (#5093)
d56314f866 [wpiutil] Disable mock time on the Rio (#5092)
43975ac7cc [examples] ArmSimulation, ElevatorSimulation: Extract mechanism to class (#5052)
5483464158 [examples, templates] Improve descriptions (NFC) (#5051)
785e7dd85c [wpilibc] SendableChooser: static_assert copy- and default-constructibility (#5078)
e57ded8c39 [ntcore] Improve disconnect error reporting (#5085)
01f0394419 [wpinet] Revert WebSocket: When Close() is called, call closed immediately (#5084)
59be120982 [wpimath] Fix Pose3d exp()/log() and add rotation vector constructor to Rotation3d (#5072)
37f065032f [wpilib] Refactor TimedRobot tests (#5068)
22a170bee7 [wpilib] Add Notifier test (#5070)
2f310a748c [wpimath] Fix DCMotor.getSpeed() (#5061)
b43ec87f57 [wpilib] ElevatorSim: Fix WouldHitLimit methods (#5057)
19267bef0c [ntcore] Output warning on property set on unpublished topic (#5059)
84cbd48d84 [ntcore] Handle excludeSelf on SetDefault (#5058)
1f35750865 [cameraserver] Add GetInstance() to all functions (#5054)
8230fc631d [wpilib] Revert throw on nonexistent SimDevice name in SimDeviceSim (#5053)
b879a6f8c6 [wpinet] WebSocket: When Close() is called, call closed immediately (#5047)
49459d3e45 [ntcore] Change wire timeout to fixed 1 second (#5048)
4079eabe9b [wpimath] Discard stale pose estimates (#5045)
fe5d226a19 [glass] Fix option for debug-level NT logging (#5049)
b7535252c2 [ntcore] Don't leak buffers in rare WS shutdown case (#5046)
b61ac6db33 [ntcore] Add client disconnect function (#5022)
7b828ce84f [wpimath] Add nearest to Pose2d and Translation2d (#4882)
08a536291b [examples] Improvements to Elevator Simulation Example (#4937)
193a10d020 [wpigui] Limit frame rate to 120 fps by default (#5030)
7867bbde0e [wpilib] Clarify DS functions provided by FMS (NFC) (#5043)
fa7c01b598 [glass] Add option for debug-level NT logging (#5007)
2b81610248 [wpiutil] Add msgpack to datalog Python example (#5032)
a4a369b8da CONTRIBUTING.md: Add unicodeit CLI to math docs guidelines (#5031)
d991f6e435 [wpilib] Throw on nonexistent SimDevice name in SimDeviceSim constructor (#5041)
a27a047ae8 [hal] Check for null in getSimDeviceName JNI (#5038)
2f96cae31a [examples] Hatchbots: Add telemetry (#5011)
83ef8f9658 [simulation] GUI: Fix buffer overflow in joystick axes copy (#5036)
4054893669 [commands] Fix C++ Select() factory (#5024)
f75acd11ce [commands] Use Timer.restart() (#5023)
8bf67b1b33 [wpimath] PIDController::Calculate(double, double): update setpoint flag (#5021)
49bb1358d8 [wpiutil] MemoryBuffer: Fix GetMemoryBufferForStream (#5017)
9c4c07c0f9 [wpiutil] Remove NDEBUG check for debug-level logging (#5018)
1a47cc2e86 [ntcore] Use full handle when subscribing (#5013)
7cd30cffbc Ignore networktables.json (#5006)
92aecab2ef [commands] Command controllers are not subclasses (NFC) (#5000)
8785bba080 [ntcore] Special-case default timestamps (#5003)
9e5b7b8040 [ntcore] Handle topicsonly followed by value subscribe (#4991)
917906530a [wpilib] Add Timer::Restart() (#4963)
00aa66e4fd [wpimath] Remove extraneous assignments from DiscretizeAB() (#4967)
893320544a [examples] C++ RamseteCommand: Fix units (#4954)
b95d0e060d [wpilib] XboxController: Fix docs discrepancy (NFC) (#4993)
008232b43c [ntcore] Write empty persistent file if none found (#4996)
522be348f4 [examples] Rewrite tags (NFC) (#4961)
d48a83dee2 [wpimath] Update Wikipedia links for quaternion to Euler angle conversion (NFC) (#4995)
504fa22143 [wpimath] Workaround intellisense Eigen issue (#4992)
b2b25bf09f [commands] Fix docs inconsistency for toggleOnFalse(Command) (NFC) (#4978)
ce3dc4eb3b [hal] Properly use control word that is in sync with DS data (#4989)
1ea48caa7d [wpilib] Fix C++ ADXRS450 and Java SPI gyro defs (#4988)
fb101925a7 [build] Include wpimathjni in commands binaries (#4981)
657951f6dd [starter] Add a process starter for use by the installer for launching tools (#4931)
a60ca9d71c [examples] Update AprilTag field load API usage (#4975)
f8a45f1558 [wpimath] Remove print statements from tests (#4977)
ecba8b99a8 [examples] Fix swapped arguments in MecanumControllerCommand example (#4976)
e95e88fdf9 [examples] Add comment to drivedistanceoffboard example (#4877)
371d15dec3 [examples] Add Computer Vision Pose Estimation and Latency Compensation Example (#4901)
cb9b8938af [sim] Enable docking in the GUI (#4960)
3b084ecbe0 [apriltag] AprilTagFieldLayout: Improve API shape for loading builtin JSONs (#4949)
27ba096ea1 [wpilib] Fix MOI calculation error in SingleJointedArmSim (#4968)
42c997a3c4 [wpimath] Fix Pose3d exponential and clean up Pose3d logarithm (#4970)
5f1a025f27 [wpilibj] Fix typo in MecanumDrive docs (NFC) (#4969)
0ebf79b54c [wpimath] Fix typo in Pose3d::Exp() docs (NFC) (#4966)
a8c465f3fb [wpimath] HolonomicDriveController: Add getters for the controllers (#4948)
a7b1ab683d [wpilibc] Add unit test for fast deconstruction of GenericHID (#4953)
bd6479dc29 [build] Add Spotless for JSON (#4956)
5cb0340a8c [hal, wpilib] Load joystick values upon code initialization (#4950)
ab0e8c37a7 [readme] Update build requirements (NFC) (#4947)
b74ac1c645 [build] Add apriltag to C++ cmake example builds (#4944)
cf1a411acf [examples] Add example programs for AprilTags detection (#4932)
1e05b21ab5 [wpimath] Fix PID atSetpoint to not return true prematurely (#4906)
e5a6197633 [wpimath] Fix SwerveDriveKinematics not initializing a new array each time (#4942)
039edcc23f [ntcore] Queue current value on subscriber creation (#4938)
f7f19207e0 [wpimath] Allow multiple vision measurements from same timestamp (#4917)
befd12911c [commands] Delete UB-causing rvalue variants of CommandPtr methods (#4923)
34519de60a [commands] Fix spacing in command composition exception (#4924)
dc4355c031 [hal] Add handle constructor and name getters for sim devices (#4925)
53d8d33bca [hal, wpilibj] Add missing distance per pulse functions to EncoderSim (#4928)
530ae40614 [apriltag] Explain what April tag poses represent (NFC) (#4930)
79f565191e [examples] DigitalCommunication, I2CCommunication: Add tests (#4865)
2cd9be413f [wpilib, examples] Cleanup PotentiometerPID, Ultrasonic, UltrasonicPID examples (#4893)
babb0c1fcf [apriltag] Add 2023 field layout JSON (#4912)
330ba45f9c [wpimath] Fix swerve kinematics util classes equals function (#4907)
51272ef6b3 [fieldImages] Add 2023 field (#4915)
0d105ab771 [commands] Deduplicate command test utils (#4897)
cf4235ea36 [wpiutil] Guard MSVC pragma in SymbolExports.h (#4911)
2d4b7b9147 [build] Update opencv version in opencv.gradle (#4909)
aec6f3d506 [ntcore] Fix client flush behavior (#4903)
bfe346c76a [build] Fix cmake java resources (#4898)
Change-Id: Ia1dd90fe42c6cd5df281b8a5b710e136f54355f4
git-subtree-dir: third_party/allwpilib
git-subtree-split: f1a82828fed8950f9a3f1586c44327027627a0c8
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/wpilibNewCommands/.styleguide b/wpilibNewCommands/.styleguide
index 3f20ec8..7c8d7a7 100644
--- a/wpilibNewCommands/.styleguide
+++ b/wpilibNewCommands/.styleguide
@@ -17,6 +17,7 @@
^cscore
^fmt/
^frc/
+ ^gtest/
^hal/
^imgui
^mockdata/
diff --git a/wpilibNewCommands/CMakeLists.txt b/wpilibNewCommands/CMakeLists.txt
index 716c508..34a6bb1 100644
--- a/wpilibNewCommands/CMakeLists.txt
+++ b/wpilibNewCommands/CMakeLists.txt
@@ -22,8 +22,22 @@
else()
set (wpilibNewCommands_config_dir share/wpilibNewCommands)
endif()
+endif()
- install(FILES wpilibNewCommands-config.cmake DESTINATION ${wpilibNewCommands_config_dir})
+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)
@@ -39,10 +53,10 @@
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
$<INSTALL_INTERFACE:${include_dest}/wpilibNewCommands>)
-install(TARGETS wpilibNewCommands EXPORT wpilibNewCommands DESTINATION "${main_lib_dest}")
+install(TARGETS wpilibNewCommands EXPORT wpilibNewCommands)
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/wpilibNewCommands")
-if (MSVC OR FLAT_INSTALL_WPILIB)
+if (FLAT_INSTALL_WPILIB)
set(wpilibNewCommands_config_dir ${wpilib_dest})
else()
set(wpilibNewCommands_config_dir share/wpilibNewCommands)
diff --git a/wpilibNewCommands/WPILibNewCommands.json b/wpilibNewCommands/WPILibNewCommands.json
index da4bc52..67bf389 100644
--- a/wpilibNewCommands/WPILibNewCommands.json
+++ b/wpilibNewCommands/WPILibNewCommands.json
@@ -1,37 +1,38 @@
-{
- "fileName": "WPILibNewCommands.json",
- "name": "WPILib-New-Commands",
- "version": "1.0.0",
- "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
- "mavenUrls": [],
- "jsonUrl": "",
- "javaDependencies": [
- {
- "groupId": "edu.wpi.first.wpilibNewCommands",
- "artifactId": "wpilibNewCommands-java",
- "version": "wpilib"
- }
- ],
- "jniDependencies": [],
- "cppDependencies": [
- {
- "groupId": "edu.wpi.first.wpilibNewCommands",
- "artifactId": "wpilibNewCommands-cpp",
- "version": "wpilib",
- "libName": "wpilibNewCommands",
- "headerClassifier": "headers",
- "sourcesClassifier": "sources",
- "sharedLibrary": true,
- "skipInvalidPlatforms": true,
- "binaryPlatforms": [
- "linuxathena",
- "linuxarm32",
- "linuxarm64",
- "windowsx86-64",
- "windowsx86",
- "linuxx86-64",
- "osxuniversal"
- ]
- }
- ]
-}
+{
+ "fileName": "WPILibNewCommands.json",
+ "name": "WPILib-New-Commands",
+ "version": "1.0.0",
+ "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
+ "frcYear": "2024",
+ "mavenUrls": [],
+ "jsonUrl": "",
+ "javaDependencies": [
+ {
+ "groupId": "edu.wpi.first.wpilibNewCommands",
+ "artifactId": "wpilibNewCommands-java",
+ "version": "wpilib"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": [
+ {
+ "groupId": "edu.wpi.first.wpilibNewCommands",
+ "artifactId": "wpilibNewCommands-cpp",
+ "version": "wpilib",
+ "libName": "wpilibNewCommands",
+ "headerClassifier": "headers",
+ "sourcesClassifier": "sources",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "linuxathena",
+ "linuxarm32",
+ "linuxarm64",
+ "windowsx86-64",
+ "windowsx86",
+ "linuxx86-64",
+ "osxuniversal"
+ ]
+ }
+ ]
+}
diff --git a/wpilibNewCommands/build.gradle b/wpilibNewCommands/build.gradle
index 82fc470..d60fcde 100644
--- a/wpilibNewCommands/build.gradle
+++ b/wpilibNewCommands/build.gradle
@@ -1,6 +1,6 @@
ext {
nativeName = 'wpilibNewCommands'
- devMain = 'edu.wpi.first.wpilibj.commands.DevMain'
+ devMain = 'edu.wpi.first.wpilibj2.commands.DevMain'
}
evaluationDependsOn(':ntcore')
@@ -21,13 +21,6 @@
implementation project(':hal')
implementation project(':wpimath')
implementation project(':wpilibj')
- devImplementation project(':wpiutil')
- devImplementation project(':wpinet')
- devImplementation project(':ntcore')
- devImplementation project(':cscore')
- devImplementation project(':hal')
- devImplementation project(':wpimath')
- devImplementation project(':wpilibj')
testImplementation 'org.mockito:mockito-core:4.1.0'
}
@@ -67,6 +60,7 @@
project(':ntcore').addNtcoreJniDependency(it)
lib project: ':wpinet', library: 'wpinetJNIShared', linkage: 'shared'
lib project: ':wpiutil', library: 'wpiutilJNIShared', linkage: 'shared'
+ lib project: ':wpimath', library: 'wpimathJNIShared', linkage: 'shared'
project(':hal').addHalJniDependency(it)
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Command.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Command.java
index 0383099..a913b55 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Command.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Command.java
@@ -7,6 +7,10 @@
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.util.function.BooleanConsumer;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.util.HashSet;
import java.util.Set;
import java.util.function.BooleanSupplier;
@@ -20,12 +24,19 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public interface Command {
+public abstract class Command implements Sendable {
+ protected Set<Subsystem> m_requirements = new HashSet<>();
+
+ protected Command() {
+ String name = getClass().getName();
+ SendableRegistry.add(this, name.substring(name.lastIndexOf('.') + 1));
+ }
+
/** The initial subroutine of a command. Called once when the command is initially scheduled. */
- default void initialize() {}
+ public void initialize() {}
/** The main body of a command. Called repeatedly while the command is scheduled. */
- default void execute() {}
+ public void execute() {}
/**
* The action to take when the command ends. Called when either the command finishes normally, or
@@ -36,7 +47,7 @@
*
* @param interrupted whether the command was interrupted/canceled
*/
- default void end(boolean interrupted) {}
+ public void end(boolean interrupted) {}
/**
* Whether the command has finished. Once a command finishes, the scheduler will call its end()
@@ -44,7 +55,7 @@
*
* @return whether the command has finished.
*/
- default boolean isFinished() {
+ public boolean isFinished() {
return false;
}
@@ -60,12 +71,67 @@
* @return the set of subsystems that are required
* @see InterruptionBehavior
*/
- Set<Subsystem> getRequirements();
+ public Set<Subsystem> getRequirements() {
+ return m_requirements;
+ }
+
+ /**
+ * Adds the specified subsystems to the requirements of the command. The scheduler will prevent
+ * two commands that require the same subsystem from being scheduled simultaneously.
+ *
+ * <p>Note that the scheduler determines the requirements of a command when it is scheduled, so
+ * this method should normally be called from the command's constructor.
+ *
+ * @param requirements the requirements to add
+ */
+ public final void addRequirements(Subsystem... requirements) {
+ for (Subsystem requirement : requirements) {
+ m_requirements.add(requireNonNullParam(requirement, "requirement", "addRequirements"));
+ }
+ }
+
+ /**
+ * Gets the name of this Command.
+ *
+ * <p>By default, the simple class name is used. This can be changed with {@link
+ * #setName(String)}.
+ *
+ * @return The display name of the Command
+ */
+ public String getName() {
+ return SendableRegistry.getName(this);
+ }
+
+ /**
+ * Sets the name of this Command.
+ *
+ * @param name The display name of the Command.
+ */
+ public void setName(String name) {
+ SendableRegistry.setName(this, name);
+ }
+
+ /**
+ * Gets the subsystem name of this Command.
+ *
+ * @return Subsystem name
+ */
+ public String getSubsystem() {
+ return SendableRegistry.getSubsystem(this);
+ }
+
+ /**
+ * Sets the subsystem name of this Command.
+ *
+ * @param subsystem subsystem name
+ */
+ public void setSubsystem(String subsystem) {
+ SendableRegistry.setSubsystem(this, subsystem);
+ }
/**
* Decorates this command with a timeout. If the specified timeout is exceeded before the command
- * finishes normally, the command will be interrupted and un-scheduled. Note that the timeout only
- * applies to the command returned by this method; the calling command is not itself changed.
+ * finishes normally, the command will be interrupted and un-scheduled.
*
* <p>Note: This decorator works by adding this command to a composition. The command the
* decorator was called on cannot be scheduled independently or be added to a different
@@ -76,15 +142,13 @@
* @param seconds the timeout duration
* @return the command with the timeout added
*/
- default ParallelRaceGroup withTimeout(double seconds) {
+ public ParallelRaceGroup withTimeout(double seconds) {
return raceWith(new WaitCommand(seconds));
}
/**
* Decorates this command with an interrupt condition. If the specified condition becomes true
- * before the command finishes normally, the command will be interrupted and un-scheduled. Note
- * that this only applies to the command returned by this method; the calling command is not
- * itself changed.
+ * before the command finishes normally, the command will be interrupted and un-scheduled.
*
* <p>Note: This decorator works by adding this command to a composition. The command the
* decorator was called on cannot be scheduled independently or be added to a different
@@ -94,16 +158,15 @@
*
* @param condition the interrupt condition
* @return the command with the interrupt condition added
+ * @see #onlyWhile(BooleanSupplier)
*/
- default ParallelRaceGroup until(BooleanSupplier condition) {
+ public ParallelRaceGroup until(BooleanSupplier condition) {
return raceWith(new WaitUntilCommand(condition));
}
/**
- * Decorates this command with an interrupt condition. If the specified condition becomes true
- * before the command finishes normally, the command will be interrupted and un-scheduled. Note
- * that this only applies to the command returned by this method; the calling command is not
- * itself changed.
+ * Decorates this command with a run condition. If the specified condition becomes false before
+ * the command finishes normally, the command will be interrupted and un-scheduled.
*
* <p>Note: This decorator works by adding this command to a composition. The command the
* decorator was called on cannot be scheduled independently or be added to a different
@@ -111,13 +174,12 @@
* commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
* returned from this method can be further decorated without issue.
*
- * @param condition the interrupt condition
- * @return the command with the interrupt condition added
- * @deprecated Replace with {@link #until(BooleanSupplier)}
+ * @param condition the run condition
+ * @return the command with the run condition added
+ * @see #until(BooleanSupplier)
*/
- @Deprecated(since = "2023")
- default ParallelRaceGroup withInterrupt(BooleanSupplier condition) {
- return until(condition);
+ public ParallelRaceGroup onlyWhile(BooleanSupplier condition) {
+ return until(() -> !condition.getAsBoolean());
}
/**
@@ -133,7 +195,7 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- default SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) {
+ public SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) {
return beforeStarting(new InstantCommand(toRun, requirements));
}
@@ -149,7 +211,7 @@
* @param before the command to run before this one
* @return the decorated command
*/
- default SequentialCommandGroup beforeStarting(Command before) {
+ public SequentialCommandGroup beforeStarting(Command before) {
return new SequentialCommandGroup(before, this);
}
@@ -166,7 +228,7 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- default SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) {
+ public SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) {
return andThen(new InstantCommand(toRun, requirements));
}
@@ -183,7 +245,7 @@
* @param next the commands to run next
* @return the decorated command
*/
- default SequentialCommandGroup andThen(Command... next) {
+ public SequentialCommandGroup andThen(Command... next) {
SequentialCommandGroup group = new SequentialCommandGroup(this);
group.addCommands(next);
return group;
@@ -203,7 +265,7 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- default ParallelDeadlineGroup deadlineWith(Command... parallel) {
+ public ParallelDeadlineGroup deadlineWith(Command... parallel) {
return new ParallelDeadlineGroup(this, parallel);
}
@@ -221,7 +283,7 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- default ParallelCommandGroup alongWith(Command... parallel) {
+ public ParallelCommandGroup alongWith(Command... parallel) {
ParallelCommandGroup group = new ParallelCommandGroup(this);
group.addCommands(parallel);
return group;
@@ -241,35 +303,13 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- default ParallelRaceGroup raceWith(Command... parallel) {
+ public ParallelRaceGroup raceWith(Command... parallel) {
ParallelRaceGroup group = new ParallelRaceGroup(this);
group.addCommands(parallel);
return group;
}
/**
- * Decorates this command to run perpetually, ignoring its ordinary end conditions. The decorated
- * command can still be interrupted or canceled.
- *
- * <p>Note: This decorator works by adding this command to a composition. The command the
- * decorator was called on cannot be scheduled independently or be added to a different
- * composition (namely, decorators), unless it is manually cleared from the list of composed
- * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
- * returned from this method can be further decorated without issue.
- *
- * @return the decorated command
- * @deprecated PerpetualCommand violates the assumption that execute() doesn't get called after
- * isFinished() returns true -- an assumption that should be valid. This was unsafe/undefined
- * behavior from the start, and RepeatCommand provides an easy way to achieve similar end
- * results with slightly different (and safe) semantics.
- */
- @SuppressWarnings("removal") // PerpetualCommand
- @Deprecated(forRemoval = true, since = "2023")
- default PerpetualCommand perpetually() {
- return new PerpetualCommand(this);
- }
-
- /**
* Decorates this command to run repeatedly, restarting it when it ends, until this command is
* interrupted. The decorated command can still be canceled.
*
@@ -281,7 +321,7 @@
*
* @return the decorated command
*/
- default RepeatCommand repeatedly() {
+ public RepeatCommand repeatedly() {
return new RepeatCommand(this);
}
@@ -292,7 +332,7 @@
*
* @return the decorated command
*/
- default ProxyCommand asProxy() {
+ public ProxyCommand asProxy() {
return new ProxyCommand(this);
}
@@ -301,20 +341,46 @@
* running and the condition changes to true, the command will not stop running. The requirements
* of this command will be kept for the new conditional command.
*
+ * <p>Note: This decorator works by adding this command to a composition. The command the
+ * decorator was called on cannot be scheduled independently or be added to a different
+ * composition (namely, decorators), unless it is manually cleared from the list of composed
+ * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
+ * returned from this method can be further decorated without issue.
+ *
* @param condition the condition that will prevent the command from running
* @return the decorated command
+ * @see #onlyIf(BooleanSupplier)
*/
- default ConditionalCommand unless(BooleanSupplier condition) {
+ public ConditionalCommand unless(BooleanSupplier condition) {
return new ConditionalCommand(new InstantCommand(), this, condition);
}
/**
+ * Decorates this command to only run if this condition is met. If the command is already running
+ * and the condition changes to false, the command will not stop running. The requirements of this
+ * command will be kept for the new conditional command.
+ *
+ * <p>Note: This decorator works by adding this command to a composition. The command the
+ * decorator was called on cannot be scheduled independently or be added to a different
+ * composition (namely, decorators), unless it is manually cleared from the list of composed
+ * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
+ * returned from this method can be further decorated without issue.
+ *
+ * @param condition the condition that will allow the command to run
+ * @return the decorated command
+ * @see #unless(BooleanSupplier)
+ */
+ public ConditionalCommand onlyIf(BooleanSupplier condition) {
+ return unless(() -> !condition.getAsBoolean());
+ }
+
+ /**
* Decorates this command to run or stop when disabled.
*
* @param doesRunWhenDisabled true to run when disabled.
* @return the decorated command
*/
- default WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
+ public WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
return new WrapperCommand(this) {
@Override
public boolean runsWhenDisabled() {
@@ -329,7 +395,7 @@
* @param interruptBehavior the desired interrupt behavior
* @return the decorated command
*/
- default WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
+ public WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
return new WrapperCommand(this) {
@Override
public InterruptionBehavior getInterruptionBehavior() {
@@ -346,7 +412,7 @@
* interrupted.
* @return the decorated command
*/
- default WrapperCommand finallyDo(BooleanConsumer end) {
+ public WrapperCommand finallyDo(BooleanConsumer end) {
requireNonNullParam(end, "end", "Command.finallyDo()");
return new WrapperCommand(this) {
@Override
@@ -358,13 +424,25 @@
}
/**
+ * 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.
*
* @param handler a lambda to run when the command is interrupted
* @return the decorated command
*/
- default WrapperCommand handleInterrupt(Runnable handler) {
+ public WrapperCommand handleInterrupt(Runnable handler) {
requireNonNullParam(handler, "handler", "Command.handleInterrupt()");
return finallyDo(
interrupted -> {
@@ -375,7 +453,7 @@
}
/** Schedules this command. */
- default void schedule() {
+ public void schedule() {
CommandScheduler.getInstance().schedule(this);
}
@@ -385,7 +463,7 @@
*
* @see CommandScheduler#cancel(Command...)
*/
- default void cancel() {
+ public void cancel() {
CommandScheduler.getInstance().cancel(this);
}
@@ -395,7 +473,7 @@
*
* @return Whether the command is scheduled.
*/
- default boolean isScheduled() {
+ public boolean isScheduled() {
return CommandScheduler.getInstance().isScheduled(this);
}
@@ -405,7 +483,7 @@
* @param requirement the subsystem to inquire about
* @return whether the subsystem is required
*/
- default boolean hasRequirement(Subsystem requirement) {
+ public boolean hasRequirement(Subsystem requirement) {
return getRequirements().contains(requirement);
}
@@ -415,7 +493,7 @@
* @return a variant of {@link InterruptionBehavior}, defaulting to {@link
* InterruptionBehavior#kCancelSelf kCancelSelf}.
*/
- default InterruptionBehavior getInterruptionBehavior() {
+ public InterruptionBehavior getInterruptionBehavior() {
return InterruptionBehavior.kCancelSelf;
}
@@ -425,43 +503,52 @@
*
* @return whether the command should run when the robot is disabled
*/
- default boolean runsWhenDisabled() {
+ public boolean runsWhenDisabled() {
return false;
}
/**
- * Gets the name of this Command. Defaults to the simple class name if not overridden.
- *
- * @return The display name of the Command
- */
- default String getName() {
- return this.getClass().getSimpleName();
- }
-
- /**
- * Sets the name of this Command. Nullop if not overridden.
- *
- * @param name The display name of the Command.
- */
- default void setName(String name) {}
-
- /**
* Decorates this Command with a name.
*
* @param name name
* @return the decorated Command
*/
- default WrapperCommand withName(String name) {
+ public WrapperCommand withName(String name) {
WrapperCommand wrapper = new WrapperCommand(Command.this) {};
wrapper.setName(name);
return wrapper;
}
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Command");
+ builder.addStringProperty(".name", this::getName, null);
+ builder.addBooleanProperty(
+ "running",
+ this::isScheduled,
+ value -> {
+ if (value) {
+ if (!isScheduled()) {
+ schedule();
+ }
+ } else {
+ if (isScheduled()) {
+ cancel();
+ }
+ }
+ });
+ builder.addBooleanProperty(
+ ".isParented", () -> CommandScheduler.getInstance().isComposed(this), null);
+ builder.addStringProperty(
+ "interruptBehavior", () -> getInterruptionBehavior().toString(), null);
+ builder.addBooleanProperty("runsWhenDisabled", this::runsWhenDisabled, null);
+ }
+
/**
* An enum describing the command's behavior when another command with a shared requirement is
* scheduled.
*/
- enum InterruptionBehavior {
+ public enum InterruptionBehavior {
/**
* This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is
* scheduled normally.
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandBase.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandBase.java
index 395322a..12243cb 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandBase.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandBase.java
@@ -4,103 +4,16 @@
package edu.wpi.first.wpilibj2.command;
-import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
-
import edu.wpi.first.util.sendable.Sendable;
-import edu.wpi.first.util.sendable.SendableBuilder;
-import edu.wpi.first.util.sendable.SendableRegistry;
-import java.util.HashSet;
-import java.util.Set;
/**
* A {@link Sendable} base class for {@link Command}s.
*
* <p>This class is provided by the NewCommands VendorDep
+ *
+ * @deprecated All functionality provided by {@link CommandBase} has been merged into {@link
+ * Command}. Use {@link Command} instead.
*/
-public abstract class CommandBase implements Sendable, Command {
- protected Set<Subsystem> m_requirements = new HashSet<>();
-
- protected CommandBase() {
- String name = getClass().getName();
- SendableRegistry.add(this, name.substring(name.lastIndexOf('.') + 1));
- }
-
- /**
- * Adds the specified requirements to the command.
- *
- * @param requirements the requirements to add
- */
- public final void addRequirements(Subsystem... requirements) {
- for (Subsystem requirement : requirements) {
- m_requirements.add(requireNonNullParam(requirement, "requirement", "addRequirements"));
- }
- }
-
- @Override
- public Set<Subsystem> getRequirements() {
- return m_requirements;
- }
-
- @Override
- public String getName() {
- return SendableRegistry.getName(this);
- }
-
- /**
- * Sets the name of this Command.
- *
- * @param name name
- */
- @Override
- public void setName(String name) {
- SendableRegistry.setName(this, name);
- }
-
- /**
- * Gets the subsystem name of this Command.
- *
- * @return Subsystem name
- */
- public String getSubsystem() {
- return SendableRegistry.getSubsystem(this);
- }
-
- /**
- * Sets the subsystem name of this Command.
- *
- * @param subsystem subsystem name
- */
- public void setSubsystem(String subsystem) {
- SendableRegistry.setSubsystem(this, subsystem);
- }
-
- /**
- * Initializes this sendable. Useful for allowing implementations to easily extend SendableBase.
- *
- * @param builder the builder used to construct this sendable
- */
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("Command");
- builder.addStringProperty(".name", this::getName, null);
- builder.addBooleanProperty(
- "running",
- this::isScheduled,
- value -> {
- if (value) {
- if (!isScheduled()) {
- schedule();
- }
- } else {
- if (isScheduled()) {
- cancel();
- }
- }
- });
- builder.addBooleanProperty(
- ".isParented", () -> CommandScheduler.getInstance().isComposed(this), null);
- builder.addStringProperty(
- "interruptBehavior", () -> getInterruptionBehavior().toString(), null);
- builder.addBooleanProperty("runsWhenDisabled", this::runsWhenDisabled, null);
- }
-}
+@Deprecated(since = "2024", forRemoval = true)
+@SuppressWarnings("PMD.AbstractClassWithoutAnyMethod")
+public abstract class CommandBase extends Command {}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandGroupBase.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandGroupBase.java
deleted file mode 100644
index 73a1342..0000000
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandGroupBase.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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;
-
-/**
- * A base for CommandGroups.
- *
- * <p>This class is provided by the NewCommands VendorDep
- *
- * @deprecated This class is an empty abstraction. Inherit directly from CommandBase/Command.
- */
-@Deprecated(forRemoval = true)
-public abstract class CommandGroupBase extends CommandBase {
- /**
- * Adds the given commands to the command group.
- *
- * @param commands The commands to add.
- */
- public abstract void addCommands(Command... commands);
-
- /**
- * Factory method for {@link SequentialCommandGroup}, included for brevity/convenience.
- *
- * @param commands the commands to include
- * @return the command group
- * @deprecated Replace with {@link Commands#sequence(Command...)}
- */
- @Deprecated
- public static SequentialCommandGroup sequence(Command... commands) {
- return new SequentialCommandGroup(commands);
- }
-
- /**
- * Factory method for {@link ParallelCommandGroup}, included for brevity/convenience.
- *
- * @param commands the commands to include
- * @return the command group
- * @deprecated Replace with {@link Commands#parallel(Command...)}
- */
- @Deprecated
- public static ParallelCommandGroup parallel(Command... commands) {
- return new ParallelCommandGroup(commands);
- }
-
- /**
- * Factory method for {@link ParallelRaceGroup}, included for brevity/convenience.
- *
- * @param commands the commands to include
- * @return the command group
- * @deprecated Replace with {@link Commands#race(Command...)}
- */
- @Deprecated
- public static ParallelRaceGroup race(Command... commands) {
- return new ParallelRaceGroup(commands);
- }
-
- /**
- * Factory method for {@link ParallelDeadlineGroup}, included for brevity/convenience.
- *
- * @param deadline the deadline command
- * @param commands the commands to include
- * @return the command group
- * @deprecated Replace with {@link Commands#deadline(Command, Command...)}
- */
- @Deprecated
- public static ParallelDeadlineGroup deadline(Command deadline, Command... commands) {
- return new ParallelDeadlineGroup(deadline, commands);
- }
-}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
index 15c8606..c868539 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
@@ -9,13 +9,8 @@
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.networktables.IntegerArrayEntry;
-import edu.wpi.first.networktables.IntegerArrayPublisher;
-import edu.wpi.first.networktables.IntegerArrayTopic;
-import edu.wpi.first.networktables.NTSendable;
-import edu.wpi.first.networktables.NTSendableBuilder;
-import edu.wpi.first.networktables.StringArrayPublisher;
-import edu.wpi.first.networktables.StringArrayTopic;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.RobotBase;
@@ -33,8 +28,10 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
@@ -46,7 +43,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public final class CommandScheduler implements NTSendable, AutoCloseable {
+public final class CommandScheduler implements Sendable, AutoCloseable {
/** The Singleton Instance. */
private static CommandScheduler instance;
@@ -62,6 +59,8 @@
return instance;
}
+ private static final Optional<Command> kNoInterruptor = Optional.empty();
+
private final Set<Command> m_composedCommands = Collections.newSetFromMap(new WeakHashMap<>());
// A set of the currently-running commands.
@@ -84,14 +83,16 @@
// Lists of user-supplied actions to be executed on scheduling events for every command.
private final List<Consumer<Command>> m_initActions = new ArrayList<>();
private final List<Consumer<Command>> m_executeActions = new ArrayList<>();
- private final List<Consumer<Command>> m_interruptActions = new ArrayList<>();
+ private final List<BiConsumer<Command, Optional<Command>>> m_interruptActions = new ArrayList<>();
private final List<Consumer<Command>> m_finishActions = new ArrayList<>();
// Flag and queues for avoiding ConcurrentModificationException if commands are
// scheduled/canceled during run
private boolean m_inRunLoop;
private final Set<Command> m_toSchedule = new LinkedHashSet<>();
- private final List<Command> m_toCancel = new ArrayList<>();
+ private final List<Command> m_toCancelCommands = new ArrayList<>();
+ private final List<Optional<Command>> m_toCancelInterruptors = new ArrayList<>();
+ private final Set<Command> m_endingCommands = new LinkedHashSet<>();
private final Watchdog m_watchdog = new Watchdog(TimedRobot.kDefaultPeriod, () -> {});
@@ -152,27 +153,6 @@
}
/**
- * Adds a button binding to the scheduler, which will be polled to schedule commands.
- *
- * @param button The button to add
- * @deprecated Use {@link edu.wpi.first.wpilibj2.command.button.Trigger}
- */
- @Deprecated(since = "2023")
- public void addButton(Runnable button) {
- m_activeButtonLoop.bind(requireNonNullParam(button, "button", "addButton"));
- }
-
- /**
- * Removes all button bindings from the scheduler.
- *
- * @deprecated call {@link EventLoop#clear()} on {@link #getActiveButtonLoop()} directly instead.
- */
- @Deprecated(since = "2023")
- public void clearButtons() {
- m_activeButtonLoop.clear();
- }
-
- /**
* Initializes a given command, adds its requirements to the list, and performs the init actions.
*
* @param command The command to initialize
@@ -237,7 +217,7 @@
for (Subsystem requirement : requirements) {
Command requiring = requiring(requirement);
if (requiring != null) {
- cancel(requiring);
+ cancel(requiring, Optional.of(command));
}
}
initCommand(command, requirements);
@@ -292,18 +272,13 @@
m_watchdog.addEpoch("buttons.run()");
m_inRunLoop = true;
+ boolean isDisabled = RobotState.isDisabled();
// Run scheduled commands, remove finished commands.
for (Iterator<Command> iterator = m_scheduledCommands.iterator(); iterator.hasNext(); ) {
Command command = iterator.next();
- if (!command.runsWhenDisabled() && RobotState.isDisabled()) {
- command.end(true);
- for (Consumer<Command> action : m_interruptActions) {
- action.accept(command);
- }
- m_requirements.keySet().removeAll(command.getRequirements());
- iterator.remove();
- m_watchdog.addEpoch(command.getName() + ".end(true)");
+ if (isDisabled && !command.runsWhenDisabled()) {
+ cancel(command, kNoInterruptor);
continue;
}
@@ -313,10 +288,12 @@
}
m_watchdog.addEpoch(command.getName() + ".execute()");
if (command.isFinished()) {
+ m_endingCommands.add(command);
command.end(false);
for (Consumer<Command> action : m_finishActions) {
action.accept(command);
}
+ m_endingCommands.remove(command);
iterator.remove();
m_requirements.keySet().removeAll(command.getRequirements());
@@ -330,12 +307,13 @@
schedule(command);
}
- for (Command command : m_toCancel) {
- cancel(command);
+ for (int i = 0; i < m_toCancelCommands.size(); i++) {
+ cancel(m_toCancelCommands.get(i), m_toCancelInterruptors.get(i));
}
m_toSchedule.clear();
- m_toCancel.clear();
+ m_toCancelCommands.clear();
+ m_toCancelInterruptors.clear();
// Add default commands for un-required registered subsystems.
for (Map.Entry<Subsystem, Command> subsystemCommand : m_subsystems.entrySet()) {
@@ -384,6 +362,15 @@
}
/**
+ * Un-registers all registered Subsystems with the scheduler. All currently registered subsystems
+ * will no longer have their periodic block called, and will not have their default command
+ * scheduled.
+ */
+ public void unregisterAllSubsystems() {
+ m_subsystems.clear();
+ }
+
+ /**
* Sets the default command for a subsystem. Registers that subsystem if it is not already
* registered. Default commands will run whenever there is no other command currently scheduled
* that requires the subsystem. Default commands should be written to never end (i.e. their {@link
@@ -457,28 +444,47 @@
* @param commands the commands to cancel
*/
public void cancel(Command... commands) {
+ for (Command command : commands) {
+ cancel(command, kNoInterruptor);
+ }
+ }
+
+ /**
+ * Cancels a command. The scheduler will only call {@link Command#end(boolean)} method of the
+ * canceled command with {@code true}, indicating they were canceled (as opposed to finishing
+ * normally).
+ *
+ * <p>Commands will be canceled regardless of {@link InterruptionBehavior interruption behavior}.
+ *
+ * @param command the command to cancel
+ * @param interruptor the interrupting command, if any
+ */
+ private void cancel(Command command, Optional<Command> interruptor) {
+ if (command == null) {
+ DriverStation.reportWarning("Tried to cancel a null command", true);
+ return;
+ }
+ if (m_endingCommands.contains(command)) {
+ return;
+ }
if (m_inRunLoop) {
- m_toCancel.addAll(List.of(commands));
+ m_toCancelCommands.add(command);
+ m_toCancelInterruptors.add(interruptor);
+ return;
+ }
+ if (!isScheduled(command)) {
return;
}
- for (Command command : commands) {
- if (command == null) {
- DriverStation.reportWarning("Tried to cancel a null command", true);
- continue;
- }
- if (!isScheduled(command)) {
- continue;
- }
-
- m_scheduledCommands.remove(command);
- m_requirements.keySet().removeAll(command.getRequirements());
- command.end(true);
- for (Consumer<Command> action : m_interruptActions) {
- action.accept(command);
- }
- m_watchdog.addEpoch(command.getName() + ".end(true)");
+ m_endingCommands.add(command);
+ command.end(true);
+ for (BiConsumer<Command, Optional<Command>> action : m_interruptActions) {
+ action.accept(command, interruptor);
}
+ m_endingCommands.remove(command);
+ m_scheduledCommands.remove(command);
+ m_requirements.keySet().removeAll(command.getRequirements());
+ m_watchdog.addEpoch(command.getName() + ".end(true)");
}
/** Cancels all commands that are currently scheduled. */
@@ -545,6 +551,19 @@
* @param action the action to perform
*/
public void onCommandInterrupt(Consumer<Command> action) {
+ requireNonNullParam(action, "action", "onCommandInterrupt");
+ m_interruptActions.add((command, interruptor) -> action.accept(command));
+ }
+
+ /**
+ * Adds an action to perform on the interruption of any command by the scheduler. The action
+ * receives the interrupted command and an Optional containing the interrupting command, or
+ * Optional.empty() if it was not canceled by a command (e.g., by {@link
+ * CommandScheduler#cancel}).
+ *
+ * @param action the action to perform
+ */
+ public void onCommandInterrupt(BiConsumer<Command, Optional<Command>> action) {
m_interruptActions.add(requireNonNullParam(action, "action", "onCommandInterrupt"));
}
@@ -602,7 +621,7 @@
public void requireNotComposed(Command command) {
if (m_composedCommands.contains(command)) {
throw new IllegalArgumentException(
- "Commands that have been composed may not be added to another composition or scheduled"
+ "Commands that have been composed may not be added to another composition or scheduled "
+ "individually!");
}
}
@@ -616,7 +635,7 @@
public void requireNotComposed(Collection<Command> commands) {
if (!Collections.disjoint(commands, getComposedCommands())) {
throw new IllegalArgumentException(
- "Commands that have been composed may not be added to another composition or scheduled"
+ "Commands that have been composed may not be added to another composition or scheduled "
+ "individually!");
}
}
@@ -626,7 +645,6 @@
*
* @param command The command to check
* @return true if composed
- * @throws IllegalArgumentException if the given commands have already been composed.
*/
public boolean isComposed(Command command) {
return getComposedCommands().contains(command);
@@ -637,45 +655,46 @@
}
@Override
- public void initSendable(NTSendableBuilder builder) {
+ public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Scheduler");
- final StringArrayPublisher namesPub = new StringArrayTopic(builder.getTopic("Names")).publish();
- final IntegerArrayPublisher idsPub = new IntegerArrayTopic(builder.getTopic("Ids")).publish();
- final IntegerArrayEntry cancelEntry =
- new IntegerArrayTopic(builder.getTopic("Cancel")).getEntry(new long[] {});
- builder.addCloseable(namesPub);
- builder.addCloseable(idsPub);
- builder.addCloseable(cancelEntry);
- builder.setUpdateTable(
+ builder.addStringArrayProperty(
+ "Names",
() -> {
- if (namesPub == null || idsPub == null || cancelEntry == null) {
- return;
- }
-
- Map<Long, Command> ids = new LinkedHashMap<>();
- List<String> names = new ArrayList<>();
- long[] ids2 = new long[m_scheduledCommands.size()];
-
+ String[] names = new String[m_scheduledCommands.size()];
int i = 0;
for (Command command : m_scheduledCommands) {
+ names[i] = command.getName();
+ i++;
+ }
+ return names;
+ },
+ null);
+ builder.addIntegerArrayProperty(
+ "Ids",
+ () -> {
+ long[] ids = new long[m_scheduledCommands.size()];
+ int i = 0;
+ for (Command command : m_scheduledCommands) {
+ ids[i] = command.hashCode();
+ i++;
+ }
+ return ids;
+ },
+ null);
+ builder.addIntegerArrayProperty(
+ "Cancel",
+ () -> {
+ return new long[] {};
+ },
+ toCancel -> {
+ Map<Long, Command> ids = new LinkedHashMap<>();
+ for (Command command : m_scheduledCommands) {
long id = command.hashCode();
ids.put(id, command);
- names.add(command.getName());
- ids2[i] = id;
- i++;
}
-
- long[] toCancel = cancelEntry.get();
- if (toCancel.length > 0) {
- for (long hash : toCancel) {
- cancel(ids.get(hash));
- ids.remove(hash);
- }
- cancelEntry.set(new long[] {});
+ for (long hash : toCancel) {
+ cancel(ids.get(hash));
}
-
- namesPub.set(names.toArray(new String[] {}));
- idsPub.set(ids2);
});
}
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Commands.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Commands.java
index 737b9cc..7295e3c 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Commands.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Commands.java
@@ -7,6 +7,7 @@
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;
@@ -21,10 +22,20 @@
*
* @return the command
*/
- public static CommandBase none() {
+ public static Command none() {
return new InstantCommand();
}
+ /**
+ * Constructs a command that does nothing until interrupted.
+ *
+ * @param requirements Subsystems to require
+ * @return the command
+ */
+ public static Command idle(Subsystem... requirements) {
+ return run(() -> {}, requirements);
+ }
+
// Action Commands
/**
@@ -35,7 +46,7 @@
* @return the command
* @see InstantCommand
*/
- public static CommandBase runOnce(Runnable action, Subsystem... requirements) {
+ public static Command runOnce(Runnable action, Subsystem... requirements) {
return new InstantCommand(action, requirements);
}
@@ -47,7 +58,7 @@
* @return the command
* @see RunCommand
*/
- public static CommandBase run(Runnable action, Subsystem... requirements) {
+ public static Command run(Runnable action, Subsystem... requirements) {
return new RunCommand(action, requirements);
}
@@ -61,7 +72,7 @@
* @return the command
* @see StartEndCommand
*/
- public static CommandBase startEnd(Runnable start, Runnable end, Subsystem... requirements) {
+ public static Command startEnd(Runnable start, Runnable end, Subsystem... requirements) {
return new StartEndCommand(start, end, requirements);
}
@@ -74,7 +85,7 @@
* @param requirements subsystems the action requires
* @return the command
*/
- public static CommandBase runEnd(Runnable run, Runnable end, Subsystem... requirements) {
+ public static Command runEnd(Runnable run, Runnable end, Subsystem... requirements) {
requireNonNullParam(end, "end", "Command.runEnd");
return new FunctionalCommand(
() -> {}, run, interrupted -> end.run(), () -> false, requirements);
@@ -87,7 +98,7 @@
* @return the command
* @see PrintCommand
*/
- public static CommandBase print(String message) {
+ public static Command print(String message) {
return new PrintCommand(message);
}
@@ -100,7 +111,7 @@
* @return the command
* @see WaitCommand
*/
- public static CommandBase waitSeconds(double seconds) {
+ public static Command waitSeconds(double seconds) {
return new WaitCommand(seconds);
}
@@ -111,7 +122,7 @@
* @return the command
* @see WaitUntilCommand
*/
- public static CommandBase waitUntil(BooleanSupplier condition) {
+ public static Command waitUntil(BooleanSupplier condition) {
return new WaitUntilCommand(condition);
}
@@ -126,35 +137,61 @@
* @return the command
* @see ConditionalCommand
*/
- public static CommandBase either(Command onTrue, Command onFalse, BooleanSupplier selector) {
+ public static Command either(Command onTrue, Command onFalse, BooleanSupplier selector) {
return new ConditionalCommand(onTrue, onFalse, selector);
}
/**
* 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 CommandBase 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);
+ }
+
+ /**
+ * Constructs a command that schedules the command returned from the supplier when initialized,
+ * and ends when it is no longer scheduled. The supplier is called when the command is
+ * initialized.
+ *
+ * @param supplier the command supplier
+ * @return the command
+ * @see ProxyCommand
+ */
+ public static Command deferredProxy(Supplier<Command> supplier) {
+ return new ProxyCommand(supplier);
+ }
+
+ // Command Groups
+
+ /**
* Runs a group of commands in series, one after the other.
*
* @param commands the commands to include
* @return the command group
* @see SequentialCommandGroup
*/
- public static CommandBase sequence(Command... commands) {
+ public static Command sequence(Command... commands) {
return new SequentialCommandGroup(commands);
}
- // Command Groups
-
/**
* Runs a group of commands in series, one after the other. Once the last command ends, the group
* is restarted.
@@ -164,7 +201,7 @@
* @see SequentialCommandGroup
* @see Command#repeatedly()
*/
- public static CommandBase repeatingSequence(Command... commands) {
+ public static Command repeatingSequence(Command... commands) {
return sequence(commands).repeatedly();
}
@@ -175,7 +212,7 @@
* @return the command
* @see ParallelCommandGroup
*/
- public static CommandBase parallel(Command... commands) {
+ public static Command parallel(Command... commands) {
return new ParallelCommandGroup(commands);
}
@@ -187,7 +224,7 @@
* @return the command group
* @see ParallelRaceGroup
*/
- public static CommandBase race(Command... commands) {
+ public static Command race(Command... commands) {
return new ParallelRaceGroup(commands);
}
@@ -200,7 +237,7 @@
* @return the command group
* @see ParallelDeadlineGroup
*/
- public static CommandBase deadline(Command deadline, Command... commands) {
+ public static Command deadline(Command deadline, Command... commands) {
return new ParallelDeadlineGroup(deadline, commands);
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ConditionalCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ConditionalCommand.java
index 782f217..42db3f0 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ConditionalCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ConditionalCommand.java
@@ -19,7 +19,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class ConditionalCommand extends CommandBase {
+public class ConditionalCommand extends Command {
private final Command m_onTrue;
private final Command m_onFalse;
private final BooleanSupplier m_condition;
@@ -74,6 +74,16 @@
}
@Override
+ public InterruptionBehavior getInterruptionBehavior() {
+ if (m_onTrue.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf
+ || m_onFalse.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) {
+ return InterruptionBehavior.kCancelSelf;
+ } else {
+ return InterruptionBehavior.kCancelIncoming;
+ }
+ }
+
+ @Override
public void initSendable(SendableBuilder builder) {
super.initSendable(builder);
builder.addStringProperty("onTrue", m_onTrue::getName, null);
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/DeferredCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/DeferredCommand.java
new file mode 100644
index 0000000..76a5276
--- /dev/null
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/DeferredCommand.java
@@ -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);
+ }
+}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/FunctionalCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/FunctionalCommand.java
index fcd4bd7..dde5ae1 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/FunctionalCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/FunctionalCommand.java
@@ -17,7 +17,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class FunctionalCommand extends CommandBase {
+public class FunctionalCommand extends Command {
protected final Runnable m_onInit;
protected final Runnable m_onExecute;
protected final Consumer<Boolean> m_onEnd;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommand.java
index f6b6668..16d9c8a 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommand.java
@@ -38,7 +38,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class MecanumControllerCommand extends CommandBase {
+public class MecanumControllerCommand extends Command {
private final Timer m_timer = new Timer();
private final boolean m_usePID;
private final Trajectory m_trajectory;
@@ -332,8 +332,7 @@
m_prevSpeeds =
m_kinematics.toWheelSpeeds(new ChassisSpeeds(initialXVelocity, initialYVelocity, 0.0));
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
}
@Override
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/NotifierCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/NotifierCommand.java
index 730ef1b..ad1a12a 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/NotifierCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/NotifierCommand.java
@@ -17,7 +17,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class NotifierCommand extends CommandBase {
+public class NotifierCommand extends Command {
protected final Notifier m_notifier;
protected final double m_period;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PIDCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PIDCommand.java
index ec184c8..c761f3f 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PIDCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PIDCommand.java
@@ -18,7 +18,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class PIDCommand extends CommandBase {
+public class PIDCommand extends Command {
protected final PIDController m_controller;
protected DoubleSupplier m_measurement;
protected DoubleSupplier m_setpoint;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelCommandGroup.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelCommandGroup.java
index 3b36f42..8604189 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelCommandGroup.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelCommandGroup.java
@@ -17,8 +17,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("removal")
-public class ParallelCommandGroup extends CommandGroupBase {
+public class ParallelCommandGroup extends Command {
// maps commands in this composition to whether they are still running
private final Map<Command, Boolean> m_commands = new HashMap<>();
private boolean m_runWhenDisabled = true;
@@ -35,7 +34,11 @@
addCommands(commands);
}
- @Override
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
public final void addCommands(Command... commands) {
if (m_commands.containsValue(true)) {
throw new IllegalStateException(
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelDeadlineGroup.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelDeadlineGroup.java
index 2e62a9f..6d263e8 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelDeadlineGroup.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelDeadlineGroup.java
@@ -20,8 +20,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("removal")
-public class ParallelDeadlineGroup extends CommandGroupBase {
+public class ParallelDeadlineGroup extends Command {
// maps commands in this composition to whether they are still running
private final Map<Command, Boolean> m_commands = new HashMap<>();
private boolean m_runWhenDisabled = true;
@@ -59,7 +58,11 @@
m_deadline = deadline;
}
- @Override
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
public final void addCommands(Command... commands) {
if (!m_finished) {
throw new IllegalStateException(
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelRaceGroup.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelRaceGroup.java
index e5ba80d..7195cd7 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelRaceGroup.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ParallelRaceGroup.java
@@ -18,8 +18,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("removal")
-public class ParallelRaceGroup extends CommandGroupBase {
+public class ParallelRaceGroup extends Command {
private final Set<Command> m_commands = new HashSet<>();
private boolean m_runWhenDisabled = true;
private boolean m_finished = true;
@@ -36,7 +35,11 @@
addCommands(commands);
}
- @Override
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
public final void addCommands(Command... commands) {
if (!m_finished) {
throw new IllegalStateException(
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PerpetualCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PerpetualCommand.java
deleted file mode 100644
index 9fb9019..0000000
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/PerpetualCommand.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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;
-
-/**
- * A command that runs another command in perpetuity, ignoring that command's end conditions. While
- * this class does not extend {@link CommandGroupBase}, it is still considered a composition, as it
- * allows one to compose another command within it; the command instances that are passed to it
- * cannot be added to any other groups, or scheduled individually.
- *
- * <p>As a rule, CommandGroups require the union of the requirements of their component commands.
- *
- * <p>This class is provided by the NewCommands VendorDep
- *
- * @deprecated PerpetualCommand violates the assumption that execute() doesn't get called after
- * isFinished() returns true -- an assumption that should be valid. This was unsafe/undefined
- * behavior from the start, and RepeatCommand provides an easy way to achieve similar end
- * results with slightly different (and safe) semantics.
- */
-@Deprecated(forRemoval = true, since = "2023")
-public class PerpetualCommand extends CommandBase {
- protected final Command m_command;
-
- /**
- * Creates a new PerpetualCommand. Will run another command in perpetuity, ignoring that command's
- * end conditions, unless this command itself is interrupted.
- *
- * @param command the command to run perpetually
- */
- public PerpetualCommand(Command command) {
- CommandScheduler.getInstance().registerComposedCommands(command);
- m_command = command;
- m_requirements.addAll(command.getRequirements());
- }
-
- @Override
- public void initialize() {
- m_command.initialize();
- }
-
- @Override
- public void execute() {
- m_command.execute();
- }
-
- @Override
- public void end(boolean interrupted) {
- m_command.end(interrupted);
- }
-
- @Override
- public boolean runsWhenDisabled() {
- return m_command.runsWhenDisabled();
- }
-}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProfiledPIDCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProfiledPIDCommand.java
index 4344913..f7175fc 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProfiledPIDCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProfiledPIDCommand.java
@@ -20,7 +20,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class ProfiledPIDCommand extends CommandBase {
+public class ProfiledPIDCommand extends Command {
protected final ProfiledPIDController m_controller;
protected DoubleSupplier m_measurement;
protected Supplier<State> m_goal;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java
index ef6ca5b..d6e93e8 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java
@@ -15,7 +15,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class ProxyCommand extends CommandBase {
+public class ProxyCommand extends Command {
private final Supplier<Command> m_supplier;
private Command m_command;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyScheduleCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyScheduleCommand.java
deleted file mode 100644
index eec1b18..0000000
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyScheduleCommand.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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 java.util.Set;
-
-/**
- * Schedules the given commands when this command is initialized, and ends when all the commands are
- * no longer scheduled. Useful for forking off from CommandGroups. If this command is interrupted,
- * it will cancel all the commands.
- *
- * <p>This class is provided by the NewCommands VendorDep
- */
-public class ProxyScheduleCommand extends CommandBase {
- private final Set<Command> m_toSchedule;
- private boolean m_finished;
-
- /**
- * Creates a new ProxyScheduleCommand that schedules the given commands when initialized, and ends
- * when they are all no longer scheduled.
- *
- * @param toSchedule the commands to schedule
- * @deprecated Replace with {@link ProxyCommand}, composing multiple of them in a {@link
- * ParallelRaceGroup} if needed.
- */
- @Deprecated
- public ProxyScheduleCommand(Command... toSchedule) {
- m_toSchedule = Set.of(toSchedule);
- }
-
- @Override
- public void initialize() {
- for (Command command : m_toSchedule) {
- command.schedule();
- }
- }
-
- @Override
- public void end(boolean interrupted) {
- if (interrupted) {
- for (Command command : m_toSchedule) {
- command.cancel();
- }
- }
- }
-
- @Override
- public void execute() {
- m_finished = true;
- for (Command command : m_toSchedule) {
- m_finished &= !command.isScheduled();
- }
- }
-
- @Override
- public boolean isFinished() {
- return m_finished;
- }
-}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RamseteCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RamseteCommand.java
index 69e271b..9f19e4a 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RamseteCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RamseteCommand.java
@@ -33,7 +33,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class RamseteCommand extends CommandBase {
+public class RamseteCommand extends Command {
private final Timer m_timer = new Timer();
private final boolean m_usePID;
private final Trajectory m_trajectory;
@@ -45,7 +45,7 @@
private final PIDController m_leftController;
private final PIDController m_rightController;
private final BiConsumer<Double, Double> m_output;
- private DifferentialDriveWheelSpeeds m_prevSpeeds;
+ private DifferentialDriveWheelSpeeds m_prevSpeeds = new DifferentialDriveWheelSpeeds();
private double m_prevTime;
/**
@@ -143,8 +143,7 @@
initialState.velocityMetersPerSecond,
0,
initialState.curvatureRadPerMeter * initialState.velocityMetersPerSecond));
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
if (m_usePID) {
m_leftController.reset();
m_rightController.reset();
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RepeatCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RepeatCommand.java
index 6de06c5..5b49ae0 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RepeatCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/RepeatCommand.java
@@ -19,7 +19,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class RepeatCommand extends CommandBase {
+public class RepeatCommand extends Command {
protected final Command m_command;
private boolean m_ended;
@@ -63,7 +63,12 @@
@Override
public void end(boolean interrupted) {
- m_command.end(interrupted);
+ // Make sure we didn't already call end() (which would happen if the command finished in the
+ // last call to our execute())
+ if (!m_ended) {
+ m_command.end(interrupted);
+ m_ended = true;
+ }
}
@Override
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ScheduleCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ScheduleCommand.java
index a61be2f..cc22341 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ScheduleCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ScheduleCommand.java
@@ -13,7 +13,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class ScheduleCommand extends CommandBase {
+public class ScheduleCommand extends Command {
private final Set<Command> m_toSchedule;
/**
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SelectCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SelectCommand.java
index d947701..28d06eb 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SelectCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SelectCommand.java
@@ -11,38 +11,41 @@
import java.util.function.Supplier;
/**
- * A command composition that runs one of a selection of commands, either using a selector and a key
- * to command mapping, or a supplier that returns the command directly at runtime.
+ * A command composition that runs one of a selection of commands using a selector and a key to
+ * command mapping.
*
* <p>The rules for command compositions apply: command instances that are passed to it cannot be
* added to any other composition or scheduled individually, and the composition requires all
* 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 CommandBase {
- private final Map<Object, Command> m_commands;
- private final Supplier<Object> m_selector;
- private final Supplier<Command> m_toRun;
+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;
+ private final Command m_defaultCommand =
+ new PrintCommand("SelectCommand selector value does not correspond to any command!");
+
/**
* Creates a new SelectCommand.
*
* @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");
+ CommandScheduler.getInstance().registerComposedCommands(m_defaultCommand);
CommandScheduler.getInstance()
.registerComposedCommands(commands.values().toArray(new Command[] {}));
- m_toRun = null;
-
for (Command command : m_commands.values()) {
m_requirements.addAll(command.getRequirements());
m_runsWhenDisabled &= command.runsWhenDisabled();
@@ -52,36 +55,9 @@
}
}
- /**
- * Creates a new SelectCommand.
- *
- * @param toRun a supplier providing the command to run
- * @deprecated Replace with {@link ProxyCommand}
- */
- @Deprecated
- public SelectCommand(Supplier<Command> toRun) {
- m_commands = null;
- m_selector = null;
- m_toRun = requireNonNullParam(toRun, "toRun", "SelectCommand");
-
- // we have no way of checking the underlying command, so default.
- m_runsWhenDisabled = false;
- m_interruptBehavior = InterruptionBehavior.kCancelSelf;
- }
-
@Override
public void initialize() {
- if (m_selector != null) {
- if (!m_commands.containsKey(m_selector.get())) {
- m_selectedCommand =
- new PrintCommand(
- "SelectCommand selector value does not correspond to" + " any command!");
- return;
- }
- m_selectedCommand = m_commands.get(m_selector.get());
- } else {
- m_selectedCommand = m_toRun.get();
- }
+ m_selectedCommand = m_commands.getOrDefault(m_selector.get(), m_defaultCommand);
m_selectedCommand.initialize();
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SequentialCommandGroup.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SequentialCommandGroup.java
index 892f94a..c3598cb 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SequentialCommandGroup.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SequentialCommandGroup.java
@@ -17,8 +17,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("removal")
-public class SequentialCommandGroup extends CommandGroupBase {
+public class SequentialCommandGroup extends Command {
private final List<Command> m_commands = new ArrayList<>();
private int m_currentCommandIndex = -1;
private boolean m_runWhenDisabled = true;
@@ -34,7 +33,11 @@
addCommands(commands);
}
- @Override
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add, in order of execution.
+ */
public final void addCommands(Command... commands) {
if (m_currentCommandIndex != -1) {
throw new IllegalStateException(
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Subsystem.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Subsystem.java
index 0584ced..ac89dbd 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Subsystem.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/Subsystem.java
@@ -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
@@ -51,6 +54,14 @@
}
/**
+ * Removes the default command for the subsystem. This will not cancel the default command if it
+ * is currently running.
+ */
+ default void removeDefaultCommand() {
+ CommandScheduler.getInstance().removeDefaultCommand(this);
+ }
+
+ /**
* Gets the default command for this subsystem. Returns null if no default command is currently
* associated with the subsystem.
*
@@ -85,7 +96,7 @@
* @return the command
* @see InstantCommand
*/
- default CommandBase runOnce(Runnable action) {
+ default Command runOnce(Runnable action) {
return Commands.runOnce(action, this);
}
@@ -97,7 +108,7 @@
* @return the command
* @see RunCommand
*/
- default CommandBase run(Runnable action) {
+ default Command run(Runnable action) {
return Commands.run(action, this);
}
@@ -110,7 +121,7 @@
* @return the command
* @see StartEndCommand
*/
- default CommandBase startEnd(Runnable start, Runnable end) {
+ default Command startEnd(Runnable start, Runnable end) {
return Commands.startEnd(start, end, this);
}
@@ -122,7 +133,19 @@
* @param end the action to run on interrupt
* @return the command
*/
- default CommandBase runEnd(Runnable run, Runnable end) {
+ 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));
+ }
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommand.java
index 850699e..3eacac3 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommand.java
@@ -31,7 +31,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class SwerveControllerCommand extends CommandBase {
+public class SwerveControllerCommand extends Command {
private final Timer m_timer = new Timer();
private final Trajectory m_trajectory;
private final Supplier<Pose2d> m_pose;
@@ -210,8 +210,7 @@
@Override
public void initialize() {
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
}
@Override
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileCommand.java
index 7c13973..57185a9 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileCommand.java
@@ -10,16 +10,19 @@
import edu.wpi.first.math.trajectory.TrapezoidProfile;
import edu.wpi.first.wpilibj.Timer;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* A command that runs a {@link TrapezoidProfile}. Useful for smoothly controlling mechanism motion.
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class TrapezoidProfileCommand extends CommandBase {
+public class TrapezoidProfileCommand extends Command {
private final TrapezoidProfile m_profile;
private final Consumer<State> m_output;
-
+ private final Supplier<State> m_goal;
+ private final Supplier<State> m_currentState;
+ private final boolean m_newAPI; // TODO: Remove
private final Timer m_timer = new Timer();
/**
@@ -28,24 +31,58 @@
*
* @param profile The motion profile to execute.
* @param output The consumer for the profile output.
+ * @param goal The supplier for the desired state
+ * @param currentState The current state
* @param requirements The subsystems required by this command.
*/
public TrapezoidProfileCommand(
+ TrapezoidProfile profile,
+ Consumer<State> output,
+ Supplier<State> goal,
+ Supplier<State> currentState,
+ Subsystem... requirements) {
+ m_profile = requireNonNullParam(profile, "profile", "TrapezoidProfileCommand");
+ m_output = requireNonNullParam(output, "output", "TrapezoidProfileCommand");
+ m_goal = goal;
+ m_currentState = currentState;
+ m_newAPI = true;
+ addRequirements(requirements);
+ }
+
+ /**
+ * Creates a new TrapezoidProfileCommand that will execute the given {@link TrapezoidProfile}.
+ * Output will be piped to the provided consumer function.
+ *
+ * @param profile The motion profile to execute.
+ * @param output The consumer for the profile output.
+ * @param requirements The subsystems required by this command.
+ * @deprecated The new constructor allows you to pass in a supplier for desired and current state.
+ * This allows you to change goals at runtime.
+ */
+ @Deprecated(since = "2024", forRemoval = true)
+ public TrapezoidProfileCommand(
TrapezoidProfile profile, Consumer<State> output, Subsystem... requirements) {
m_profile = requireNonNullParam(profile, "profile", "TrapezoidProfileCommand");
m_output = requireNonNullParam(output, "output", "TrapezoidProfileCommand");
+ m_newAPI = false;
+ m_goal = null;
+ m_currentState = null;
addRequirements(requirements);
}
@Override
public void initialize() {
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
}
@Override
+ @SuppressWarnings("removal")
public void execute() {
- m_output.accept(m_profile.calculate(m_timer.get()));
+ if (m_newAPI) {
+ m_output.accept(m_profile.calculate(m_timer.get(), m_goal.get(), m_currentState.get()));
+ } else {
+ m_output.accept(m_profile.calculate(m_timer.get()));
+ }
}
@Override
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileSubsystem.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileSubsystem.java
index 1db6619..35c02e6 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileSubsystem.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/TrapezoidProfileSubsystem.java
@@ -16,7 +16,7 @@
*/
public abstract class TrapezoidProfileSubsystem extends SubsystemBase {
private final double m_period;
- private final TrapezoidProfile.Constraints m_constraints;
+ private final TrapezoidProfile m_profile;
private TrapezoidProfile.State m_state;
private TrapezoidProfile.State m_goal;
@@ -33,7 +33,8 @@
*/
public TrapezoidProfileSubsystem(
TrapezoidProfile.Constraints constraints, double initialPosition, double period) {
- m_constraints = requireNonNullParam(constraints, "constraints", "TrapezoidProfileSubsystem");
+ requireNonNullParam(constraints, "constraints", "TrapezoidProfileSubsystem");
+ m_profile = new TrapezoidProfile(constraints);
m_state = new TrapezoidProfile.State(initialPosition, 0);
setGoal(initialPosition);
m_period = period;
@@ -62,8 +63,7 @@
@Override
public void periodic() {
- var profile = new TrapezoidProfile(m_constraints, m_goal, m_state);
- m_state = profile.calculate(m_period);
+ m_state = m_profile.calculate(m_period, m_goal, m_state);
if (m_enabled) {
useState(m_state);
}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitCommand.java
index 647e87e..e7b32be 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitCommand.java
@@ -9,12 +9,11 @@
import edu.wpi.first.wpilibj.Timer;
/**
- * A command that does nothing but takes a specified amount of time to finish. Useful for
- * CommandGroups. Can also be subclassed to make a command with an internal timer.
+ * A command that does nothing but takes a specified amount of time to finish.
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class WaitCommand extends CommandBase {
+public class WaitCommand extends Command {
protected Timer m_timer = new Timer();
private final double m_duration;
@@ -30,8 +29,7 @@
@Override
public void initialize() {
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
}
@Override
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitUntilCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitUntilCommand.java
index 4d51e62..b96bc26 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitUntilCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WaitUntilCommand.java
@@ -15,7 +15,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-public class WaitUntilCommand extends CommandBase {
+public class WaitUntilCommand extends Command {
private final BooleanSupplier m_condition;
/**
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WrapperCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WrapperCommand.java
index c48871c..c687f0a 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WrapperCommand.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/WrapperCommand.java
@@ -14,7 +14,7 @@
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*/
-public abstract class WrapperCommand extends CommandBase {
+public abstract class WrapperCommand extends Command {
protected final Command m_command;
/**
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java
deleted file mode 100644
index 4e4e11a..0000000
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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.wpilibj2.command.Command;
-import edu.wpi.first.wpilibj2.command.Subsystem;
-import java.util.function.BooleanSupplier;
-
-/**
- * This class provides an easy way to link commands to OI inputs.
- *
- * <p>It is very easy to link a button to a command. For instance, you could link the trigger button
- * of a joystick to a "score" command.
- *
- * <p>This class represents a subclass of Trigger that is specifically aimed at buttons on an
- * operator interface as a common use case of the more generalized Trigger objects. This is a simple
- * wrapper around Trigger with the method names renamed to fit the Button object use.
- *
- * @deprecated Replace with {@link Trigger}.
- */
-@Deprecated
-public class Button extends Trigger {
- /**
- * Default constructor; creates a button that is never pressed.
- *
- * @deprecated Replace with {@code new Button(() -> false) }.
- */
- @Deprecated(since = "2023")
- public Button() {}
-
- /**
- * Creates a new button with the given condition determining whether it is pressed.
- *
- * @param isPressed returns whether the trigger should be active
- * @deprecated Replace with Trigger.
- */
- @Deprecated
- public Button(BooleanSupplier isPressed) {
- super(isPressed);
- }
-
- /**
- * Starts the given command whenever the button is newly pressed.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link Trigger#onTrue(Command)}
- */
- @Deprecated
- public Button whenPressed(final Command command) {
- whenActive(command);
- return this;
- }
-
- /**
- * Runs the given runnable whenever the button is newly pressed.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link #onTrue(Command)}, creating the InstantCommand manually
- */
- @Deprecated
- public Button whenPressed(final Runnable toRun, Subsystem... requirements) {
- whenActive(toRun, requirements);
- return this;
- }
-
- /**
- * Constantly starts the given command while the button is held.
- *
- * <p>{@link Command#schedule()} will be called repeatedly while the button is held, and will be
- * canceled when the button is released.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Use {@link #whileTrue(Command)} with {@link
- * edu.wpi.first.wpilibj2.command.RepeatCommand RepeatCommand}.
- */
- @Deprecated
- public Button whileHeld(final Command command) {
- whileActiveContinuous(command);
- return this;
- }
-
- /**
- * Constantly runs the given runnable while the button is held.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this button, so calls can be chained
- * @deprecated Use {@link #whileTrue(Command)} and construct a RunCommand manually
- */
- @Deprecated
- public Button whileHeld(final Runnable toRun, Subsystem... requirements) {
- whileActiveContinuous(toRun, requirements);
- return this;
- }
-
- /**
- * Starts the given command when the button is first pressed, and cancels it when it is released,
- * but does not start it again if it ends or is otherwise interrupted.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link Trigger#whileTrue(Command)}
- */
- @Deprecated
- public Button whenHeld(final Command command) {
- whileActiveOnce(command);
- return this;
- }
-
- /**
- * Starts the command when the button is released. The command is set to be interruptible.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link Trigger#onFalse(Command)}
- */
- @Deprecated
- public Button whenReleased(final Command command) {
- whenInactive(command);
- return this;
- }
-
- /**
- * Runs the given runnable when the button is released.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link Trigger#onFalse(Command)}, creating the InstantCommand manually
- */
- @Deprecated
- public Button whenReleased(final Runnable toRun, Subsystem... requirements) {
- whenInactive(toRun, requirements);
- return this;
- }
-
- /**
- * Toggles the command whenever the button is pressed (on, then off, then on). The command is set
- * to be interruptible.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Replace with {@link Trigger#toggleOnTrue(Command)}
- */
- @Deprecated
- public Button toggleWhenPressed(final Command command) {
- toggleWhenActive(command);
- return this;
- }
-
- /**
- * Cancels the command when the button is pressed.
- *
- * @param command the command to start
- * @return this button, so calls can be chained
- * @deprecated Instead, pass this as an end condition to {@link Command#until(BooleanSupplier)}.
- */
- @Deprecated
- public Button cancelWhenPressed(final Command command) {
- cancelWhenActive(command);
- return this;
- }
-}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandJoystick.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandJoystick.java
index 9f3d48a..f993609 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandJoystick.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandJoystick.java
@@ -9,7 +9,7 @@
import edu.wpi.first.wpilibj2.command.CommandScheduler;
/**
- * A subclass of {@link Joystick} with {@link Trigger} factories for command-based.
+ * A version of {@link Joystick} with {@link Trigger} factories for command-based.
*
* @see Joystick
*/
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandPS5Controller.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandPS5Controller.java
new file mode 100644
index 0000000..6b149d6
--- /dev/null
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandPS5Controller.java
@@ -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();
+ }
+}
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandXboxController.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandXboxController.java
index 1e83e83..6969c98 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandXboxController.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/CommandXboxController.java
@@ -9,7 +9,7 @@
import edu.wpi.first.wpilibj2.command.CommandScheduler;
/**
- * A subclass of {@link XboxController} with {@link Trigger} factories for command-based.
+ * A version of {@link XboxController} with {@link Trigger} factories for command-based.
*
* @see XboxController
*/
@@ -261,13 +261,13 @@
* 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 @@
* button loop}.
*/
public Trigger leftTrigger(double threshold) {
- return leftTrigger(CommandScheduler.getInstance().getDefaultButtonLoop(), threshold);
+ return leftTrigger(threshold, CommandScheduler.getInstance().getDefaultButtonLoop());
}
/**
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/InternalButton.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/InternalButton.java
index 3106264..f4897f2 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/InternalButton.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/InternalButton.java
@@ -12,8 +12,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("deprecation")
-public class InternalButton extends Button {
+public class InternalButton extends Trigger {
// need to be references, so they can be mutated after being captured in the constructor.
private final AtomicBoolean m_pressed;
private final AtomicBoolean m_inverted;
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/JoystickButton.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/JoystickButton.java
index f22d443..e85b666 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/JoystickButton.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/JoystickButton.java
@@ -9,12 +9,11 @@
import edu.wpi.first.wpilibj.GenericHID;
/**
- * A {@link Button} that gets its state from a {@link GenericHID}.
+ * A {@link Trigger} that gets its state from a {@link GenericHID}.
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("deprecation")
-public class JoystickButton extends Button {
+public class JoystickButton extends Trigger {
/**
* Creates a joystick button for triggering commands.
*
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/NetworkButton.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/NetworkButton.java
index b21cd97..0fb5571 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/NetworkButton.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/NetworkButton.java
@@ -12,12 +12,11 @@
import edu.wpi.first.networktables.NetworkTableInstance;
/**
- * A {@link Button} that uses a {@link NetworkTable} boolean field.
+ * A {@link Trigger} that uses a {@link NetworkTable} boolean field.
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("deprecation")
-public class NetworkButton extends Button {
+public class NetworkButton extends Trigger {
/**
* Creates a NetworkButton that commands can be bound to.
*
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/POVButton.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/POVButton.java
index 28087ae..b8a63e4 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/POVButton.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/POVButton.java
@@ -9,12 +9,11 @@
import edu.wpi.first.wpilibj.GenericHID;
/**
- * A {@link Button} that gets its state from a POV on a {@link GenericHID}.
+ * A {@link Trigger} that gets its state from a POV on a {@link GenericHID}.
*
* <p>This class is provided by the NewCommands VendorDep
*/
-@SuppressWarnings("deprecation")
-public class POVButton extends Button {
+public class POVButton extends Trigger {
/**
* Creates a POV button for triggering commands.
*
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
index 19b8b20..5bdee37 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
@@ -7,12 +7,9 @@
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.math.filter.Debouncer;
-import edu.wpi.first.wpilibj.event.BooleanEvent;
import edu.wpi.first.wpilibj.event.EventLoop;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
-import edu.wpi.first.wpilibj2.command.InstantCommand;
-import edu.wpi.first.wpilibj2.command.Subsystem;
import java.util.function.BooleanSupplier;
/**
@@ -52,12 +49,6 @@
this(CommandScheduler.getInstance().getDefaultButtonLoop(), condition);
}
- /** Creates a new trigger that is always `false`. */
- @Deprecated
- public Trigger() {
- this(() -> false);
- }
-
/**
* Starts the given command whenever the condition changes from `false` to `true`.
*
@@ -65,7 +56,7 @@
* @return this trigger, so calls can be chained
*/
public Trigger onTrue(Command command) {
- requireNonNullParam(command, "command", "onRising");
+ requireNonNullParam(command, "command", "onTrue");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -91,7 +82,7 @@
* @return this trigger, so calls can be chained
*/
public Trigger onFalse(Command command) {
- requireNonNullParam(command, "command", "onFalling");
+ requireNonNullParam(command, "command", "onFalse");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -121,7 +112,7 @@
* @return this trigger, so calls can be chained
*/
public Trigger whileTrue(Command command) {
- requireNonNullParam(command, "command", "whileHigh");
+ requireNonNullParam(command, "command", "whileTrue");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -153,7 +144,7 @@
* @return this trigger, so calls can be chained
*/
public Trigger whileFalse(Command command) {
- requireNonNullParam(command, "command", "whileLow");
+ requireNonNullParam(command, "command", "whileFalse");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -181,7 +172,7 @@
* @return this trigger, so calls can be chained
*/
public Trigger toggleOnTrue(Command command) {
- requireNonNullParam(command, "command", "toggleOnRising");
+ requireNonNullParam(command, "command", "toggleOnTrue");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -205,13 +196,13 @@
}
/**
- * Toggles a command when the condition changes from `true` to the low state.
+ * Toggles a command when the condition changes from `true` to `false`.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
public Trigger toggleOnFalse(Command command) {
- requireNonNullParam(command, "command", "toggleOnFalling");
+ requireNonNullParam(command, "command", "toggleOnFalse");
m_loop.bind(
new Runnable() {
private boolean m_pressedLast = m_condition.getAsBoolean();
@@ -234,238 +225,6 @@
return this;
}
- /**
- * Starts the given command whenever the trigger just becomes active.
- *
- * @param command the command to start
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #onTrue(Command)} instead.
- */
- @Deprecated
- public Trigger whenActive(final Command command) {
- requireNonNullParam(command, "command", "whenActive");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (!m_pressedLast && pressed) {
- command.schedule();
- }
-
- m_pressedLast = pressed;
- }
- });
- return this;
- }
-
- /**
- * Runs the given runnable whenever the trigger just becomes active.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this trigger, so calls can be chained
- * @deprecated Replace with {@link #onTrue(Command)}, creating the InstantCommand manually
- */
- @Deprecated
- public Trigger whenActive(final Runnable toRun, Subsystem... requirements) {
- return whenActive(new InstantCommand(toRun, requirements));
- }
-
- /**
- * Constantly starts the given command while the button is held.
- *
- * <p>{@link Command#schedule()} will be called repeatedly while the trigger is active, and will
- * be canceled when the trigger becomes inactive.
- *
- * @param command the command to start
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #whileTrue(Command)} with {@link
- * edu.wpi.first.wpilibj2.command.RepeatCommand RepeatCommand}, or bind {@link
- * Command#schedule() command::schedule} to {@link BooleanEvent#ifHigh(Runnable)} (passing no
- * requirements).
- */
- @Deprecated
- public Trigger whileActiveContinuous(final Command command) {
- requireNonNullParam(command, "command", "whileActiveContinuous");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (pressed) {
- command.schedule();
- } else if (m_pressedLast) {
- command.cancel();
- }
-
- m_pressedLast = pressed;
- }
- });
-
- return this;
- }
-
- /**
- * Constantly runs the given runnable while the button is held.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #whileTrue(Command)} and construct a RunCommand manually
- */
- @Deprecated
- public Trigger whileActiveContinuous(final Runnable toRun, Subsystem... requirements) {
- return whileActiveContinuous(new InstantCommand(toRun, requirements));
- }
-
- /**
- * Starts the given command when the trigger initially becomes active, and ends it when it becomes
- * inactive, but does not re-start it in-between.
- *
- * @param command the command to start
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #whileTrue(Command)} instead.
- */
- @Deprecated
- public Trigger whileActiveOnce(final Command command) {
- requireNonNullParam(command, "command", "whileActiveOnce");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (!m_pressedLast && pressed) {
- command.schedule();
- } else if (m_pressedLast && !pressed) {
- command.cancel();
- }
-
- m_pressedLast = pressed;
- }
- });
- return this;
- }
-
- /**
- * Starts the command when the trigger becomes inactive.
- *
- * @param command the command to start
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #onFalse(Command)} instead.
- */
- @Deprecated
- public Trigger whenInactive(final Command command) {
- requireNonNullParam(command, "command", "whenInactive");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (m_pressedLast && !pressed) {
- command.schedule();
- }
-
- m_pressedLast = pressed;
- }
- });
-
- return this;
- }
-
- /**
- * Runs the given runnable when the trigger becomes inactive.
- *
- * @param toRun the runnable to run
- * @param requirements the required subsystems
- * @return this trigger, so calls can be chained
- * @deprecated Construct the InstantCommand manually and replace with {@link #onFalse(Command)}
- */
- @Deprecated
- public Trigger whenInactive(final Runnable toRun, Subsystem... requirements) {
- return whenInactive(new InstantCommand(toRun, requirements));
- }
-
- /**
- * Toggles a command when the trigger becomes active.
- *
- * @param command the command to toggle
- * @return this trigger, so calls can be chained
- * @deprecated Use {@link #toggleOnTrue(Command)} instead.
- */
- @Deprecated
- public Trigger toggleWhenActive(final Command command) {
- requireNonNullParam(command, "command", "toggleWhenActive");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (!m_pressedLast && pressed) {
- if (command.isScheduled()) {
- command.cancel();
- } else {
- command.schedule();
- }
- }
-
- m_pressedLast = pressed;
- }
- });
-
- return this;
- }
-
- /**
- * Cancels a command when the trigger becomes active.
- *
- * @param command the command to cancel
- * @return this trigger, so calls can be chained
- * @deprecated Instead, pass this as an end condition to {@link Command#until(BooleanSupplier)}.
- */
- @Deprecated
- public Trigger cancelWhenActive(final Command command) {
- requireNonNullParam(command, "command", "cancelWhenActive");
-
- m_loop.bind(
- new Runnable() {
- private boolean m_pressedLast = m_condition.getAsBoolean();
-
- @Override
- public void run() {
- boolean pressed = m_condition.getAsBoolean();
-
- if (!m_pressedLast && pressed) {
- command.cancel();
- }
-
- m_pressedLast = pressed;
- }
- });
-
- return this;
- }
-
@Override
public boolean getAsBoolean() {
return m_condition.getAsBoolean();
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp
index b173ada..66de555 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp
@@ -4,6 +4,9 @@
#include "frc2/command/Command.h"
+#include <wpi/sendable/SendableBuilder.h>
+#include <wpi/sendable/SendableRegistry.h>
+
#include "frc2/command/CommandHelper.h"
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/ConditionalCommand.h"
@@ -11,7 +14,6 @@
#include "frc2/command/ParallelCommandGroup.h"
#include "frc2/command/ParallelDeadlineGroup.h"
#include "frc2/command/ParallelRaceGroup.h"
-#include "frc2/command/PerpetualCommand.h"
#include "frc2/command/RepeatCommand.h"
#include "frc2/command/SequentialCommandGroup.h"
#include "frc2/command/WaitCommand.h"
@@ -20,6 +22,10 @@
using namespace frc2;
+Command::Command() {
+ wpi::SendableRegistry::Add(this, GetTypeName(*this));
+}
+
Command::~Command() {
CommandScheduler::GetInstance().Cancel(this);
}
@@ -33,6 +39,38 @@
void Command::Execute() {}
void Command::End(bool interrupted) {}
+wpi::SmallSet<Subsystem*, 4> Command::GetRequirements() const {
+ return m_requirements;
+}
+
+void Command::AddRequirements(Requirements requirements) {
+ m_requirements.insert(requirements.begin(), requirements.end());
+}
+
+void Command::AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements) {
+ m_requirements.insert(requirements.begin(), requirements.end());
+}
+
+void Command::AddRequirements(Subsystem* requirement) {
+ m_requirements.insert(requirement);
+}
+
+void Command::SetName(std::string_view name) {
+ wpi::SendableRegistry::SetName(this, name);
+}
+
+std::string Command::GetName() const {
+ return wpi::SendableRegistry::GetName(this);
+}
+
+std::string Command::GetSubsystem() const {
+ return wpi::SendableRegistry::GetSubsystem(this);
+}
+
+void Command::SetSubsystem(std::string_view subsystem) {
+ wpi::SendableRegistry::SetSubsystem(this, subsystem);
+}
+
CommandPtr Command::WithTimeout(units::second_t duration) && {
return std::move(*this).ToPtr().WithTimeout(duration);
}
@@ -41,6 +79,10 @@
return std::move(*this).ToPtr().Until(std::move(condition));
}
+CommandPtr Command::OnlyWhile(std::function<bool()> condition) && {
+ return std::move(*this).ToPtr().OnlyWhile(std::move(condition));
+}
+
CommandPtr Command::IgnoringDisable(bool doesRunWhenDisabled) && {
return std::move(*this).ToPtr().IgnoringDisable(doesRunWhenDisabled);
}
@@ -50,40 +92,17 @@
return std::move(*this).ToPtr().WithInterruptBehavior(interruptBehavior);
}
-CommandPtr Command::WithInterrupt(std::function<bool()> condition) && {
- return std::move(*this).ToPtr().Until(std::move(condition));
-}
-
-CommandPtr Command::BeforeStarting(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) && {
- return std::move(*this).BeforeStarting(
- std::move(toRun), {requirements.begin(), requirements.end()});
-}
-
-CommandPtr Command::BeforeStarting(
- std::function<void()> toRun, std::span<Subsystem* const> requirements) && {
+CommandPtr Command::BeforeStarting(std::function<void()> toRun,
+ Requirements requirements) && {
return std::move(*this).ToPtr().BeforeStarting(std::move(toRun),
requirements);
}
CommandPtr Command::AndThen(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) && {
- return std::move(*this).AndThen(std::move(toRun),
- {requirements.begin(), requirements.end()});
-}
-
-CommandPtr Command::AndThen(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) && {
+ Requirements requirements) && {
return std::move(*this).ToPtr().AndThen(std::move(toRun), requirements);
}
-PerpetualCommand Command::Perpetually() && {
- WPI_IGNORE_DEPRECATED
- return PerpetualCommand(std::move(*this).TransferOwnership());
- WPI_UNIGNORE_DEPRECATED
-}
-
CommandPtr Command::Repeatedly() && {
return std::move(*this).ToPtr().Repeatedly();
}
@@ -96,11 +115,19 @@
return std::move(*this).ToPtr().Unless(std::move(condition));
}
+CommandPtr Command::OnlyIf(std::function<bool()> condition) && {
+ return std::move(*this).ToPtr().OnlyIf(std::move(condition));
+}
+
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));
}
@@ -128,12 +155,6 @@
return hasRequirement;
}
-std::string Command::GetName() const {
- return GetTypeName(*this);
-}
-
-void Command::SetName(std::string_view name) {}
-
bool Command::IsComposed() const {
return m_isComposed;
}
@@ -142,12 +163,37 @@
m_isComposed = isComposed;
}
-bool Command::IsGrouped() const {
- return IsComposed();
-}
-
-void Command::SetGrouped(bool grouped) {
- SetComposed(grouped);
+void Command::InitSendable(wpi::SendableBuilder& builder) {
+ builder.SetSmartDashboardType("Command");
+ builder.AddStringProperty(
+ ".name", [this] { return GetName(); }, nullptr);
+ builder.AddBooleanProperty(
+ "running", [this] { return IsScheduled(); },
+ [this](bool value) {
+ bool isScheduled = IsScheduled();
+ if (value && !isScheduled) {
+ Schedule();
+ } else if (!value && isScheduled) {
+ Cancel();
+ }
+ });
+ builder.AddBooleanProperty(
+ ".isParented", [this] { return IsComposed(); }, nullptr);
+ builder.AddStringProperty(
+ "interruptBehavior",
+ [this] {
+ switch (GetInterruptionBehavior()) {
+ case Command::InterruptionBehavior::kCancelIncoming:
+ return "kCancelIncoming";
+ case Command::InterruptionBehavior::kCancelSelf:
+ return "kCancelSelf";
+ default:
+ return "Invalid";
+ }
+ },
+ nullptr);
+ builder.AddBooleanProperty(
+ "runsWhenDisabled", [this] { return RunsWhenDisabled(); }, nullptr);
}
namespace frc2 {
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandBase.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandBase.cpp
index 416c78b..7e2fad1 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandBase.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandBase.cpp
@@ -3,82 +3,3 @@
// the WPILib BSD license file in the root directory of this project.
#include "frc2/command/CommandBase.h"
-
-#include <wpi/sendable/SendableBuilder.h>
-#include <wpi/sendable/SendableRegistry.h>
-
-using namespace frc2;
-
-CommandBase::CommandBase() {
- wpi::SendableRegistry::Add(this, GetTypeName(*this));
-}
-
-void CommandBase::AddRequirements(
- std::initializer_list<Subsystem*> requirements) {
- m_requirements.insert(requirements.begin(), requirements.end());
-}
-
-void CommandBase::AddRequirements(std::span<Subsystem* const> requirements) {
- m_requirements.insert(requirements.begin(), requirements.end());
-}
-
-void CommandBase::AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements) {
- m_requirements.insert(requirements.begin(), requirements.end());
-}
-
-void CommandBase::AddRequirements(Subsystem* requirement) {
- m_requirements.insert(requirement);
-}
-
-wpi::SmallSet<Subsystem*, 4> CommandBase::GetRequirements() const {
- return m_requirements;
-}
-
-void CommandBase::SetName(std::string_view name) {
- wpi::SendableRegistry::SetName(this, name);
-}
-
-std::string CommandBase::GetName() const {
- return wpi::SendableRegistry::GetName(this);
-}
-
-std::string CommandBase::GetSubsystem() const {
- return wpi::SendableRegistry::GetSubsystem(this);
-}
-
-void CommandBase::SetSubsystem(std::string_view subsystem) {
- wpi::SendableRegistry::SetSubsystem(this, subsystem);
-}
-
-void CommandBase::InitSendable(wpi::SendableBuilder& builder) {
- builder.SetSmartDashboardType("Command");
- builder.AddStringProperty(
- ".name", [this] { return GetName(); }, nullptr);
- builder.AddBooleanProperty(
- "running", [this] { return IsScheduled(); },
- [this](bool value) {
- bool isScheduled = IsScheduled();
- if (value && !isScheduled) {
- Schedule();
- } else if (!value && isScheduled) {
- Cancel();
- }
- });
- builder.AddBooleanProperty(
- ".isParented", [this] { return IsComposed(); }, nullptr);
- builder.AddStringProperty(
- "interruptBehavior",
- [this] {
- switch (GetInterruptionBehavior()) {
- case Command::InterruptionBehavior::kCancelIncoming:
- return "kCancelIncoming";
- case Command::InterruptionBehavior::kCancelSelf:
- return "kCancelSelf";
- default:
- return "Invalid";
- }
- },
- nullptr);
- builder.AddBooleanProperty(
- "runsWhenDisabled", [this] { return RunsWhenDisabled(); }, nullptr);
-}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandGroupBase.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandGroupBase.cpp
deleted file mode 100644
index eb9c293..0000000
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandGroupBase.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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/CommandGroupBase.h"
-
-using namespace frc2;
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp
index 44150a2..6f7e418 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp
@@ -86,15 +86,7 @@
}
CommandPtr CommandPtr::AndThen(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) && {
- AssertValid();
- return std::move(*this).AndThen(CommandPtr(
- std::make_unique<InstantCommand>(std::move(toRun), requirements)));
-}
-
-CommandPtr CommandPtr::AndThen(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) && {
+ Requirements requirements) && {
AssertValid();
return std::move(*this).AndThen(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
@@ -109,16 +101,8 @@
return std::move(*this);
}
-CommandPtr CommandPtr::BeforeStarting(
- std::function<void()> toRun, std::span<Subsystem* const> requirements) && {
- AssertValid();
- return std::move(*this).BeforeStarting(CommandPtr(
- std::make_unique<InstantCommand>(std::move(toRun), requirements)));
-}
-
-CommandPtr CommandPtr::BeforeStarting(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) && {
+CommandPtr CommandPtr::BeforeStarting(std::function<void()> toRun,
+ Requirements requirements) && {
AssertValid();
return std::move(*this).BeforeStarting(CommandPtr(
std::make_unique<InstantCommand>(std::move(toRun), requirements)));
@@ -151,6 +135,11 @@
return std::move(*this);
}
+CommandPtr CommandPtr::OnlyWhile(std::function<bool()> condition) && {
+ AssertValid();
+ return std::move(*this).Until(std::not_fn(std::move(condition)));
+}
+
CommandPtr CommandPtr::Unless(std::function<bool()> condition) && {
AssertValid();
m_ptr = std::make_unique<ConditionalCommand>(
@@ -159,6 +148,11 @@
return std::move(*this);
}
+CommandPtr CommandPtr::OnlyIf(std::function<bool()> condition) && {
+ AssertValid();
+ return std::move(*this).Unless(std::not_fn(std::move(condition)));
+}
+
CommandPtr CommandPtr::DeadlineWith(CommandPtr&& parallel) && {
AssertValid();
std::vector<std::unique_ptr<Command>> vec;
@@ -209,7 +203,13 @@
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) {
@@ -226,37 +226,37 @@
return std::move(wrapper).ToPtr();
}
-CommandBase* CommandPtr::get() const {
+Command* CommandPtr::get() const& {
AssertValid();
return m_ptr.get();
}
-std::unique_ptr<CommandBase> CommandPtr::Unwrap() && {
+std::unique_ptr<Command> CommandPtr::Unwrap() && {
AssertValid();
return std::move(m_ptr);
}
-void CommandPtr::Schedule() const {
+void CommandPtr::Schedule() const& {
AssertValid();
CommandScheduler::GetInstance().Schedule(*this);
}
-void CommandPtr::Cancel() const {
+void CommandPtr::Cancel() const& {
AssertValid();
CommandScheduler::GetInstance().Cancel(*this);
}
-bool CommandPtr::IsScheduled() const {
+bool CommandPtr::IsScheduled() const& {
AssertValid();
return CommandScheduler::GetInstance().IsScheduled(*this);
}
-bool CommandPtr::HasRequirement(Subsystem* requirement) const {
+bool CommandPtr::HasRequirement(Subsystem* requirement) const& {
AssertValid();
return m_ptr->HasRequirement(requirement);
}
-CommandPtr::operator bool() const {
+CommandPtr::operator bool() const& {
return m_ptr.operator bool();
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp
index 5a4782f..d61ffbd 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp
@@ -13,10 +13,10 @@
#include <hal/FRCUsageReporting.h>
#include <hal/HALBase.h>
#include <networktables/IntegerArrayTopic.h>
-#include <networktables/NTSendableBuilder.h>
#include <networktables/StringArrayTopic.h>
#include <wpi/DenseMap.h>
#include <wpi/SmallVector.h>
+#include <wpi/sendable/SendableBuilder.h>
#include <wpi/sendable/SendableRegistry.h>
#include "frc2/command/CommandPtr.h"
@@ -48,15 +48,16 @@
// every command.
wpi::SmallVector<Action, 4> initActions;
wpi::SmallVector<Action, 4> executeActions;
- wpi::SmallVector<Action, 4> interruptActions;
+ wpi::SmallVector<InterruptAction, 4> interruptActions;
wpi::SmallVector<Action, 4> finishActions;
// Flag and queues for avoiding concurrent modification if commands are
// scheduled/canceled during run
-
bool inRunLoop = false;
wpi::SmallVector<Command*, 4> toSchedule;
- wpi::SmallVector<Command*, 4> toCancel;
+ wpi::SmallVector<Command*, 4> toCancelCommands;
+ wpi::SmallVector<std::optional<Command*>, 4> toCancelInterruptors;
+ wpi::SmallSet<Command*, 4> endingCommands;
};
template <typename TMap, typename TKey>
@@ -107,10 +108,6 @@
return &(m_impl->defaultButtonLoop);
}
-void CommandScheduler::ClearButtons() {
- m_impl->activeButtonLoop->Clear();
-}
-
void CommandScheduler::Schedule(Command* command) {
if (m_impl->inRunLoop) {
m_impl->toSchedule.emplace_back(command);
@@ -142,7 +139,7 @@
if (isDisjoint || allInterruptible) {
if (allInterruptible) {
for (auto&& cmdToCancel : intersection) {
- Cancel(cmdToCancel);
+ Cancel(cmdToCancel, std::make_optional(command));
}
}
m_impl->scheduledCommands.insert(command);
@@ -197,10 +194,11 @@
m_watchdog.AddEpoch("buttons.Run()");
m_impl->inRunLoop = true;
+ bool isDisabled = frc::RobotState::IsDisabled();
// Run scheduled commands, remove finished commands.
for (Command* command : m_impl->scheduledCommands) {
- if (!command->RunsWhenDisabled() && frc::RobotState::IsDisabled()) {
- Cancel(command);
+ if (isDisabled && !command->RunsWhenDisabled()) {
+ Cancel(command, std::nullopt);
continue;
}
@@ -211,16 +209,18 @@
m_watchdog.AddEpoch(command->GetName() + ".Execute()");
if (command->IsFinished()) {
+ m_impl->endingCommands.insert(command);
command->End(false);
for (auto&& action : m_impl->finishActions) {
action(*command);
}
+ m_impl->endingCommands.erase(command);
+ m_impl->scheduledCommands.erase(command);
for (auto&& requirement : command->GetRequirements()) {
m_impl->requirements.erase(requirement);
}
- m_impl->scheduledCommands.erase(command);
m_watchdog.AddEpoch(command->GetName() + ".End(false)");
}
}
@@ -230,12 +230,13 @@
Schedule(command);
}
- for (auto&& command : m_impl->toCancel) {
- Cancel(command);
+ for (size_t i = 0; i < m_impl->toCancelCommands.size(); i++) {
+ Cancel(m_impl->toCancelCommands[i], m_impl->toCancelInterruptors[i]);
}
m_impl->toSchedule.clear();
- m_impl->toCancel.clear();
+ m_impl->toCancelCommands.clear();
+ m_impl->toCancelInterruptors.clear();
// Add default commands for un-required registered subsystems.
for (auto&& subsystem : m_impl->subsystems) {
@@ -295,6 +296,10 @@
}
}
+void CommandScheduler::UnregisterAllSubsystems() {
+ m_impl->subsystems.clear();
+}
+
void CommandScheduler::SetDefaultCommand(Subsystem* subsystem,
CommandPtr&& defaultCommand) {
if (!defaultCommand.get()->HasRequirement(subsystem)) {
@@ -319,33 +324,41 @@
}
}
-void CommandScheduler::Cancel(Command* command) {
+void CommandScheduler::Cancel(Command* command,
+ std::optional<Command*> interruptor) {
if (!m_impl) {
return;
}
-
+ if (m_impl->endingCommands.contains(command)) {
+ return;
+ }
if (m_impl->inRunLoop) {
- m_impl->toCancel.emplace_back(command);
+ m_impl->toCancelCommands.emplace_back(command);
+ m_impl->toCancelInterruptors.emplace_back(interruptor);
return;
}
-
- auto find = m_impl->scheduledCommands.find(command);
- if (find == m_impl->scheduledCommands.end()) {
+ if (!IsScheduled(command)) {
return;
}
- m_impl->scheduledCommands.erase(*find);
+ m_impl->endingCommands.insert(command);
+ command->End(true);
+ for (auto&& action : m_impl->interruptActions) {
+ action(*command, interruptor);
+ }
+ m_impl->endingCommands.erase(command);
+ m_impl->scheduledCommands.erase(command);
for (auto&& requirement : m_impl->requirements) {
if (requirement.second == command) {
m_impl->requirements.erase(requirement.first);
}
}
- command->End(true);
- for (auto&& action : m_impl->interruptActions) {
- action(*command);
- }
m_watchdog.AddEpoch(command->GetName() + ".End(true)");
}
+void CommandScheduler::Cancel(Command* command) {
+ Cancel(command, std::nullopt);
+}
+
void CommandScheduler::Cancel(const CommandPtr& command) {
Cancel(command.get());
}
@@ -424,6 +437,14 @@
}
void CommandScheduler::OnCommandInterrupt(Action action) {
+ m_impl->interruptActions.emplace_back(
+ [action = std::move(action)](const Command& command,
+ const std::optional<Command*>& interruptor) {
+ action(command);
+ });
+}
+
+void CommandScheduler::OnCommandInterrupt(InterruptAction action) {
m_impl->interruptActions.emplace_back(std::move(action));
}
@@ -433,9 +454,10 @@
void CommandScheduler::RequireUngrouped(const Command* command) {
if (command->IsComposed()) {
- throw FRC_MakeError(
- frc::err::CommandIllegalUse,
- "Commands cannot be added to more than one CommandGroup");
+ throw FRC_MakeError(frc::err::CommandIllegalUse,
+ "Commands that have been composed may not be added to "
+ "another composition or scheduled "
+ "individually!");
}
}
@@ -453,36 +475,40 @@
}
}
-void CommandScheduler::InitSendable(nt::NTSendableBuilder& builder) {
+void CommandScheduler::InitSendable(wpi::SendableBuilder& builder) {
builder.SetSmartDashboardType("Scheduler");
- builder.SetUpdateTable(
- [this,
- namesPub = nt::StringArrayTopic{builder.GetTopic("Names")}.Publish(),
- idsPub = nt::IntegerArrayTopic{builder.GetTopic("Ids")}.Publish(),
- cancelEntry = nt::IntegerArrayTopic{builder.GetTopic("Cancel")}.GetEntry(
- {})]() mutable {
- auto toCancel = cancelEntry.Get();
- if (!toCancel.empty()) {
- for (auto cancel : cancelEntry.Get()) {
- uintptr_t ptrTmp = static_cast<uintptr_t>(cancel);
- Command* command = reinterpret_cast<Command*>(ptrTmp);
- if (m_impl->scheduledCommands.find(command) !=
- m_impl->scheduledCommands.end()) {
- Cancel(command);
- }
- }
- cancelEntry.Set({});
- }
-
- wpi::SmallVector<std::string, 8> names;
- wpi::SmallVector<int64_t, 8> ids;
+ builder.AddStringArrayProperty(
+ "Names",
+ [this]() mutable {
+ std::vector<std::string> names;
for (Command* command : m_impl->scheduledCommands) {
names.emplace_back(command->GetName());
+ }
+ return names;
+ },
+ nullptr);
+ builder.AddIntegerArrayProperty(
+ "Ids",
+ [this]() mutable {
+ std::vector<int64_t> ids;
+ for (Command* command : m_impl->scheduledCommands) {
uintptr_t ptrTmp = reinterpret_cast<uintptr_t>(command);
ids.emplace_back(static_cast<int64_t>(ptrTmp));
}
- namesPub.Set(names);
- idsPub.Set(ids);
+ return ids;
+ },
+ nullptr);
+ builder.AddIntegerArrayProperty(
+ "Cancel", []() { return std::vector<int64_t>{}; },
+ [this](std::span<const int64_t> toCancel) mutable {
+ for (auto cancel : toCancel) {
+ uintptr_t ptrTmp = static_cast<uintptr_t>(cancel);
+ Command* command = reinterpret_cast<Command*>(ptrTmp);
+ if (m_impl->scheduledCommands.find(command) !=
+ m_impl->scheduledCommands.end()) {
+ Cancel(command);
+ }
+ }
});
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp
index 1932e45..31a4b1f 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp
@@ -5,12 +5,14 @@
#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"
#include "frc2/command/ParallelDeadlineGroup.h"
#include "frc2/command/ParallelRaceGroup.h"
#include "frc2/command/PrintCommand.h"
+#include "frc2/command/ProxyCommand.h"
#include "frc2/command/RunCommand.h"
#include "frc2/command/SequentialCommandGroup.h"
#include "frc2/command/WaitCommand.h"
@@ -24,37 +26,21 @@
return InstantCommand().ToPtr();
}
-CommandPtr cmd::RunOnce(std::function<void()> action,
- std::initializer_list<Subsystem*> requirements) {
- return InstantCommand(std::move(action), requirements).ToPtr();
+CommandPtr cmd::Idle(Requirements requirements) {
+ return Run([] {}, requirements);
}
CommandPtr cmd::RunOnce(std::function<void()> action,
- std::span<Subsystem* const> requirements) {
+ Requirements requirements) {
return InstantCommand(std::move(action), requirements).ToPtr();
}
-CommandPtr cmd::Run(std::function<void()> action,
- std::initializer_list<Subsystem*> requirements) {
- return RunCommand(std::move(action), requirements).ToPtr();
-}
-
-CommandPtr cmd::Run(std::function<void()> action,
- std::span<Subsystem* const> requirements) {
+CommandPtr cmd::Run(std::function<void()> action, Requirements requirements) {
return RunCommand(std::move(action), requirements).ToPtr();
}
CommandPtr cmd::StartEnd(std::function<void()> start, std::function<void()> end,
- std::initializer_list<Subsystem*> requirements) {
- return FunctionalCommand(
- std::move(start), [] {},
- [end = std::move(end)](bool interrupted) { end(); },
- [] { return false; }, requirements)
- .ToPtr();
-}
-
-CommandPtr cmd::StartEnd(std::function<void()> start, std::function<void()> end,
- std::span<Subsystem* const> requirements) {
+ Requirements requirements) {
return FunctionalCommand(
std::move(start), [] {},
[end = std::move(end)](bool interrupted) { end(); },
@@ -63,15 +49,7 @@
}
CommandPtr cmd::RunEnd(std::function<void()> run, std::function<void()> end,
- std::initializer_list<Subsystem*> requirements) {
- return FunctionalCommand([] {}, std::move(run),
- [end = std::move(end)](bool interrupted) { end(); },
- [] { return false; }, requirements)
- .ToPtr();
-}
-
-CommandPtr cmd::RunEnd(std::function<void()> run, std::function<void()> end,
- std::span<Subsystem* const> requirements) {
+ Requirements requirements) {
return FunctionalCommand([] {}, std::move(run),
[end = std::move(end)](bool interrupted) { end(); },
[] { return false; }, requirements)
@@ -82,6 +60,14 @@
return PrintCommand(msg).ToPtr();
}
+CommandPtr cmd::DeferredProxy(wpi::unique_function<Command*()> supplier) {
+ return ProxyCommand(std::move(supplier)).ToPtr();
+}
+
+CommandPtr cmd::DeferredProxy(wpi::unique_function<CommandPtr()> supplier) {
+ return ProxyCommand(std::move(supplier)).ToPtr();
+}
+
CommandPtr cmd::Wait(units::second_t duration) {
return WaitCommand(duration).ToPtr();
}
@@ -97,6 +83,11 @@
.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();
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp
index 2610c96..4c07c7a 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp
@@ -53,8 +53,20 @@
return m_runsWhenDisabled;
}
+Command::InterruptionBehavior ConditionalCommand::GetInterruptionBehavior()
+ const {
+ if (m_onTrue->GetInterruptionBehavior() ==
+ InterruptionBehavior::kCancelSelf ||
+ m_onFalse->GetInterruptionBehavior() ==
+ InterruptionBehavior::kCancelSelf) {
+ return InterruptionBehavior::kCancelSelf;
+ } else {
+ return InterruptionBehavior::kCancelIncoming;
+ }
+}
+
void ConditionalCommand::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddStringProperty(
"onTrue", [this] { return m_onTrue->GetName(); }, nullptr);
builder.AddStringProperty(
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp
new file mode 100644
index 0000000..2a7f162
--- /dev/null
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp
@@ -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);
+}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp
index 02e8338..e4ff6ea 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp
@@ -6,22 +6,11 @@
using namespace frc2;
-FunctionalCommand::FunctionalCommand(
- std::function<void()> onInit, std::function<void()> onExecute,
- std::function<void(bool)> onEnd, std::function<bool()> isFinished,
- std::initializer_list<Subsystem*> requirements)
- : m_onInit{std::move(onInit)},
- m_onExecute{std::move(onExecute)},
- m_onEnd{std::move(onEnd)},
- m_isFinished{std::move(isFinished)} {
- AddRequirements(requirements);
-}
-
FunctionalCommand::FunctionalCommand(std::function<void()> onInit,
std::function<void()> onExecute,
std::function<void(bool)> onEnd,
std::function<bool()> isFinished,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: m_onInit{std::move(onInit)},
m_onExecute{std::move(onExecute)},
m_onEnd{std::move(onEnd)},
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp
index 7b73239..b78d30e 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp
@@ -7,13 +7,7 @@
using namespace frc2;
InstantCommand::InstantCommand(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements)
- : CommandHelper(
- std::move(toRun), [] {}, [](bool interrupted) {}, [] { return true; },
- requirements) {}
-
-InstantCommand::InstantCommand(std::function<void()> toRun,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: CommandHelper(
std::move(toRun), [] {}, [](bool interrupted) {}, [] { return true; },
requirements) {}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp
index d95d596..902c26b 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp
@@ -11,20 +11,20 @@
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
units::meters_per_second_t maxWheelVelocity,
std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
+ frc::PIDController frontLeftController,
+ frc::PIDController rearLeftController,
+ frc::PIDController frontRightController,
+ frc::PIDController rearRightController,
std::function<void(units::volt_t, units::volt_t, units::volt_t,
units::volt_t)>
output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_feedforward(feedforward),
@@ -33,13 +33,13 @@
m_desiredRotation(std::move(desiredRotation)),
m_maxWheelVelocity(maxWheelVelocity),
m_frontLeftController(
- std::make_unique<frc2::PIDController>(frontLeftController)),
+ std::make_unique<frc::PIDController>(frontLeftController)),
m_rearLeftController(
- std::make_unique<frc2::PIDController>(rearLeftController)),
+ std::make_unique<frc::PIDController>(rearLeftController)),
m_frontRightController(
- std::make_unique<frc2::PIDController>(frontRightController)),
+ std::make_unique<frc::PIDController>(frontRightController)),
m_rearRightController(
- std::make_unique<frc2::PIDController>(rearRightController)),
+ std::make_unique<frc::PIDController>(rearRightController)),
m_currentWheelSpeeds(std::move(currentWheelSpeeds)),
m_outputVolts(std::move(output)),
m_usePID(true) {
@@ -49,19 +49,19 @@
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
+ frc::PIDController frontLeftController,
+ frc::PIDController rearLeftController,
+ frc::PIDController frontRightController,
+ frc::PIDController rearRightController,
std::function<void(units::volt_t, units::volt_t, units::volt_t,
units::volt_t)>
output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_feedforward(feedforward),
@@ -69,13 +69,13 @@
m_controller(xController, yController, thetaController),
m_maxWheelVelocity(maxWheelVelocity),
m_frontLeftController(
- std::make_unique<frc2::PIDController>(frontLeftController)),
+ std::make_unique<frc::PIDController>(frontLeftController)),
m_rearLeftController(
- std::make_unique<frc2::PIDController>(rearLeftController)),
+ std::make_unique<frc::PIDController>(rearLeftController)),
m_frontRightController(
- std::make_unique<frc2::PIDController>(frontRightController)),
+ std::make_unique<frc::PIDController>(frontRightController)),
m_rearRightController(
- std::make_unique<frc2::PIDController>(rearRightController)),
+ std::make_unique<frc::PIDController>(rearRightController)),
m_currentWheelSpeeds(std::move(currentWheelSpeeds)),
m_outputVolts(std::move(output)),
m_usePID(true) {
@@ -84,89 +84,15 @@
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- units::meters_per_second_t maxWheelVelocity,
- std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
- std::function<void(units::volt_t, units::volt_t, units::volt_t,
- units::volt_t)>
- output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_feedforward(feedforward),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_desiredRotation(std::move(desiredRotation)),
- m_maxWheelVelocity(maxWheelVelocity),
- m_frontLeftController(
- std::make_unique<frc2::PIDController>(frontLeftController)),
- m_rearLeftController(
- std::make_unique<frc2::PIDController>(rearLeftController)),
- m_frontRightController(
- std::make_unique<frc2::PIDController>(frontRightController)),
- m_rearRightController(
- std::make_unique<frc2::PIDController>(rearRightController)),
- m_currentWheelSpeeds(std::move(currentWheelSpeeds)),
- m_outputVolts(std::move(output)),
- m_usePID(true) {
- AddRequirements(requirements);
-}
-
-MecanumControllerCommand::MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- units::meters_per_second_t maxWheelVelocity,
- std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
- std::function<void(units::volt_t, units::volt_t, units::volt_t,
- units::volt_t)>
- output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_feedforward(feedforward),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_maxWheelVelocity(maxWheelVelocity),
- m_frontLeftController(
- std::make_unique<frc2::PIDController>(frontLeftController)),
- m_rearLeftController(
- std::make_unique<frc2::PIDController>(rearLeftController)),
- m_frontRightController(
- std::make_unique<frc2::PIDController>(frontRightController)),
- m_rearRightController(
- std::make_unique<frc2::PIDController>(rearRightController)),
- m_currentWheelSpeeds(std::move(currentWheelSpeeds)),
- m_outputVolts(std::move(output)),
- m_usePID(true) {
- AddRequirements(requirements);
-}
-
-MecanumControllerCommand::MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
units::meters_per_second_t maxWheelVelocity,
std::function<void(units::meters_per_second_t, units::meters_per_second_t,
units::meters_per_second_t, units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -180,56 +106,14 @@
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<void(units::meters_per_second_t, units::meters_per_second_t,
units::meters_per_second_t, units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_maxWheelVelocity(maxWheelVelocity),
- m_outputVel(std::move(output)),
- m_usePID(false) {
- AddRequirements(requirements);
-}
-
-MecanumControllerCommand::MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- units::meters_per_second_t maxWheelVelocity,
- std::function<void(units::meters_per_second_t, units::meters_per_second_t,
- units::meters_per_second_t, units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_desiredRotation(std::move(desiredRotation)),
- m_maxWheelVelocity(maxWheelVelocity),
- m_outputVel(std::move(output)),
- m_usePID(false) {
- AddRequirements(requirements);
-}
-
-MecanumControllerCommand::MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- units::meters_per_second_t maxWheelVelocity,
- std::function<void(units::meters_per_second_t, units::meters_per_second_t,
- units::meters_per_second_t, units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -257,8 +141,7 @@
m_prevSpeeds = m_kinematics.ToWheelSpeeds(
frc::ChassisSpeeds{initialXVelocity, initialYVelocity, 0_rad_per_s});
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
if (m_usePID) {
m_frontLeftController->Reset();
m_rearLeftController->Reset();
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp
index 2081d07..5dc5add 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp
@@ -8,14 +8,7 @@
NotifierCommand::NotifierCommand(std::function<void()> toRun,
units::second_t period,
- std::initializer_list<Subsystem*> requirements)
- : m_toRun(toRun), m_notifier{std::move(toRun)}, m_period{period} {
- AddRequirements(requirements);
-}
-
-NotifierCommand::NotifierCommand(std::function<void()> toRun,
- units::second_t period,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: m_toRun(toRun), m_notifier{std::move(toRun)}, m_period{period} {
AddRequirements(requirements);
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDCommand.cpp
index 672fa47..361ec84 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDCommand.cpp
@@ -8,11 +8,11 @@
using namespace frc2;
-PIDCommand::PIDCommand(PIDController controller,
+PIDCommand::PIDCommand(frc::PIDController controller,
std::function<double()> measurementSource,
std::function<double()> setpointSource,
std::function<void(double)> useOutput,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_controller{std::move(controller)},
m_measurement{std::move(measurementSource)},
m_setpoint{std::move(setpointSource)},
@@ -20,30 +20,10 @@
AddRequirements(requirements);
}
-PIDCommand::PIDCommand(PIDController controller,
- std::function<double()> measurementSource,
- std::function<double()> setpointSource,
- std::function<void(double)> useOutput,
- std::span<Subsystem* const> requirements)
- : m_controller{std::move(controller)},
- m_measurement{std::move(measurementSource)},
- m_setpoint{std::move(setpointSource)},
- m_useOutput{std::move(useOutput)} {
- AddRequirements(requirements);
-}
-
-PIDCommand::PIDCommand(PIDController controller,
+PIDCommand::PIDCommand(frc::PIDController controller,
std::function<double()> measurementSource,
double setpoint, std::function<void(double)> useOutput,
- std::initializer_list<Subsystem*> requirements)
- : PIDCommand(
- controller, measurementSource, [setpoint] { return setpoint; },
- useOutput, requirements) {}
-
-PIDCommand::PIDCommand(PIDController controller,
- std::function<double()> measurementSource,
- double setpoint, std::function<void(double)> useOutput,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: PIDCommand(
controller, measurementSource, [setpoint] { return setpoint; },
useOutput, requirements) {}
@@ -60,6 +40,6 @@
m_useOutput(0);
}
-PIDController& PIDCommand::GetController() {
+frc::PIDController& PIDCommand::GetController() {
return m_controller;
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDSubsystem.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDSubsystem.cpp
index 8db032a..0764cb9 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDSubsystem.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/PIDSubsystem.cpp
@@ -8,7 +8,8 @@
using namespace frc2;
-PIDSubsystem::PIDSubsystem(PIDController controller, double initialPosition)
+PIDSubsystem::PIDSubsystem(frc::PIDController controller,
+ double initialPosition)
: m_controller{std::move(controller)} {
SetSetpoint(initialPosition);
AddChild("PID Controller", &m_controller);
@@ -42,6 +43,6 @@
return m_enabled;
}
-PIDController& PIDSubsystem::GetController() {
+frc::PIDController& PIDSubsystem::GetController() {
return m_controller;
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp
index 14c28c3..a6b5c1c 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp
@@ -97,7 +97,7 @@
}
void ParallelDeadlineGroup::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddStringProperty(
"deadline", [this] { return m_deadline->GetName(); }, nullptr);
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/PerpetualCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/PerpetualCommand.cpp
deleted file mode 100644
index 2d0af1e..0000000
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/PerpetualCommand.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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/PerpetualCommand.h"
-
-using namespace frc2;
-
-PerpetualCommand::PerpetualCommand(std::unique_ptr<Command>&& command) {
- CommandScheduler::GetInstance().RequireUngrouped(command.get());
- m_command = std::move(command);
- m_command->SetComposed(true);
- AddRequirements(m_command->GetRequirements());
-}
-
-void PerpetualCommand::Initialize() {
- m_command->Initialize();
-}
-
-void PerpetualCommand::Execute() {
- m_command->Execute();
-}
-
-void PerpetualCommand::End(bool interrupted) {
- m_command->End(interrupted);
-}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp
index cc1b815..eb4fb7c 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp
@@ -11,13 +11,22 @@
ProxyCommand::ProxyCommand(wpi::unique_function<Command*()> supplier)
: m_supplier(std::move(supplier)) {}
+ProxyCommand::ProxyCommand(wpi::unique_function<CommandPtr()> supplier)
+ : ProxyCommand([supplier = std::move(supplier),
+ holder = std::optional<CommandPtr>{}]() mutable {
+ holder = supplier();
+ return holder->get();
+ }) {}
+
ProxyCommand::ProxyCommand(Command* command)
- : m_supplier([command] { return command; }) {
+ : ProxyCommand([command] { return command; }) {
SetName(std::string{"Proxy("}.append(command->GetName()).append(")"));
}
-ProxyCommand::ProxyCommand(std::unique_ptr<Command> command)
- : m_supplier([command = std::move(command)] { return command.get(); }) {}
+ProxyCommand::ProxyCommand(std::unique_ptr<Command> command) {
+ SetName(std::string{"Proxy("}.append(command->GetName()).append(")"));
+ m_supplier = [command = std::move(command)] { return command.get(); };
+}
void ProxyCommand::Initialize() {
m_command = m_supplier();
@@ -31,8 +40,6 @@
m_command = nullptr;
}
-void ProxyCommand::Execute() {}
-
bool ProxyCommand::IsFinished() {
// because we're between `initialize` and `end`, `m_command` is necessarily
// not null but if called otherwise and m_command is null, it's UB, so we can
@@ -41,7 +48,7 @@
}
void ProxyCommand::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddStringProperty(
"proxied",
[this] {
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyScheduleCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyScheduleCommand.cpp
deleted file mode 100644
index dd0e2a7..0000000
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyScheduleCommand.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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/ProxyScheduleCommand.h"
-
-using namespace frc2;
-
-ProxyScheduleCommand::ProxyScheduleCommand(
- std::span<Command* const> toSchedule) {
- SetInsert(m_toSchedule, toSchedule);
-}
-
-ProxyScheduleCommand::ProxyScheduleCommand(Command* toSchedule) {
- SetInsert(m_toSchedule, {&toSchedule, 1});
-}
-
-void ProxyScheduleCommand::Initialize() {
- for (auto* command : m_toSchedule) {
- command->Schedule();
- }
-}
-
-void ProxyScheduleCommand::End(bool interrupted) {
- if (interrupted) {
- for (auto* command : m_toSchedule) {
- command->Cancel();
- }
- }
-}
-
-void ProxyScheduleCommand::Execute() {
- m_finished = true;
- for (auto* command : m_toSchedule) {
- m_finished &= !command->IsScheduled();
- }
-}
-
-bool ProxyScheduleCommand::IsFinished() {
- return m_finished;
-}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/RamseteCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/RamseteCommand.cpp
index d46cdd0..9145985 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/RamseteCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/RamseteCommand.cpp
@@ -16,39 +16,17 @@
frc::SimpleMotorFeedforward<units::meters> feedforward,
frc::DifferentialDriveKinematics kinematics,
std::function<frc::DifferentialDriveWheelSpeeds()> wheelSpeeds,
- frc2::PIDController leftController, frc2::PIDController rightController,
+ frc::PIDController leftController, frc::PIDController rightController,
std::function<void(units::volt_t, units::volt_t)> output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_controller(controller),
m_feedforward(feedforward),
- m_kinematics(kinematics),
+ m_kinematics(std::move(kinematics)),
m_speeds(std::move(wheelSpeeds)),
- m_leftController(std::make_unique<frc2::PIDController>(leftController)),
- m_rightController(std::make_unique<frc2::PIDController>(rightController)),
- m_outputVolts(std::move(output)),
- m_usePID(true) {
- AddRequirements(requirements);
-}
-
-RamseteCommand::RamseteCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::RamseteController controller,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::DifferentialDriveKinematics kinematics,
- std::function<frc::DifferentialDriveWheelSpeeds()> wheelSpeeds,
- frc2::PIDController leftController, frc2::PIDController rightController,
- std::function<void(units::volt_t, units::volt_t)> output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_controller(controller),
- m_feedforward(feedforward),
- m_kinematics(kinematics),
- m_speeds(std::move(wheelSpeeds)),
- m_leftController(std::make_unique<frc2::PIDController>(leftController)),
- m_rightController(std::make_unique<frc2::PIDController>(rightController)),
+ m_leftController(std::make_unique<frc::PIDController>(leftController)),
+ m_rightController(std::make_unique<frc::PIDController>(rightController)),
m_outputVolts(std::move(output)),
m_usePID(true) {
AddRequirements(requirements);
@@ -60,27 +38,11 @@
frc::DifferentialDriveKinematics kinematics,
std::function<void(units::meters_per_second_t, units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_controller(controller),
- m_kinematics(kinematics),
- m_outputVel(std::move(output)),
- m_usePID(false) {
- AddRequirements(requirements);
-}
-
-RamseteCommand::RamseteCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::RamseteController controller,
- frc::DifferentialDriveKinematics kinematics,
- std::function<void(units::meters_per_second_t, units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_controller(controller),
- m_kinematics(kinematics),
+ m_kinematics(std::move(kinematics)),
m_outputVel(std::move(output)),
m_usePID(false) {
AddRequirements(requirements);
@@ -92,8 +54,7 @@
m_prevSpeeds = m_kinematics.ToWheelSpeeds(
frc::ChassisSpeeds{initialState.velocity, 0_mps,
initialState.velocity * initialState.curvature});
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
if (m_usePID) {
m_leftController->Reset();
m_rightController->Reset();
@@ -162,7 +123,7 @@
}
void RamseteCommand::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddDoubleProperty(
"leftVelocity", [this] { return m_prevSpeeds.left.value(); }, nullptr);
builder.AddDoubleProperty(
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp
index 319a7af..2e74c8c 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp
@@ -39,7 +39,12 @@
}
void RepeatCommand::End(bool interrupted) {
- m_command->End(interrupted);
+ // Make sure we didn't already call end() (which would happen if the command
+ // finished in the last call to our execute())
+ if (!m_ended) {
+ m_command->End(interrupted);
+ m_ended = true;
+ }
}
bool RepeatCommand::RunsWhenDisabled() const {
@@ -51,7 +56,7 @@
}
void RepeatCommand::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddStringProperty(
"command", [this] { return m_command->GetName(); }, nullptr);
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp
index 342362f..c3378ea 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp
@@ -6,12 +6,6 @@
using namespace frc2;
-RunCommand::RunCommand(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements)
- : CommandHelper([] {}, std::move(toRun), [](bool interrupted) {},
- [] { return false; }, requirements) {}
-
-RunCommand::RunCommand(std::function<void()> toRun,
- std::span<Subsystem* const> requirements)
+RunCommand::RunCommand(std::function<void()> toRun, Requirements requirements)
: CommandHelper([] {}, std::move(toRun), [](bool interrupted) {},
[] { return false; }, requirements) {}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ScheduleCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ScheduleCommand.cpp
index 54c3042..c96f218 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ScheduleCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ScheduleCommand.cpp
@@ -7,11 +7,13 @@
using namespace frc2;
ScheduleCommand::ScheduleCommand(std::span<Command* const> toSchedule) {
- SetInsert(m_toSchedule, toSchedule);
+ for (auto cmd : toSchedule) {
+ m_toSchedule.insert(cmd);
+ }
}
ScheduleCommand::ScheduleCommand(Command* toSchedule) {
- SetInsert(m_toSchedule, {&toSchedule, 1});
+ m_toSchedule.insert(toSchedule);
}
void ScheduleCommand::Initialize() {
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp
index 7888c1d..b9ea3d5 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp
@@ -83,7 +83,7 @@
}
void SequentialCommandGroup::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddIntegerProperty(
"index", [this] { return m_currentCommandIndex; }, nullptr);
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp
index 3d91ac5..2d257a3 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp
@@ -8,15 +8,7 @@
StartEndCommand::StartEndCommand(std::function<void()> onInit,
std::function<void()> onEnd,
- std::initializer_list<Subsystem*> requirements)
- : CommandHelper(
- std::move(onInit), [] {},
- [onEnd = std::move(onEnd)](bool interrupted) { onEnd(); },
- [] { return false; }, requirements) {}
-
-StartEndCommand::StartEndCommand(std::function<void()> onInit,
- std::function<void()> onEnd,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: CommandHelper(
std::move(onInit), [] {},
[onEnd = std::move(onEnd)](bool interrupted) { onEnd(); },
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp
index 3c388bb..4c06f1f 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp
@@ -21,6 +21,10 @@
std::move(defaultCommand));
}
+void Subsystem::RemoveDefaultCommand() {
+ CommandScheduler::GetInstance().RemoveDefaultCommand(this);
+}
+
Command* Subsystem::GetDefaultCommand() const {
return CommandScheduler::GetInstance().GetDefaultCommand(this);
}
@@ -50,3 +54,7 @@
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});
+}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitCommand.cpp
index 94b8b8a..36b15dd 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitCommand.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitCommand.cpp
@@ -5,7 +5,6 @@
#include "frc2/command/WaitCommand.h"
#include <fmt/format.h>
-#include <frc/fmt/Units.h>
#include <wpi/sendable/SendableBuilder.h>
using namespace frc2;
@@ -15,8 +14,7 @@
}
void WaitCommand::Initialize() {
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
}
void WaitCommand::End(bool interrupted) {
@@ -32,7 +30,7 @@
}
void WaitCommand::InitSendable(wpi::SendableBuilder& builder) {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddDoubleProperty(
"duration", [this] { return m_duration.value(); }, nullptr);
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Button.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Button.cpp
deleted file mode 100644
index 787fc09..0000000
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Button.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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/Button.h"
-
-using namespace frc2;
-
-Button::Button(std::function<bool()> isPressed) : Trigger(isPressed) {}
-
-Button Button::WhenPressed(Command* command) {
- WPI_IGNORE_DEPRECATED
- WhenActive(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenPressed(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- WPI_IGNORE_DEPRECATED
- WhenActive(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenPressed(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) {
- WPI_IGNORE_DEPRECATED
- WhenActive(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhileHeld(Command* command) {
- WPI_IGNORE_DEPRECATED
- WhileActiveContinous(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhileHeld(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- WPI_IGNORE_DEPRECATED
- WhileActiveContinous(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhileHeld(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) {
- WPI_IGNORE_DEPRECATED
- WhileActiveContinous(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenHeld(Command* command) {
- WPI_IGNORE_DEPRECATED
- WhileActiveOnce(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenReleased(Command* command) {
- WPI_IGNORE_DEPRECATED
- WhenInactive(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenReleased(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- WPI_IGNORE_DEPRECATED
- WhenInactive(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::WhenReleased(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) {
- WPI_IGNORE_DEPRECATED
- WhenInactive(std::move(toRun), requirements);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::ToggleWhenPressed(Command* command) {
- WPI_IGNORE_DEPRECATED
- ToggleWhenActive(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
-
-Button Button::CancelWhenPressed(Command* command) {
- WPI_IGNORE_DEPRECATED
- CancelWhenActive(command);
- WPI_UNIGNORE_DEPRECATED
- return *this;
-}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/CommandPS5Controller.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/CommandPS5Controller.cpp
new file mode 100644
index 0000000..399a771
--- /dev/null
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/CommandPS5Controller.cpp
@@ -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>();
+}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp
index e26cd14..a0923a3 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp
@@ -4,19 +4,15 @@
#include "frc2/command/button/NetworkButton.h"
-#include <wpi/deprecated.h>
-
using namespace frc2;
-WPI_IGNORE_DEPRECATED
NetworkButton::NetworkButton(nt::BooleanTopic topic)
: NetworkButton(topic.Subscribe(false)) {}
NetworkButton::NetworkButton(nt::BooleanSubscriber sub)
- : Button([sub = std::make_shared<nt::BooleanSubscriber>(std::move(sub))] {
+ : Trigger([sub = std::make_shared<nt::BooleanSubscriber>(std::move(sub))] {
return sub->GetTopic().GetInstance().IsConnected() && sub->Get();
}) {}
-WPI_UNIGNORE_DEPRECATED
NetworkButton::NetworkButton(std::shared_ptr<nt::NetworkTable> table,
std::string_view field)
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
index 3908daf..38ec741 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
@@ -205,124 +205,6 @@
return *this;
}
-WPI_IGNORE_DEPRECATED
-Trigger Trigger::WhenActive(Command* command) {
- return OnTrue(command);
-}
-
-Trigger Trigger::WhenActive(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- return WhenActive(std::move(toRun),
- {requirements.begin(), requirements.end()});
-}
-
-Trigger Trigger::WhenActive(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) {
- return WhenActive(InstantCommand(std::move(toRun), requirements));
-}
-
-Trigger Trigger::WhileActiveContinous(Command* command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::move(command)]() mutable {
- bool current = condition();
-
- if (current) {
- command->Schedule();
- } else if (previous && !current) {
- command->Cancel();
- }
-
- previous = current;
- });
- return *this;
-}
-
-Trigger Trigger::WhileActiveContinous(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- return WhileActiveContinous(std::move(toRun),
- {requirements.begin(), requirements.end()});
-}
-
-Trigger Trigger::WhileActiveContinous(
- std::function<void()> toRun, std::span<Subsystem* const> requirements) {
- return WhileActiveContinous(InstantCommand(std::move(toRun), requirements));
-}
-
-Trigger Trigger::WhileActiveOnce(Command* command) {
- m_loop->Bind(
- [condition = m_condition, previous = m_condition(), command]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- command->Schedule();
- } else if (previous && !current) {
- command->Cancel();
- }
-
- previous = current;
- });
- return *this;
-}
-
-Trigger Trigger::WhenInactive(Command* command) {
- m_loop->Bind(
- [condition = m_condition, previous = m_condition(), command]() mutable {
- bool current = condition();
-
- if (previous && !current) {
- command->Schedule();
- }
-
- previous = current;
- });
- return *this;
-}
-
-Trigger Trigger::WhenInactive(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) {
- return WhenInactive(std::move(toRun),
- {requirements.begin(), requirements.end()});
-}
-
-Trigger Trigger::WhenInactive(std::function<void()> toRun,
- std::span<Subsystem* const> requirements) {
- return WhenInactive(InstantCommand(std::move(toRun), requirements));
-}
-
-Trigger Trigger::ToggleWhenActive(Command* command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = command]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- if (command->IsScheduled()) {
- command->Cancel();
- } else {
- command->Schedule();
- }
- }
-
- previous = current;
- });
- return *this;
-}
-
-Trigger Trigger::CancelWhenActive(Command* command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::move(command)]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- command->Cancel();
- }
-
- previous = current;
- });
- return *this;
-}
-WPI_UNIGNORE_DEPRECATED
-
Trigger Trigger::Debounce(units::second_t debounceTime,
frc::Debouncer::DebounceType type) {
return Trigger(m_loop, [debouncer = frc::Debouncer(debounceTime, type),
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/Command.h b/wpilibNewCommands/src/main/native/include/frc2/command/Command.h
index 189433b..9a48b2e 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/Command.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/Command.h
@@ -5,16 +5,15 @@
#pragma once
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <string>
#include <units/time.h>
#include <wpi/Demangle.h>
#include <wpi/SmallSet.h>
-#include <wpi/deprecated.h>
+#include <wpi/sendable/Sendable.h>
+#include "frc2/command/Requirements.h"
#include "frc2/command/Subsystem.h"
namespace frc2 {
@@ -24,8 +23,6 @@
return wpi::Demangle(typeid(type).name());
}
-class PerpetualCommand;
-
/**
* A state machine representing a complete action to be performed by the robot.
* Commands are run by the CommandScheduler, and can be composed into
@@ -44,10 +41,9 @@
* @see CommandScheduler
* @see CommandHelper
*/
-class Command {
+class Command : public wpi::Sendable, public wpi::SendableHelper<Command> {
public:
- Command() = default;
- virtual ~Command();
+ ~Command() override;
Command(const Command&) = default;
Command& operator=(const Command& rhs);
@@ -95,7 +91,83 @@
* @return the set of subsystems that are required
* @see InterruptionBehavior
*/
- virtual wpi::SmallSet<Subsystem*, 4> GetRequirements() const = 0;
+ virtual wpi::SmallSet<Subsystem*, 4> GetRequirements() const;
+
+ /**
+ * Adds the specified Subsystem requirements to the command.
+ *
+ * The scheduler will prevent two commands that require the same subsystem
+ * from being scheduled simultaneously.
+ *
+ * Note that the scheduler determines the requirements of a command when it
+ * is scheduled, so this method should normally be called from the command's
+ * constructor.
+ *
+ * While this overload can be used with {@code AddRequirements({&subsystem1,
+ * &subsystem2})}, {@code AddRequirements({&subsystem})} selects the {@code
+ * AddRequirements(Subsystem*)} overload, which will function identically but
+ * may cause warnings about redundant braces.
+ *
+ * @param requirements the Subsystem requirements to add, which can be
+ * implicitly constructed from an initializer list or a span
+ */
+ void AddRequirements(Requirements requirements);
+
+ /**
+ * Adds the specified Subsystem requirements to the command.
+ *
+ * The scheduler will prevent two commands that require the same subsystem
+ * from being scheduled simultaneously.
+ *
+ * Note that the scheduler determines the requirements of a command when it
+ * is scheduled, so this method should normally be called from the command's
+ * constructor.
+ *
+ * @param requirements the Subsystem requirements to add
+ */
+ void AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements);
+
+ /**
+ * Adds the specified Subsystem requirement to the command.
+ *
+ * The scheduler will prevent two commands that require the same subsystem
+ * from being scheduled simultaneously.
+ *
+ * Note that the scheduler determines the requirements of a command when it
+ * is scheduled, so this method should normally be called from the command's
+ * constructor.
+ *
+ * @param requirement the Subsystem requirement to add
+ */
+ void AddRequirements(Subsystem* requirement);
+
+ /**
+ * Gets the name of this Command.
+ *
+ * @return Name
+ */
+ std::string GetName() const;
+
+ /**
+ * Sets the name of this Command.
+ *
+ * @param name name
+ */
+ void SetName(std::string_view name);
+
+ /**
+ * Gets the subsystem name of this Command.
+ *
+ * @return Subsystem name
+ */
+ std::string GetSubsystem() const;
+
+ /**
+ * Sets the subsystem name of this Command.
+ *
+ * @param subsystem subsystem name
+ */
+ void SetSubsystem(std::string_view subsystem);
/**
* An enum describing the command's behavior when another command with a
@@ -116,39 +188,37 @@
friend class CommandPtr;
/**
- * Decorates this command with a timeout. If the specified timeout is
+ * Decorates this command with a timeout. If the specified timeout is
* exceeded before the command finishes normally, the command will be
- * interrupted and un-scheduled. Note that the timeout only applies to the
- * command returned by this method; the calling command is not itself changed.
+ * interrupted and un-scheduled.
*
* @param duration the timeout duration
* @return the command with the timeout added
*/
- [[nodiscard]] CommandPtr WithTimeout(units::second_t duration) &&;
+ [[nodiscard]]
+ CommandPtr WithTimeout(units::second_t duration) &&;
/**
- * Decorates this command with an interrupt condition. If the specified
+ * Decorates this command with an interrupt condition. If the specified
* condition becomes true before the command finishes normally, the command
- * will be interrupted and un-scheduled. Note that this only applies to the
- * command returned by this method; the calling command is not itself changed.
+ * will be interrupted and un-scheduled.
*
* @param condition the interrupt condition
* @return the command with the interrupt condition added
*/
- [[nodiscard]] CommandPtr Until(std::function<bool()> condition) &&;
+ [[nodiscard]]
+ CommandPtr Until(std::function<bool()> condition) &&;
/**
- * Decorates this command with an interrupt condition. If the specified
- * condition becomes true before the command finishes normally, the command
- * will be interrupted and un-scheduled. Note that this only applies to the
- * command returned by this method; the calling command is not itself changed.
+ * Decorates this command with a run condition. If the specified condition
+ * becomes false before the command finishes normally, the command will be
+ * interrupted and un-scheduled.
*
- * @param condition the interrupt condition
- * @return the command with the interrupt condition added
- * @deprecated Replace with Until()
+ * @param condition the run condition
+ * @return the command with the run condition added
*/
- WPI_DEPRECATED("Replace with Until()")
- [[nodiscard]] CommandPtr WithInterrupt(std::function<bool()> condition) &&;
+ [[nodiscard]]
+ CommandPtr OnlyWhile(std::function<bool()> condition) &&;
/**
* Decorates this command with a runnable to run before this command starts.
@@ -157,20 +227,9 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- [[nodiscard]] CommandPtr BeforeStarting(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) &&;
-
- /**
- * Decorates this command with a runnable to run before this command starts.
- *
- * @param toRun the Runnable to run
- * @param requirements the required subsystems
- * @return the decorated command
- */
- [[nodiscard]] CommandPtr BeforeStarting(
- std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {}) &&;
+ [[nodiscard]]
+ CommandPtr BeforeStarting(std::function<void()> toRun,
+ Requirements requirements = {}) &&;
/**
* Decorates this command with a runnable to run after the command finishes.
@@ -179,40 +238,9 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AndThen(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) &&;
-
- /**
- * Decorates this command with a runnable to run after the command finishes.
- *
- * @param toRun the Runnable to run
- * @param requirements the required subsystems
- * @return the decorated command
- */
- [[nodiscard]] CommandPtr AndThen(
- std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {}) &&;
-
- /**
- * Decorates this command to run perpetually, ignoring its ordinary end
- * conditions. The decorated command can still be interrupted or canceled.
- *
- * @return the decorated command
- * @deprecated PerpetualCommand violates the assumption that execute() doesn't
-get called after isFinished() returns true -- an assumption that should be
-valid. This was unsafe/undefined behavior from the start, and RepeatCommand
-provides an easy way to achieve similar end results with slightly different (and
-safe) semantics.
- */
- WPI_DEPRECATED(
- "PerpetualCommand violates the assumption that execute() doesn't get "
- "called after isFinished() returns true -- an assumption that should be "
- "valid."
- "This was unsafe/undefined behavior from the start, and RepeatCommand "
- "provides an easy way to achieve similar end results with slightly "
- "different (and safe) semantics.")
- PerpetualCommand Perpetually() &&;
+ [[nodiscard]]
+ CommandPtr AndThen(std::function<void()> toRun,
+ Requirements requirements = {}) &&;
/**
* Decorates this command to run repeatedly, restarting it when it ends, until
@@ -220,7 +248,8 @@
*
* @return the decorated command
*/
- [[nodiscard]] CommandPtr Repeatedly() &&;
+ [[nodiscard]]
+ CommandPtr Repeatedly() &&;
/**
* Decorates this command to run "by proxy" by wrapping it in a
@@ -232,7 +261,8 @@
*
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AsProxy() &&;
+ [[nodiscard]]
+ CommandPtr AsProxy() &&;
/**
* Decorates this command to only run if this condition is not met. If the
@@ -243,7 +273,20 @@
* @param condition the condition that will prevent the command from running
* @return the decorated command
*/
- [[nodiscard]] CommandPtr Unless(std::function<bool()> condition) &&;
+ [[nodiscard]]
+ CommandPtr Unless(std::function<bool()> condition) &&;
+
+ /**
+ * Decorates this command to only run if this condition is met. If the command
+ * is already running and the condition changes to false, the command will not
+ * stop running. The requirements of this command will be kept for the new
+ * conditional command.
+ *
+ * @param condition the condition that will allow the command to run
+ * @return the decorated command
+ */
+ [[nodiscard]]
+ CommandPtr OnlyIf(std::function<bool()> condition) &&;
/**
* Decorates this command to run or stop when disabled.
@@ -251,15 +294,17 @@
* @param doesRunWhenDisabled true to run when disabled.
* @return the decorated command
*/
- [[nodiscard]] CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
+ [[nodiscard]]
+ CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
/**
- * Decorates this command to run or stop when disabled.
+ * Decorates this command to have a different interrupt behavior.
*
- * @param interruptBehavior true to run when disabled.
+ * @param interruptBehavior the desired interrupt behavior
* @return the decorated command
*/
- [[nodiscard]] CommandPtr WithInterruptBehavior(
+ [[nodiscard]]
+ CommandPtr WithInterruptBehavior(
Command::InterruptionBehavior interruptBehavior) &&;
/**
@@ -270,7 +315,20 @@
* command was interrupted.
* @return the decorated command
*/
- [[nodiscard]] CommandPtr FinallyDo(std::function<void(bool)> end) &&;
+ [[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
@@ -279,7 +337,8 @@
* @param handler a lambda to run when the command is interrupted
* @return the decorated command
*/
- [[nodiscard]] CommandPtr HandleInterrupt(std::function<void()> handler) &&;
+ [[nodiscard]]
+ CommandPtr HandleInterrupt(std::function<void()> handler) &&;
/**
* Decorates this Command with a name.
@@ -287,7 +346,8 @@
* @param name name
* @return the decorated Command
*/
- [[nodiscard]] CommandPtr WithName(std::string_view name) &&;
+ [[nodiscard]]
+ CommandPtr WithName(std::string_view name) &&;
/**
* Schedules this command.
@@ -333,25 +393,6 @@
void SetComposed(bool isComposed);
/**
- * Whether the command is currently grouped in a command group. Used as extra
- * insurance to prevent accidental independent use of grouped commands.
- *
- * @deprecated Moved to IsComposed()
- */
- WPI_DEPRECATED("Moved to IsComposed()")
- bool IsGrouped() const;
-
- /**
- * Sets whether the command is currently grouped in a command group. Can be
- * used to "reclaim" a command if a group is no longer going to use it. NOT
- * ADVISED!
- *
- * @deprecated Moved to SetComposed()
- */
- WPI_DEPRECATED("Moved to SetComposed()")
- void SetGrouped(bool grouped);
-
- /**
* Whether the given command should run when the robot is disabled. Override
* to return true if the command should run when disabled.
*
@@ -370,27 +411,18 @@
}
/**
- * Gets the name of this Command. Defaults to the simple class name if not
- * overridden.
- *
- * @return The display name of the Command
- */
- virtual std::string GetName() const;
-
- /**
- * Sets the name of this Command. Nullop if not overridden.
- *
- * @param name The display name of the Command.
- */
- virtual void SetName(std::string_view name);
-
- /**
* Transfers ownership of this command to a unique pointer. Used for
* decorator methods.
*/
virtual CommandPtr ToPtr() && = 0;
+ void InitSendable(wpi::SendableBuilder& builder) override;
+
protected:
+ Command();
+
+ wpi::SmallSet<Subsystem*, 4> m_requirements;
+
/**
* Transfers ownership of this command to a unique pointer. Used for
* decorator methods.
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/CommandBase.h b/wpilibNewCommands/src/main/native/include/frc2/command/CommandBase.h
index 64bd88b..ea24e42 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/CommandBase.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/CommandBase.h
@@ -4,14 +4,7 @@
#pragma once
-#include <initializer_list>
-#include <span>
-#include <string>
-#include <string_view>
-
-#include <wpi/SmallSet.h>
-#include <wpi/sendable/Sendable.h>
-#include <wpi/sendable/SendableHelper.h>
+#include <wpi/deprecated.h>
#include "frc2/command/Command.h"
@@ -20,78 +13,13 @@
* A Sendable base class for Commands.
*
* This class is provided by the NewCommands VendorDep
+ *
+ * @deprecated All functionality provided by CommandBase has been merged into
+ * Command. Use Command instead.
*/
-class CommandBase : public Command,
- public wpi::Sendable,
- public wpi::SendableHelper<CommandBase> {
- public:
- /**
- * Adds the specified Subsystem requirements to the command.
- *
- * @param requirements the Subsystem requirements to add
- */
- void AddRequirements(std::initializer_list<Subsystem*> requirements);
-
- /**
- * Adds the specified Subsystem requirements to the command.
- *
- * @param requirements the Subsystem requirements to add
- */
- void AddRequirements(std::span<Subsystem* const> requirements);
-
- /**
- * Adds the specified Subsystem requirements to the command.
- *
- * @param requirements the Subsystem requirements to add
- */
- void AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements);
-
- /**
- * Adds the specified Subsystem requirement to the command.
- *
- * @param requirement the Subsystem requirement to add
- */
- void AddRequirements(Subsystem* requirement);
-
- /**
- * Gets the Subsystem requirements of the command.
- *
- * @return the Command's Subsystem requirements
- */
- wpi::SmallSet<Subsystem*, 4> GetRequirements() const override;
-
- /**
- * Sets the name of this Command.
- *
- * @param name name
- */
- void SetName(std::string_view name) override;
-
- /**
- * Gets the name of this Command.
- *
- * @return Name
- */
- std::string GetName() const override;
-
- /**
- * Gets the subsystem name of this Command.
- *
- * @return Subsystem name
- */
- std::string GetSubsystem() const;
-
- /**
- * Sets the subsystem name of this Command.
- *
- * @param subsystem subsystem name
- */
- void SetSubsystem(std::string_view subsystem);
-
- void InitSendable(wpi::SendableBuilder& builder) override;
-
+class [[deprecated("Use Command instead")]] CommandBase : public Command {
protected:
+ WPI_DEPRECATED("Use Command instead")
CommandBase();
- wpi::SmallSet<Subsystem*, 4> m_requirements;
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/CommandGroupBase.h b/wpilibNewCommands/src/main/native/include/frc2/command/CommandGroupBase.h
deleted file mode 100644
index 9fe65fa..0000000
--- a/wpilibNewCommands/src/main/native/include/frc2/command/CommandGroupBase.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 <vector>
-
-#include <wpi/deprecated.h>
-
-#include "frc2/command/CommandBase.h"
-
-namespace frc2 {
-
-/**
- * A base for CommandGroups.
- *
- * This class is provided by the NewCommands VendorDep
- * @deprecated This class is an empty abstraction. Inherit directly from
- * CommandBase.
- */
-class CommandGroupBase : public CommandBase {
- public:
- /**
- * Adds the given commands to the command group.
- *
- * @param commands The commands to add.
- */
- virtual void AddCommands(
- std::vector<std::unique_ptr<Command>>&& commands) = 0;
-};
-} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/CommandHelper.h b/wpilibNewCommands/src/main/native/include/frc2/command/CommandHelper.h
index 76ee6cd..ed93b65 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/CommandHelper.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/CommandHelper.h
@@ -4,8 +4,8 @@
#pragma once
+#include <concepts>
#include <memory>
-#include <type_traits>
#include <utility>
#include "frc2/command/Command.h"
@@ -21,8 +21,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-template <typename Base, typename CRTP,
- typename = std::enable_if_t<std::is_base_of_v<Command, Base>>>
+template <std::derived_from<Command> Base, typename CRTP>
class CommandHelper : public Base {
using Base::Base;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/CommandPtr.h b/wpilibNewCommands/src/main/native/include/frc2/command/CommandPtr.h
index 0ab1e97..ae8c118 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/CommandPtr.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/CommandPtr.h
@@ -4,15 +4,15 @@
#pragma once
+#include <concepts>
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <string>
#include <utility>
#include <vector>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -27,14 +27,14 @@
*/
class CommandPtr final {
public:
- explicit CommandPtr(std::unique_ptr<CommandBase>&& command)
+ explicit CommandPtr(std::unique_ptr<Command>&& command)
: m_ptr(std::move(command)) {}
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
+ template <std::derived_from<Command> T>
+ // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit CommandPtr(T&& command)
- : CommandPtr(std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))) {}
+ : CommandPtr(
+ std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
CommandPtr(CommandPtr&&) = default;
CommandPtr& operator=(CommandPtr&&) = default;
@@ -45,7 +45,8 @@
*
* @return the decorated command
*/
- [[nodiscard]] CommandPtr Repeatedly() &&;
+ [[nodiscard]]
+ CommandPtr Repeatedly() &&;
/**
* Decorates this command to run "by proxy" by wrapping it in a
@@ -55,23 +56,26 @@
*
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AsProxy() &&;
+ [[nodiscard]]
+ CommandPtr AsProxy() &&;
/**
* Decorates this command to run or stop when disabled.
*
- * @param doesRunWhenDisabled true to run when disabled.
+ * @param doesRunWhenDisabled true to run when disabled
* @return the decorated command
*/
- [[nodiscard]] CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
+ [[nodiscard]]
+ CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
/**
- * Decorates this command to run or stop when disabled.
+ * Decorates this command to have a different interrupt behavior.
*
- * @param interruptBehavior true to run when disabled.
+ * @param interruptBehavior the desired interrupt behavior
* @return the decorated command
*/
- [[nodiscard]] CommandPtr WithInterruptBehavior(
+ [[nodiscard]]
+ CommandPtr WithInterruptBehavior(
Command::InterruptionBehavior interruptBehavior) &&;
/**
@@ -81,20 +85,9 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AndThen(
- std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {}) &&;
-
- /**
- * Decorates this command with a runnable to run after the command finishes.
- *
- * @param toRun the Runnable to run
- * @param requirements the required subsystems
- * @return the decorated command
- */
- [[nodiscard]] CommandPtr AndThen(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) &&;
+ [[nodiscard]]
+ CommandPtr AndThen(std::function<void()> toRun,
+ Requirements requirements = {}) &&;
/**
* Decorates this command with a set of commands to run after it in sequence.
@@ -104,7 +97,8 @@
* @param next the commands to run next
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AndThen(CommandPtr&& next) &&;
+ [[nodiscard]]
+ CommandPtr AndThen(CommandPtr&& next) &&;
/**
* Decorates this command with a runnable to run before this command starts.
@@ -113,20 +107,9 @@
* @param requirements the required subsystems
* @return the decorated command
*/
- [[nodiscard]] CommandPtr BeforeStarting(
- std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements) &&;
-
- /**
- * Decorates this command with a runnable to run before this command starts.
- *
- * @param toRun the Runnable to run
- * @param requirements the required subsystems
- * @return the decorated command
- */
- [[nodiscard]] CommandPtr BeforeStarting(
- std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {}) &&;
+ [[nodiscard]]
+ CommandPtr BeforeStarting(std::function<void()> toRun,
+ Requirements requirements = {}) &&;
/**
* Decorates this command with another command to run before this command
@@ -135,29 +118,41 @@
* @param before the command to run before this one
* @return the decorated command
*/
- [[nodiscard]] CommandPtr BeforeStarting(CommandPtr&& before) &&;
+ [[nodiscard]]
+ CommandPtr BeforeStarting(CommandPtr&& before) &&;
/**
- * Decorates this command with a timeout. If the specified timeout is
+ * Decorates this command with a timeout. If the specified timeout is
* exceeded before the command finishes normally, the command will be
- * interrupted and un-scheduled. Note that the timeout only applies to the
- * command returned by this method; the calling command is not itself changed.
+ * interrupted and un-scheduled.
*
* @param duration the timeout duration
* @return the command with the timeout added
*/
- [[nodiscard]] CommandPtr WithTimeout(units::second_t duration) &&;
+ [[nodiscard]]
+ CommandPtr WithTimeout(units::second_t duration) &&;
/**
- * Decorates this command with an interrupt condition. If the specified
+ * Decorates this command with an interrupt condition. If the specified
* condition becomes true before the command finishes normally, the command
- * will be interrupted and un-scheduled. Note that this only applies to the
- * command returned by this method; the calling command is not itself changed.
+ * will be interrupted and un-scheduled.
*
* @param condition the interrupt condition
* @return the command with the interrupt condition added
*/
- [[nodiscard]] CommandPtr Until(std::function<bool()> condition) &&;
+ [[nodiscard]]
+ CommandPtr Until(std::function<bool()> condition) &&;
+
+ /**
+ * Decorates this command with a run condition. If the specified condition
+ * becomes false before the command finishes normally, the command will be
+ * interrupted and un-scheduled.
+ *
+ * @param condition the run condition
+ * @return the command with the run condition added
+ */
+ [[nodiscard]]
+ CommandPtr OnlyWhile(std::function<bool()> condition) &&;
/**
* Decorates this command to only run if this condition is not met. If the
@@ -168,7 +163,20 @@
* @param condition the condition that will prevent the command from running
* @return the decorated command
*/
- [[nodiscard]] CommandPtr Unless(std::function<bool()> condition) &&;
+ [[nodiscard]]
+ CommandPtr Unless(std::function<bool()> condition) &&;
+
+ /**
+ * Decorates this command to only run if this condition is met. If the command
+ * is already running and the condition changes to false, the command will not
+ * stop running. The requirements of this command will be kept for the new
+ * conditional command.
+ *
+ * @param condition the condition that will allow the command to run
+ * @return the decorated command
+ */
+ [[nodiscard]]
+ CommandPtr OnlyIf(std::function<bool()> condition) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
@@ -179,7 +187,8 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- [[nodiscard]] CommandPtr DeadlineWith(CommandPtr&& parallel) &&;
+ [[nodiscard]]
+ CommandPtr DeadlineWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
@@ -189,7 +198,8 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- [[nodiscard]] CommandPtr AlongWith(CommandPtr&& parallel) &&;
+ [[nodiscard]]
+ CommandPtr AlongWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
@@ -199,17 +209,31 @@
* @param parallel the commands to run in parallel
* @return the decorated command
*/
- [[nodiscard]] CommandPtr RaceWith(CommandPtr&& parallel) &&;
+ [[nodiscard]]
+ CommandPtr RaceWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a lambda to call on interrupt or end, following
* the command's inherent Command::End(bool) method.
*
* @param end a lambda accepting a boolean parameter specifying whether the
- * command was interrupted.
+ * command was interrupted
* @return the decorated command
*/
- [[nodiscard]] CommandPtr FinallyDo(std::function<void(bool)> end) &&;
+ [[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
@@ -218,7 +242,8 @@
* @param handler a lambda to run when the command is interrupted
* @return the decorated command
*/
- [[nodiscard]] CommandPtr HandleInterrupt(std::function<void()> handler) &&;
+ [[nodiscard]]
+ CommandPtr HandleInterrupt(std::function<void()> handler) &&;
/**
* Decorates this Command with a name. Is an inline function for
@@ -227,28 +252,38 @@
* @param name name
* @return the decorated Command
*/
- [[nodiscard]] CommandPtr WithName(std::string_view name) &&;
+ [[nodiscard]]
+ CommandPtr WithName(std::string_view name) &&;
/**
* Get a raw pointer to the held command.
*/
- CommandBase* get() const;
+ Command* get() const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ Command* get() && = delete;
/**
* Convert to the underlying unique_ptr.
*/
- std::unique_ptr<CommandBase> Unwrap() &&;
+ std::unique_ptr<Command> Unwrap() &&;
/**
* Schedules this command.
*/
- void Schedule() const;
+ void Schedule() const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ void Schedule() && = delete;
/**
* Cancels this command. Will call End(true). Commands will be canceled
* regardless of interruption behavior.
*/
- void Cancel() const;
+ void Cancel() const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ void Cancel() && = delete;
/**
* Whether or not the command is currently scheduled. Note that this does not
@@ -257,7 +292,10 @@
*
* @return Whether the command is scheduled.
*/
- bool IsScheduled() const;
+ bool IsScheduled() const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ void IsScheduled() && = delete;
/**
* Whether the command requires a given subsystem. Named "HasRequirement"
@@ -267,12 +305,18 @@
* @param requirement the subsystem to inquire about
* @return whether the subsystem is required
*/
- bool HasRequirement(Subsystem* requirement) const;
+ bool HasRequirement(Subsystem* requirement) const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ void HasRequirement(Subsystem* requirement) && = delete;
/**
* Check if this CommandPtr object is valid and wasn't moved-from.
*/
- explicit operator bool() const;
+ explicit operator bool() const&;
+
+ // Prevent calls on a temporary, as the returned pointer would be invalid
+ explicit operator bool() && = delete;
/**
* Convert a vector of CommandPtr objects to their underlying unique_ptrs.
@@ -281,7 +325,7 @@
std::vector<CommandPtr>&& vec);
private:
- std::unique_ptr<CommandBase> m_ptr;
+ std::unique_ptr<Command> m_ptr;
void AssertValid() const;
};
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/CommandScheduler.h b/wpilibNewCommands/src/main/native/include/frc2/command/CommandScheduler.h
index c0c09c1..ce4dc91 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/CommandScheduler.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/CommandScheduler.h
@@ -4,18 +4,20 @@
#pragma once
+#include <concepts>
+#include <functional>
#include <initializer_list>
#include <memory>
+#include <optional>
#include <span>
#include <utility>
#include <frc/Errors.h>
#include <frc/Watchdog.h>
#include <frc/event/EventLoop.h>
-#include <networktables/NTSendable.h>
#include <units/time.h>
#include <wpi/FunctionExtras.h>
-#include <wpi/deprecated.h>
+#include <wpi/sendable/Sendable.h>
#include <wpi/sendable/SendableHelper.h>
namespace frc2 {
@@ -32,7 +34,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class CommandScheduler final : public nt::NTSendable,
+class CommandScheduler final : public wpi::Sendable,
public wpi::SendableHelper<CommandScheduler> {
public:
/**
@@ -47,6 +49,8 @@
CommandScheduler& operator=(const CommandScheduler&) = delete;
using Action = std::function<void(const Command&)>;
+ using InterruptAction =
+ std::function<void(const Command&, const std::optional<Command*>&)>;
/**
* Changes the period of the loop overrun watchdog. This should be kept in
@@ -78,12 +82,6 @@
frc::EventLoop* GetDefaultButtonLoop() const;
/**
- * Removes all button bindings from the scheduler.
- */
- WPI_DEPRECATED("Call Clear on the EventLoop instance directly!")
- void ClearButtons();
-
- /**
* Schedules a command for execution. Does nothing if the command is already
* scheduled. If a command's requirements are not available, it will only be
* started if all the commands currently using those requirements are
@@ -165,6 +163,13 @@
void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
/**
+ * Un-registers all registered Subsystems with the scheduler. All currently
+ * registered subsystems will no longer have their periodic block called, and
+ * will not have their default command scheduled.
+ */
+ void UnregisterAllSubsystems();
+
+ /**
* Sets the default command for a subsystem. Registers that subsystem if it
* is not already registered. Default commands will run whenever there is no
* other command currently scheduled that requires the subsystem. Default
@@ -175,16 +180,14 @@
* @param subsystem the subsystem whose default command will be set
* @param defaultCommand the default command to associate with the subsystem
*/
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
+ template <std::derived_from<Command> T>
void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
if (!defaultCommand.HasRequirement(subsystem)) {
throw FRC_MakeError(frc::err::CommandIllegalUse,
"Default commands must require their subsystem!");
}
- SetDefaultCommandImpl(subsystem,
- std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(defaultCommand)));
+ SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
+ std::forward<T>(defaultCommand)));
}
/**
@@ -354,6 +357,16 @@
void OnCommandInterrupt(Action action);
/**
+ * Adds an action to perform on the interruption of any command by the
+ * scheduler. The action receives the interrupted command and an optional
+ * containing the interrupting command, or nullopt if it was not canceled by a
+ * command (e.g., by Cancel()).
+ *
+ * @param action the action to perform
+ */
+ void OnCommandInterrupt(InterruptAction action);
+
+ /**
* Adds an action to perform on the finishing of any command by the scheduler.
*
* @param action the action to perform
@@ -388,7 +401,7 @@
*/
void RequireUngrouped(std::initializer_list<const Command*> commands);
- void InitSendable(nt::NTSendableBuilder& builder) override;
+ void InitSendable(wpi::SendableBuilder& builder) override;
private:
// Constructor; private as this is a singleton
@@ -397,6 +410,8 @@
void SetDefaultCommandImpl(Subsystem* subsystem,
std::unique_ptr<Command> command);
+ void Cancel(Command* command, std::optional<Command*> interruptor);
+
class Impl;
std::unique_ptr<Impl> m_impl;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/Commands.h b/wpilibNewCommands/src/main/native/include/frc2/command/Commands.h
index 8b38275..5c1d49a 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/Commands.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/Commands.h
@@ -4,14 +4,16 @@
#pragma once
+#include <concepts>
#include <functional>
-#include <initializer_list>
-#include <span>
+#include <memory>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
#include "frc2/command/CommandPtr.h"
+#include "frc2/command/Requirements.h"
#include "frc2/command/SelectCommand.h"
namespace frc2 {
@@ -25,7 +27,17 @@
/**
* Constructs a command that does nothing, finishing immediately.
*/
-[[nodiscard]] CommandPtr None();
+[[nodiscard]]
+CommandPtr None();
+
+/**
+ * Constructs a command that does nothing until interrupted.
+ *
+ * @param requirements Subsystems to require
+ * @return the command
+ */
+[[nodiscard]]
+CommandPtr Idle(Requirements requirements = {});
// Action Commands
@@ -35,18 +47,9 @@
* @param action the action to run
* @param requirements subsystems the action requires
*/
-[[nodiscard]] CommandPtr RunOnce(
- std::function<void()> action,
- std::initializer_list<Subsystem*> requirements);
-
-/**
- * Constructs a command that runs an action once and finishes.
- *
- * @param action the action to run
- * @param requirements subsystems the action requires
- */
-[[nodiscard]] CommandPtr RunOnce(std::function<void()> action,
- std::span<Subsystem* const> requirements = {});
+[[nodiscard]]
+CommandPtr RunOnce(std::function<void()> action,
+ Requirements requirements = {});
/**
* Constructs a command that runs an action every iteration until interrupted.
@@ -54,17 +57,8 @@
* @param action the action to run
* @param requirements subsystems the action requires
*/
-[[nodiscard]] CommandPtr Run(std::function<void()> action,
- std::initializer_list<Subsystem*> requirements);
-
-/**
- * Constructs a command that runs an action every iteration until interrupted.
- *
- * @param action the action to run
- * @param requirements subsystems the action requires
- */
-[[nodiscard]] CommandPtr Run(std::function<void()> action,
- std::span<Subsystem* const> requirements = {});
+[[nodiscard]]
+CommandPtr Run(std::function<void()> action, Requirements requirements = {});
/**
* Constructs a command that runs an action once and another action when the
@@ -74,21 +68,9 @@
* @param end the action to run on interrupt
* @param requirements subsystems the action requires
*/
-[[nodiscard]] CommandPtr StartEnd(
- std::function<void()> start, std::function<void()> end,
- std::initializer_list<Subsystem*> requirements);
-
-/**
- * Constructs a command that runs an action once and another action when the
- * command is interrupted.
- *
- * @param start the action to run on start
- * @param end the action to run on interrupt
- * @param requirements subsystems the action requires
- */
-[[nodiscard]] CommandPtr StartEnd(
- std::function<void()> start, std::function<void()> end,
- std::span<Subsystem* const> requirements = {});
+[[nodiscard]]
+CommandPtr StartEnd(std::function<void()> start, std::function<void()> end,
+ Requirements requirements = {});
/**
* Constructs a command that runs an action every iteration until interrupted,
@@ -98,28 +80,17 @@
* @param end the action to run on interrupt
* @param requirements subsystems the action requires
*/
-[[nodiscard]] CommandPtr RunEnd(std::function<void()> run,
- std::function<void()> end,
- std::initializer_list<Subsystem*> requirements);
-
-/**
- * Constructs a command that runs an action every iteration until interrupted,
- * and then runs a second action.
- *
- * @param run the action to run every iteration
- * @param end the action to run on interrupt
- * @param requirements subsystems the action requires
- */
-[[nodiscard]] CommandPtr RunEnd(std::function<void()> run,
- std::function<void()> end,
- std::span<Subsystem* const> requirements = {});
+[[nodiscard]]
+CommandPtr RunEnd(std::function<void()> run, std::function<void()> end,
+ Requirements requirements = {});
/**
* Constructs a command that prints a message and finishes.
*
* @param msg the message to print
*/
-[[nodiscard]] CommandPtr Print(std::string_view msg);
+[[nodiscard]]
+CommandPtr Print(std::string_view msg);
// Idling Commands
@@ -128,7 +99,8 @@
*
* @param duration after how long the command finishes
*/
-[[nodiscard]] CommandPtr Wait(units::second_t duration);
+[[nodiscard]]
+CommandPtr Wait(units::second_t duration);
/**
* Constructs a command that does nothing, finishing once a condition becomes
@@ -136,7 +108,8 @@
*
* @param condition the condition
*/
-[[nodiscard]] CommandPtr WaitUntil(std::function<bool()> condition);
+[[nodiscard]]
+CommandPtr WaitUntil(std::function<bool()> condition);
// Selector Commands
@@ -147,8 +120,9 @@
* @param onFalse the command to run if the selector function returns false
* @param selector the selector function
*/
-[[nodiscard]] CommandPtr Either(CommandPtr&& onTrue, CommandPtr&& onFalse,
- std::function<bool()> selector);
+[[nodiscard]]
+CommandPtr Either(CommandPtr&& onTrue, CommandPtr&& onFalse,
+ std::function<bool()> selector);
/**
* Runs one of several commands, based on the selector function.
@@ -156,15 +130,48 @@
* @param selector the selector function
* @param commands map of commands to select from
*/
-template <typename Key>
-[[nodiscard]] CommandPtr Select(
- std::function<Key()> selector,
- std::vector<std::pair<Key, CommandPtr>> commands) {
- return SelectCommand(std::move(selector),
- CommandPtr::UnwrapVector(std::move(commands)))
- .ToPtr();
+template <typename Key, std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr Select(std::function<Key()> selector,
+ std::pair<Key, CommandPtrs>&&... commands) {
+ std::vector<std::pair<Key, std::unique_ptr<Command>>> vec;
+
+ ((void)vec.emplace_back(commands.first, std::move(commands.second).Unwrap()),
+ ...);
+
+ 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
+ * called when the command is initialized.
+ *
+ * @param supplier the command supplier
+ */
+[[nodiscard]]
+CommandPtr DeferredProxy(wpi::unique_function<Command*()> supplier);
+
+/**
+ * Constructs a command that schedules the command returned from the supplier
+ * when initialized, and ends when it is no longer scheduled. The supplier is
+ * called when the command is initialized.
+ *
+ * @param supplier the command supplier
+ */
+[[nodiscard]]
+CommandPtr DeferredProxy(wpi::unique_function<CommandPtr()> supplier);
+
// Command Groups
namespace impl {
@@ -172,7 +179,7 @@
/**
* Create a vector of commands.
*/
-template <typename... Args>
+template <std::convertible_to<CommandPtr>... Args>
std::vector<CommandPtr> MakeVector(Args&&... args) {
std::vector<CommandPtr> data;
data.reserve(sizeof...(Args));
@@ -185,76 +192,86 @@
/**
* Runs a group of commands in series, one after the other.
*/
-[[nodiscard]] CommandPtr Sequence(std::vector<CommandPtr>&& commands);
+[[nodiscard]]
+CommandPtr Sequence(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands in series, one after the other.
*/
-template <typename... Args>
-[[nodiscard]] CommandPtr Sequence(Args&&... commands) {
- return Sequence(impl::MakeVector(std::forward<Args>(commands)...));
+template <std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr Sequence(CommandPtrs&&... commands) {
+ return Sequence(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands in series, one after the other. Once the last
* command ends, the group is restarted.
*/
-[[nodiscard]] CommandPtr RepeatingSequence(std::vector<CommandPtr>&& commands);
+[[nodiscard]]
+CommandPtr RepeatingSequence(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands in series, one after the other. Once the last
* command ends, the group is restarted.
*/
-template <typename... Args>
-[[nodiscard]] CommandPtr RepeatingSequence(Args&&... commands) {
- return RepeatingSequence(impl::MakeVector(std::forward<Args>(commands)...));
+template <std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr RepeatingSequence(CommandPtrs&&... commands) {
+ return RepeatingSequence(
+ impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once all commands in the
* group finish.
*/
-[[nodiscard]] CommandPtr Parallel(std::vector<CommandPtr>&& commands);
+[[nodiscard]]
+CommandPtr Parallel(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands at the same time. Ends once all commands in the
* group finish.
*/
-template <typename... Args>
-[[nodiscard]] CommandPtr Parallel(Args&&... commands) {
- return Parallel(impl::MakeVector(std::forward<Args>(commands)...));
+template <std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr Parallel(CommandPtrs&&... commands) {
+ return Parallel(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once any command in the group
* finishes, and cancels the others.
*/
-[[nodiscard]] CommandPtr Race(std::vector<CommandPtr>&& commands);
+[[nodiscard]]
+CommandPtr Race(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands at the same time. Ends once any command in the group
* finishes, and cancels the others.
*/
-template <typename... Args>
-[[nodiscard]] CommandPtr Race(Args&&... commands) {
- return Race(impl::MakeVector(std::forward<Args>(commands)...));
+template <std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr Race(CommandPtrs&&... commands) {
+ return Race(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once a specific command
* finishes, and cancels the others.
*/
-[[nodiscard]] CommandPtr Deadline(CommandPtr&& deadline,
- std::vector<CommandPtr>&& others);
+[[nodiscard]]
+CommandPtr Deadline(CommandPtr&& deadline, std::vector<CommandPtr>&& others);
/**
* Runs a group of commands at the same time. Ends once a specific command
* finishes, and cancels the others.
*/
-template <typename... Args>
-[[nodiscard]] CommandPtr Deadline(CommandPtr&& deadline, Args&&... commands) {
+template <std::convertible_to<CommandPtr>... CommandPtrs>
+[[nodiscard]]
+CommandPtr Deadline(CommandPtr&& deadline, CommandPtrs&&... commands) {
return Deadline(std::move(deadline),
- impl::MakeVector(std::forward<Args>(commands)...));
+ impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
} // namespace cmd
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ConditionalCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ConditionalCommand.h
index 5957950..676ee0c 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ConditionalCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ConditionalCommand.h
@@ -4,11 +4,12 @@
#pragma once
+#include <concepts>
#include <functional>
#include <memory>
#include <utility>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -25,8 +26,7 @@
*
* @see ScheduleCommand
*/
-class ConditionalCommand
- : public CommandHelper<CommandBase, ConditionalCommand> {
+class ConditionalCommand : public CommandHelper<Command, ConditionalCommand> {
public:
/**
* Creates a new ConditionalCommand.
@@ -35,16 +35,14 @@
* @param onFalse the command to run if the condition is false
* @param condition the condition to determine which command to run
*/
- template <class T1, class T2,
- typename = std::enable_if_t<
- std::is_base_of_v<Command, std::remove_reference_t<T1>>>,
- typename = std::enable_if_t<
- std::is_base_of_v<Command, std::remove_reference_t<T2>>>>
- ConditionalCommand(T1&& onTrue, T2&& onFalse, std::function<bool()> condition)
- : ConditionalCommand(std::make_unique<std::remove_reference_t<T1>>(
- std::forward<T1>(onTrue)),
- std::make_unique<std::remove_reference_t<T2>>(
- std::forward<T2>(onFalse)),
+ template <std::derived_from<Command> Command1,
+ std::derived_from<Command> Command2>
+ ConditionalCommand(Command1&& onTrue, Command2&& onFalse,
+ std::function<bool()> condition)
+ : ConditionalCommand(std::make_unique<std::decay_t<Command1>>(
+ std::forward<Command1>(onTrue)),
+ std::make_unique<std::decay_t<Command2>>(
+ std::forward<Command2>(onFalse)),
condition) {}
/**
@@ -73,6 +71,8 @@
bool RunsWhenDisabled() const override;
+ InterruptionBehavior GetInterruptionBehavior() const override;
+
void InitSendable(wpi::SendableBuilder& builder) override;
private:
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/DeferredCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/DeferredCommand.h
new file mode 100644
index 0000000..442076d
--- /dev/null
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/DeferredCommand.h
@@ -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
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/FunctionalCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/FunctionalCommand.h
index ef2b5b9..ac11765 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/FunctionalCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/FunctionalCommand.h
@@ -5,11 +5,10 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -21,7 +20,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class FunctionalCommand : public CommandHelper<CommandBase, FunctionalCommand> {
+class FunctionalCommand : public CommandHelper<Command, FunctionalCommand> {
public:
/**
* Creates a new FunctionalCommand.
@@ -37,23 +36,7 @@
std::function<void()> onExecute,
std::function<void(bool)> onEnd,
std::function<bool()> isFinished,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new FunctionalCommand.
- *
- * @param onInit the function to run on command initialization
- * @param onExecute the function to run on command execution
- * @param onEnd the function to run on command end
- * @param isFinished the function that determines whether the command has
- * finished
- * @param requirements the subsystems required by this command
- */
- FunctionalCommand(std::function<void()> onInit,
- std::function<void()> onExecute,
- std::function<void(bool)> onEnd,
- std::function<bool()> isFinished,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
FunctionalCommand(FunctionalCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/InstantCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/InstantCommand.h
index cae0b3e..3ac32ec 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/InstantCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/InstantCommand.h
@@ -5,11 +5,10 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -28,18 +27,8 @@
* @param toRun the Runnable to run
* @param requirements the subsystems required by this command
*/
- InstantCommand(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new InstantCommand that runs the given Runnable with the given
- * requirements.
- *
- * @param toRun the Runnable to run
- * @param requirements the subsystems required by this command
- */
explicit InstantCommand(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
InstantCommand(InstantCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/MecanumControllerCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/MecanumControllerCommand.h
index 8ebdbe0..e189ef1 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/MecanumControllerCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/MecanumControllerCommand.h
@@ -4,9 +4,7 @@
#include <cmath>
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <frc/Timer.h>
#include <frc/controller/HolonomicDriveController.h>
@@ -23,8 +21,9 @@
#include <units/velocity.h>
#include <units/voltage.h>
-#include "CommandBase.h"
-#include "CommandHelper.h"
+#include "frc2/command/Command.h"
+#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
#pragma once
@@ -51,7 +50,7 @@
* This class is provided by the NewCommands VendorDep
*/
class MecanumControllerCommand
- : public CommandHelper<CommandBase, MecanumControllerCommand> {
+ : public CommandHelper<Command, MecanumControllerCommand> {
public:
/**
* Constructs a new MecanumControllerCommand that when executed will follow
@@ -89,20 +88,20 @@
MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
units::meters_per_second_t maxWheelVelocity,
std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
+ frc::PIDController frontLeftController,
+ frc::PIDController rearLeftController,
+ frc::PIDController frontRightController,
+ frc::PIDController rearRightController,
std::function<void(units::volt_t, units::volt_t, units::volt_t,
units::volt_t)>
output,
- std::initializer_list<Subsystem*> requirements);
+ Requirements requirements = {});
/**
* Constructs a new MecanumControllerCommand that when executed will follow
@@ -143,123 +142,19 @@
MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
+ frc::PIDController frontLeftController,
+ frc::PIDController rearLeftController,
+ frc::PIDController frontRightController,
+ frc::PIDController rearRightController,
std::function<void(units::volt_t, units::volt_t, units::volt_t,
units::volt_t)>
output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new MecanumControllerCommand that when executed will follow
- * the provided trajectory. PID control and feedforward are handled
- * internally. Outputs are scaled from -12 to 12 as a voltage output to the
- * motor.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param feedforward The feedforward to use for the drivetrain.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param desiredRotation The angle that the robot should be facing.
- * This is sampled at each time step.
- * @param maxWheelVelocity The maximum velocity of a drivetrain wheel.
- * @param frontLeftController The front left wheel velocity PID.
- * @param rearLeftController The rear left wheel velocity PID.
- * @param frontRightController The front right wheel velocity PID.
- * @param rearRightController The rear right wheel velocity PID.
- * @param currentWheelSpeeds A MecanumDriveWheelSpeeds object containing
- * the current wheel speeds.
- * @param output The output of the velocity PIDs.
- * @param requirements The subsystems to require.
- */
- MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- units::meters_per_second_t maxWheelVelocity,
- std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
- std::function<void(units::volt_t, units::volt_t, units::volt_t,
- units::volt_t)>
- output,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Constructs a new MecanumControllerCommand that when executed will follow
- * the provided trajectory. PID control and feedforward are handled
- * internally. Outputs are scaled from -12 to 12 as a voltage output to the
- * motor.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- * <p>Note 2: The final rotation of the robot will be set to the rotation of
- * the final pose in the trajectory. The robot will not follow the rotations
- * from the poses at each timestep. If alternate rotation behavior is desired,
- * the other constructor with a supplier for rotation should be used.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param feedforward The feedforward to use for the drivetrain.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param maxWheelVelocity The maximum velocity of a drivetrain wheel.
- * @param frontLeftController The front left wheel velocity PID.
- * @param rearLeftController The rear left wheel velocity PID.
- * @param frontRightController The front right wheel velocity PID.
- * @param rearRightController The rear right wheel velocity PID.
- * @param currentWheelSpeeds A MecanumDriveWheelSpeeds object containing
- * the current wheel speeds.
- * @param output The output of the velocity PIDs.
- * @param requirements The subsystems to require.
- */
- MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- units::meters_per_second_t maxWheelVelocity,
- std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
- frc2::PIDController frontLeftController,
- frc2::PIDController rearLeftController,
- frc2::PIDController frontRightController,
- frc2::PIDController rearRightController,
- std::function<void(units::volt_t, units::volt_t, units::volt_t,
- units::volt_t)>
- output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
/**
* Constructs a new MecanumControllerCommand that when executed will follow
@@ -288,8 +183,8 @@
*/
MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
units::meters_per_second_t maxWheelVelocity,
@@ -297,7 +192,7 @@
units::meters_per_second_t,
units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements);
+ Requirements requirements);
/**
* Constructs a new MecanumControllerCommand that when executed will follow
@@ -329,93 +224,15 @@
*/
MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
+ frc::MecanumDriveKinematics kinematics, frc::PIDController xController,
+ frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<void(units::meters_per_second_t, units::meters_per_second_t,
units::meters_per_second_t,
units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new MecanumControllerCommand that when executed will follow
- * the provided trajectory. The user should implement a velocity PID on the
- * desired output wheel velocities.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path - this is left to the user, since it is not
- * appropriate for paths with nonstationary end-states.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose - use one
- * of the odometry classes to provide this.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param desiredRotation The angle that the robot should be facing.
- * This is sampled at every time step.
- * @param maxWheelVelocity The maximum velocity of a drivetrain wheel.
- * @param output The output of the position PIDs.
- * @param requirements The subsystems to require.
- */
- MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- units::meters_per_second_t maxWheelVelocity,
- std::function<void(units::meters_per_second_t, units::meters_per_second_t,
- units::meters_per_second_t,
- units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Constructs a new MecanumControllerCommand that when executed will follow
- * the provided trajectory. The user should implement a velocity PID on the
- * desired output wheel velocities.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path - this is left to the user, since it is not
- * appropriate for paths with nonstationary end-states.
- *
- * <p>Note2: The final rotation of the robot will be set to the rotation of
- * the final pose in the trajectory. The robot will not follow the rotations
- * from the poses at each timestep. If alternate rotation behavior is desired,
- * the other constructor with a supplier for rotation should be used.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose - use one
- * of the odometry classes to provide this.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param maxWheelVelocity The maximum velocity of a drivetrain wheel.
- * @param output The output of the position PIDs.
- * @param requirements The subsystems to require.
- */
- MecanumControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
- frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- units::meters_per_second_t maxWheelVelocity,
- std::function<void(units::meters_per_second_t, units::meters_per_second_t,
- units::meters_per_second_t,
- units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
void Initialize() override;
@@ -433,10 +250,10 @@
frc::HolonomicDriveController m_controller;
std::function<frc::Rotation2d()> m_desiredRotation;
const units::meters_per_second_t m_maxWheelVelocity;
- std::unique_ptr<frc2::PIDController> m_frontLeftController;
- std::unique_ptr<frc2::PIDController> m_rearLeftController;
- std::unique_ptr<frc2::PIDController> m_frontRightController;
- std::unique_ptr<frc2::PIDController> m_rearRightController;
+ std::unique_ptr<frc::PIDController> m_frontLeftController;
+ std::unique_ptr<frc::PIDController> m_rearLeftController;
+ std::unique_ptr<frc::PIDController> m_frontRightController;
+ std::unique_ptr<frc::PIDController> m_rearRightController;
std::function<frc::MecanumDriveWheelSpeeds()> m_currentWheelSpeeds;
std::function<void(units::meters_per_second_t, units::meters_per_second_t,
units::meters_per_second_t, units::meters_per_second_t)>
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/NotifierCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/NotifierCommand.h
index 607799b..d17867b 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/NotifierCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/NotifierCommand.h
@@ -5,14 +5,13 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include <frc/Notifier.h>
#include <units/time.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -27,7 +26,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class NotifierCommand : public CommandHelper<CommandBase, NotifierCommand> {
+class NotifierCommand : public CommandHelper<Command, NotifierCommand> {
public:
/**
* Creates a new NotifierCommand.
@@ -37,17 +36,7 @@
* @param requirements the subsystems required by this command
*/
NotifierCommand(std::function<void()> toRun, units::second_t period,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new NotifierCommand.
- *
- * @param toRun the runnable for the notifier to run
- * @param period the period at which the notifier should run
- * @param requirements the subsystems required by this command
- */
- NotifierCommand(std::function<void()> toRun, units::second_t period,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
NotifierCommand(NotifierCommand&& other);
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/PIDCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/PIDCommand.h
index 818c50b..bede6d0 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/PIDCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/PIDCommand.h
@@ -5,13 +5,12 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include <frc/controller/PIDController.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -24,7 +23,7 @@
*
* @see PIDController
*/
-class PIDCommand : public CommandHelper<CommandBase, PIDCommand> {
+class PIDCommand : public CommandHelper<Command, PIDCommand> {
public:
/**
* Creates a new PIDCommand, which controls the given output with a
@@ -36,27 +35,11 @@
* @param useOutput the controller's output
* @param requirements the subsystems required by this command
*/
- PIDCommand(PIDController controller,
+ PIDCommand(frc::PIDController controller,
std::function<double()> measurementSource,
std::function<double()> setpointSource,
std::function<void(double)> useOutput,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * PIDController.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param setpointSource the controller's reference (aka setpoint)
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- PIDCommand(PIDController controller,
- std::function<double()> measurementSource,
- std::function<double()> setpointSource,
- std::function<void(double)> useOutput,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
/**
* Creates a new PIDCommand, which controls the given output with a
@@ -68,25 +51,10 @@
* @param useOutput the controller's output
* @param requirements the subsystems required by this command
*/
- PIDCommand(PIDController controller,
+ PIDCommand(frc::PIDController controller,
std::function<double()> measurementSource, double setpoint,
std::function<void(double)> useOutput,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * PIDController with a constant setpoint.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param setpoint the controller's setpoint (aka setpoint)
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- PIDCommand(PIDController controller,
- std::function<double()> measurementSource, double setpoint,
- std::function<void(double)> useOutput,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
PIDCommand(PIDCommand&& other) = default;
@@ -103,10 +71,10 @@
*
* @return The PIDController
*/
- PIDController& GetController();
+ frc::PIDController& GetController();
protected:
- PIDController m_controller;
+ frc::PIDController m_controller;
std::function<double()> m_measurement;
std::function<double()> m_setpoint;
std::function<void(double)> m_useOutput;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/PIDSubsystem.h b/wpilibNewCommands/src/main/native/include/frc2/command/PIDSubsystem.h
index 426e3ec..af61430 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/PIDSubsystem.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/PIDSubsystem.h
@@ -25,7 +25,8 @@
* @param controller the PIDController to use
* @param initialPosition the initial setpoint of the subsystem
*/
- explicit PIDSubsystem(PIDController controller, double initialPosition = 0);
+ explicit PIDSubsystem(frc::PIDController controller,
+ double initialPosition = 0);
void Periodic() override;
@@ -65,10 +66,10 @@
*
* @return The controller.
*/
- PIDController& GetController();
+ frc::PIDController& GetController();
protected:
- PIDController m_controller;
+ frc::PIDController m_controller;
bool m_enabled{false};
/**
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelCommandGroup.h b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelCommandGroup.h
index 943b62f..bb33a05 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelCommandGroup.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelCommandGroup.h
@@ -9,11 +9,15 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <memory>
+#include <type_traits>
#include <utility>
#include <vector>
-#include "frc2/command/CommandGroupBase.h"
+#include <wpi/DecayedDerivedFrom.h>
+
+#include "frc2/command/CommandBase.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -29,7 +33,7 @@
* This class is provided by the NewCommands VendorDep
*/
class ParallelCommandGroup
- : public CommandHelper<CommandGroupBase, ParallelCommandGroup> {
+ : public CommandHelper<Command, ParallelCommandGroup> {
public:
/**
* Creates a new ParallelCommandGroup. The given commands will be executed
@@ -50,11 +54,9 @@
*
* @param commands the commands to include in this composition.
*/
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- explicit ParallelCommandGroup(Types&&... commands) {
- AddCommands(std::forward<Types>(commands)...);
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ explicit ParallelCommandGroup(Commands&&... commands) {
+ AddCommands(std::forward<Commands>(commands)...);
}
ParallelCommandGroup(ParallelCommandGroup&& other) = default;
@@ -65,13 +67,16 @@
// Prevent template expansion from emulating copy ctor
ParallelCommandGroup(ParallelCommandGroup&) = delete;
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- void AddCommands(Types&&... commands) {
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
- ((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
- std::forward<Types>(commands))),
+ ((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
+ std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
@@ -89,7 +94,7 @@
Command::InterruptionBehavior GetInterruptionBehavior() const override;
private:
- void AddCommands(std::vector<std::unique_ptr<Command>>&& commands) final;
+ void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
std::vector<std::pair<std::unique_ptr<Command>, bool>> m_commands;
bool m_runWhenDisabled{true};
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelDeadlineGroup.h b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelDeadlineGroup.h
index cfe4b3e..9e253fb 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelDeadlineGroup.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelDeadlineGroup.h
@@ -9,11 +9,15 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <memory>
+#include <type_traits>
#include <utility>
#include <vector>
-#include "frc2/command/CommandGroupBase.h"
+#include <wpi/DecayedDerivedFrom.h>
+
+#include "frc2/command/CommandBase.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -30,7 +34,7 @@
* This class is provided by the NewCommands VendorDep
*/
class ParallelDeadlineGroup
- : public CommandHelper<CommandGroupBase, ParallelDeadlineGroup> {
+ : public CommandHelper<Command, ParallelDeadlineGroup> {
public:
/**
* Creates a new ParallelDeadlineGroup. The given commands (including the
@@ -54,15 +58,11 @@
* @param deadline the command that determines when the composition ends
* @param commands the commands to be executed
*/
- template <class T, class... Types,
- typename = std::enable_if_t<
- std::is_base_of_v<Command, std::remove_reference_t<T>>>,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- explicit ParallelDeadlineGroup(T&& deadline, Types&&... commands) {
- SetDeadline(std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(deadline)));
- AddCommands(std::forward<Types>(commands)...);
+ template <wpi::DecayedDerivedFrom<Command> T,
+ wpi::DecayedDerivedFrom<Command>... Commands>
+ explicit ParallelDeadlineGroup(T&& deadline, Commands&&... commands) {
+ SetDeadline(std::make_unique<std::decay_t<T>>(std::forward<T>(deadline)));
+ AddCommands(std::forward<Commands>(commands)...);
}
ParallelDeadlineGroup(ParallelDeadlineGroup&& other) = default;
@@ -73,13 +73,16 @@
// Prevent template expansion from emulating copy ctor
ParallelDeadlineGroup(ParallelDeadlineGroup&) = delete;
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- void AddCommands(Types&&... commands) {
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
- ((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
- std::forward<Types>(commands))),
+ ((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
+ std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
@@ -99,7 +102,7 @@
void InitSendable(wpi::SendableBuilder& builder) override;
private:
- void AddCommands(std::vector<std::unique_ptr<Command>>&& commands) final;
+ void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
void SetDeadline(std::unique_ptr<Command>&& deadline);
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelRaceGroup.h b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelRaceGroup.h
index d5412cd..caefa48 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ParallelRaceGroup.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ParallelRaceGroup.h
@@ -9,11 +9,15 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <memory>
+#include <type_traits>
#include <utility>
#include <vector>
-#include "frc2/command/CommandGroupBase.h"
+#include <wpi/DecayedDerivedFrom.h>
+
+#include "frc2/command/CommandBase.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -28,8 +32,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class ParallelRaceGroup
- : public CommandHelper<CommandGroupBase, ParallelRaceGroup> {
+class ParallelRaceGroup : public CommandHelper<Command, ParallelRaceGroup> {
public:
/**
* Creates a new ParallelCommandRace. The given commands will be executed
@@ -40,11 +43,9 @@
*/
explicit ParallelRaceGroup(std::vector<std::unique_ptr<Command>>&& commands);
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- explicit ParallelRaceGroup(Types&&... commands) {
- AddCommands(std::forward<Types>(commands)...);
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ explicit ParallelRaceGroup(Commands&&... commands) {
+ AddCommands(std::forward<Commands>(commands)...);
}
ParallelRaceGroup(ParallelRaceGroup&& other) = default;
@@ -55,11 +56,16 @@
// Prevent template expansion from emulating copy ctor
ParallelRaceGroup(ParallelRaceGroup&) = delete;
- template <class... Types>
- void AddCommands(Types&&... commands) {
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add to the group.
+ */
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
- ((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
- std::forward<Types>(commands))),
+ ((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
+ std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
@@ -77,7 +83,7 @@
Command::InterruptionBehavior GetInterruptionBehavior() const override;
private:
- void AddCommands(std::vector<std::unique_ptr<Command>>&& commands) final;
+ void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
std::vector<std::unique_ptr<Command>> m_commands;
bool m_runWhenDisabled{true};
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/PerpetualCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/PerpetualCommand.h
deleted file mode 100644
index 297cb64..0000000
--- a/wpilibNewCommands/src/main/native/include/frc2/command/PerpetualCommand.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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
-
-#ifdef _WIN32
-#pragma warning(push)
-#pragma warning(disable : 4521)
-#endif
-
-#include <memory>
-#include <utility>
-
-#include "frc2/command/CommandBase.h"
-#include "frc2/command/CommandHelper.h"
-
-namespace frc2 {
-/**
- * A command that runs another command in perpetuity, ignoring that command's
- * end conditions. While this class does not extend frc2::CommandGroupBase,
- * it is still considered a CommandGroup, as it allows one to compose another
- * command within it; the command instances that are passed to it cannot be
- * added to any other groups, or scheduled individually.
- *
- * <p>As a rule, CommandGroups require the union of the requirements of their
- * component commands.
- *
- * This class is provided by the NewCommands VendorDep
- *
- * @deprecated PerpetualCommand violates the assumption that execute() doesn't
-get called after isFinished() returns true -- an assumption that should be
-valid. This was unsafe/undefined behavior from the start, and RepeatCommand
-provides an easy way to achieve similar end results with slightly different (and
-safe) semantics.
- */
-class PerpetualCommand : public CommandHelper<CommandBase, PerpetualCommand> {
- public:
- /**
- * Creates a new PerpetualCommand. Will run another command in perpetuity,
- * ignoring that command's end conditions, unless this command itself is
- * interrupted.
- *
- * @param command the command to run perpetually
- */
- WPI_DEPRECATED(
- "PerpetualCommand violates the assumption that execute() doesn't get "
- "called after isFinished() returns true -- an assumption that should be "
- "valid."
- "This was unsafe/undefined behavior from the start, and RepeatCommand "
- "provides an easy way to achieve similar end results with slightly "
- "different (and safe) semantics.")
- explicit PerpetualCommand(std::unique_ptr<Command>&& command);
- WPI_IGNORE_DEPRECATED
-
- /**
- * Creates a new PerpetualCommand. Will run another command in perpetuity,
- * ignoring that command's end conditions, unless this command itself is
- * interrupted.
- *
- * @param command the command to run perpetually
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED(
- "PerpetualCommand violates the assumption that execute() doesn't get "
- "called after isFinished() returns true -- an assumption that should be "
- "valid."
- "This was unsafe/undefined behavior from the start, and RepeatCommand "
- "provides an easy way to achieve similar end results with slightly "
- "different (and safe) semantics.")
- explicit PerpetualCommand(T&& command)
- : PerpetualCommand(std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))) {}
- WPI_UNIGNORE_DEPRECATED
-
- PerpetualCommand(PerpetualCommand&& other) = default;
-
- // No copy constructors for command groups
- PerpetualCommand(const PerpetualCommand& other) = delete;
-
- // Prevent template expansion from emulating copy ctor
- PerpetualCommand(PerpetualCommand&) = delete;
-
- void Initialize() override;
-
- void Execute() override;
-
- void End(bool interrupted) override;
-
- private:
- std::unique_ptr<Command> m_command;
-};
-} // namespace frc2
-
-#ifdef _WIN32
-#pragma warning(pop)
-#endif
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ProfiledPIDCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ProfiledPIDCommand.h
index 3fbe726..9ea5db5 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ProfiledPIDCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ProfiledPIDCommand.h
@@ -5,15 +5,14 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include <utility>
#include <frc/controller/ProfiledPIDController.h>
#include <units/time.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -28,7 +27,7 @@
*/
template <class Distance>
class ProfiledPIDCommand
- : public CommandHelper<CommandBase, ProfiledPIDCommand<Distance>> {
+ : public CommandHelper<Command, ProfiledPIDCommand<Distance>> {
using Distance_t = units::unit_t<Distance>;
using Velocity =
units::compound_unit<Distance, units::inverse<units::seconds>>;
@@ -50,29 +49,7 @@
std::function<Distance_t()> measurementSource,
std::function<State()> goalSource,
std::function<void(double, State)> useOutput,
- std::initializer_list<Subsystem*> requirements)
- : m_controller{controller},
- m_measurement{std::move(measurementSource)},
- m_goal{std::move(goalSource)},
- m_useOutput{std::move(useOutput)} {
- this->AddRequirements(requirements);
- }
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * ProfiledPIDController.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param goalSource the controller's goal
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- ProfiledPIDCommand(frc::ProfiledPIDController<Distance> controller,
- std::function<Distance_t()> measurementSource,
- std::function<State()> goalSource,
- std::function<void(double, State)> useOutput,
- std::span<Subsystem* const> requirements = {})
+ Requirements requirements = {})
: m_controller{controller},
m_measurement{std::move(measurementSource)},
m_goal{std::move(goalSource)},
@@ -94,29 +71,7 @@
std::function<Distance_t()> measurementSource,
std::function<Distance_t()> goalSource,
std::function<void(double, State)> useOutput,
- std::initializer_list<Subsystem*> requirements)
- : ProfiledPIDCommand(
- controller, measurementSource,
- [goalSource = std::move(goalSource)]() {
- return State{goalSource(), Velocity_t{0}};
- },
- useOutput, requirements) {}
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * ProfiledPIDController.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param goalSource the controller's goal
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- ProfiledPIDCommand(frc::ProfiledPIDController<Distance> controller,
- std::function<Distance_t()> measurementSource,
- std::function<Distance_t()> goalSource,
- std::function<void(double, State)> useOutput,
- std::span<Subsystem* const> requirements = {})
+ Requirements requirements = {})
: ProfiledPIDCommand(
controller, measurementSource,
[goalSource = std::move(goalSource)]() {
@@ -137,25 +92,7 @@
ProfiledPIDCommand(frc::ProfiledPIDController<Distance> controller,
std::function<Distance_t()> measurementSource, State goal,
std::function<void(double, State)> useOutput,
- std::initializer_list<Subsystem*> requirements)
- : ProfiledPIDCommand(
- controller, measurementSource, [goal] { return goal; }, useOutput,
- requirements) {}
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * ProfiledPIDController with a constant goal.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param goal the controller's goal
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- ProfiledPIDCommand(frc::ProfiledPIDController<Distance> controller,
- std::function<Distance_t()> measurementSource, State goal,
- std::function<void(double, State)> useOutput,
- std::span<Subsystem* const> requirements = {})
+ Requirements requirements = {})
: ProfiledPIDCommand(
controller, measurementSource, [goal] { return goal; }, useOutput,
requirements) {}
@@ -174,26 +111,7 @@
std::function<Distance_t()> measurementSource,
Distance_t goal,
std::function<void(double, State)> useOutput,
- std::initializer_list<Subsystem*> requirements)
- : ProfiledPIDCommand(
- controller, measurementSource, [goal] { return goal; }, useOutput,
- requirements) {}
-
- /**
- * Creates a new PIDCommand, which controls the given output with a
- * ProfiledPIDController with a constant goal.
- *
- * @param controller the controller that controls the output.
- * @param measurementSource the measurement of the process variable
- * @param goal the controller's goal
- * @param useOutput the controller's output
- * @param requirements the subsystems required by this command
- */
- ProfiledPIDCommand(frc::ProfiledPIDController<Distance> controller,
- std::function<Distance_t()> measurementSource,
- Distance_t goal,
- std::function<void(double, State)> useOutput,
- std::span<Subsystem* const> requirements = {})
+ Requirements requirements = {})
: ProfiledPIDCommand(
controller, measurementSource, [goal] { return goal; }, useOutput,
requirements) {}
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h
index b4a00a5..3b7eecc 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h
@@ -5,13 +5,11 @@
#pragma once
#include <memory>
-#include <span>
#include <wpi/FunctionExtras.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
-#include "frc2/command/SetUtilities.h"
namespace frc2 {
/**
@@ -21,7 +19,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-class ProxyCommand : public CommandHelper<CommandBase, ProxyCommand> {
+class ProxyCommand : public CommandHelper<Command, ProxyCommand> {
public:
/**
* Creates a new ProxyCommand that schedules the supplied command when
@@ -33,6 +31,15 @@
explicit ProxyCommand(wpi::unique_function<Command*()> supplier);
/**
+ * Creates a new ProxyCommand that schedules the supplied command when
+ * initialized, and ends when it is no longer scheduled. Useful for lazily
+ * creating commands at runtime.
+ *
+ * @param supplier the command supplier
+ */
+ explicit ProxyCommand(wpi::unique_function<CommandPtr()> supplier);
+
+ /**
* Creates a new ProxyCommand that schedules the given command when
* initialized, and ends when it is no longer scheduled.
*
@@ -57,8 +64,6 @@
void End(bool interrupted) override;
- void Execute() override;
-
bool IsFinished() override;
void InitSendable(wpi::SendableBuilder& builder) override;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyScheduleCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ProxyScheduleCommand.h
deleted file mode 100644
index f79b549..0000000
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyScheduleCommand.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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/SmallVector.h>
-#include <wpi/deprecated.h>
-
-#include "frc2/command/CommandBase.h"
-#include "frc2/command/CommandHelper.h"
-#include "frc2/command/SetUtilities.h"
-
-namespace frc2 {
-/**
- * Schedules the given commands when this command is initialized, and ends when
- * all the commands are no longer scheduled. Useful for forking off from
- * CommandGroups. If this command is interrupted, it will cancel all of the
- * commands.
- *
- * This class is provided by the NewCommands VendorDep
- */
-class ProxyScheduleCommand
- : public CommandHelper<CommandBase, ProxyScheduleCommand> {
- public:
- /**
- * Creates a new ProxyScheduleCommand that schedules the given commands when
- * initialized, and ends when they are all no longer scheduled.
- *
- * @param toSchedule the commands to schedule
- * @deprecated Replace with {@link ProxyCommand},
- * composing multiple of them in a {@link ParallelRaceGroup} if needed.
- */
- WPI_DEPRECATED("Replace with ProxyCommand")
- explicit ProxyScheduleCommand(std::span<Command* const> toSchedule);
-
- explicit ProxyScheduleCommand(Command* toSchedule);
-
- ProxyScheduleCommand(ProxyScheduleCommand&& other) = default;
-
- void Initialize() override;
-
- void End(bool interrupted) override;
-
- void Execute() override;
-
- bool IsFinished() override;
-
- private:
- wpi::SmallVector<Command*, 4> m_toSchedule;
- std::unique_ptr<Command> m_owning;
- bool m_finished{false};
-};
-} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/RamseteCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/RamseteCommand.h
index d375e11..56fb8ff 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/RamseteCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/RamseteCommand.h
@@ -5,9 +5,7 @@
#pragma once
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <frc/Timer.h>
#include <frc/controller/PIDController.h>
@@ -19,8 +17,9 @@
#include <units/length.h>
#include <units/voltage.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -42,7 +41,7 @@
* @see RamseteController
* @see Trajectory
*/
-class RamseteCommand : public CommandHelper<CommandBase, RamseteCommand> {
+class RamseteCommand : public CommandHelper<Command, RamseteCommand> {
public:
/**
* Constructs a new RamseteCommand that, when executed, will follow the
@@ -76,47 +75,10 @@
frc::SimpleMotorFeedforward<units::meters> feedforward,
frc::DifferentialDriveKinematics kinematics,
std::function<frc::DifferentialDriveWheelSpeeds()> wheelSpeeds,
- frc2::PIDController leftController,
- frc2::PIDController rightController,
+ frc::PIDController leftController,
+ frc::PIDController rightController,
std::function<void(units::volt_t, units::volt_t)> output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new RamseteCommand that, when executed, will follow the
- * provided trajectory. PID control and feedforward are handled internally,
- * and outputs are scaled -12 to 12 representing units of volts.
- *
- * <p>Note: The controller will *not* set the outputVolts to zero upon
- * completion of the path - this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose - use one of
- * the odometry classes to provide this.
- * @param controller The RAMSETE controller used to follow the
- * trajectory.
- * @param feedforward A component for calculating the feedforward for the
- * drive.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param wheelSpeeds A function that supplies the speeds of the left
- * and right sides of the robot drive.
- * @param leftController The PIDController for the left side of the robot
- * drive.
- * @param rightController The PIDController for the right side of the robot
- * drive.
- * @param output A function that consumes the computed left and right
- * outputs (in volts) for the robot drive.
- * @param requirements The subsystems to require.
- */
- RamseteCommand(frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::RamseteController controller,
- frc::SimpleMotorFeedforward<units::meters> feedforward,
- frc::DifferentialDriveKinematics kinematics,
- std::function<frc::DifferentialDriveWheelSpeeds()> wheelSpeeds,
- frc2::PIDController leftController,
- frc2::PIDController rightController,
- std::function<void(units::volt_t, units::volt_t)> output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
/**
* Constructs a new RamseteCommand that, when executed, will follow the
@@ -140,31 +102,7 @@
std::function<void(units::meters_per_second_t,
units::meters_per_second_t)>
output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new RamseteCommand that, when executed, will follow the
- * provided trajectory. Performs no PID control and calculates no
- * feedforwards; outputs are the raw wheel speeds from the RAMSETE controller,
- * and will need to be converted into a usable form by the user.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose - use one of
- * the odometry classes to provide this.
- * @param controller The RAMSETE controller used to follow the
- * trajectory.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param output A function that consumes the computed left and right
- * wheel speeds.
- * @param requirements The subsystems to require.
- */
- RamseteCommand(frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::RamseteController controller,
- frc::DifferentialDriveKinematics kinematics,
- std::function<void(units::meters_per_second_t,
- units::meters_per_second_t)>
- output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
void Initialize() override;
@@ -183,8 +121,8 @@
frc::SimpleMotorFeedforward<units::meters> m_feedforward;
frc::DifferentialDriveKinematics m_kinematics;
std::function<frc::DifferentialDriveWheelSpeeds()> m_speeds;
- std::unique_ptr<frc2::PIDController> m_leftController;
- std::unique_ptr<frc2::PIDController> m_rightController;
+ std::unique_ptr<frc::PIDController> m_leftController;
+ std::unique_ptr<frc::PIDController> m_rightController;
std::function<void(units::volt_t, units::volt_t)> m_outputVolts;
std::function<void(units::meters_per_second_t, units::meters_per_second_t)>
m_outputVel;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/RepeatCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/RepeatCommand.h
index 5d353b9..9c1a5d1 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/RepeatCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/RepeatCommand.h
@@ -9,10 +9,11 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <memory>
#include <utility>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -28,7 +29,7 @@
*
* <p>This class is provided by the NewCommands VendorDep
*/
-class RepeatCommand : public CommandHelper<CommandBase, RepeatCommand> {
+class RepeatCommand : public CommandHelper<Command, RepeatCommand> {
public:
/**
* Creates a new RepeatCommand. Will run another command repeatedly,
@@ -44,11 +45,11 @@
*
* @param command the command to run repeatedly
*/
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
+ template <std::derived_from<Command> T>
+ // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit RepeatCommand(T&& command)
- : RepeatCommand(std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))) {}
+ : RepeatCommand(
+ std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
RepeatCommand(RepeatCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/Requirements.h b/wpilibNewCommands/src/main/native/include/frc2/command/Requirements.h
new file mode 100644
index 0000000..968917f
--- /dev/null
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/Requirements.h
@@ -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.
+
+#pragma once
+
+#include <initializer_list>
+#include <span>
+#include <vector>
+
+#include "frc2/command/Subsystem.h"
+
+namespace frc2 {
+
+/**
+ * Represents requirements for a command, which is a set of (pointers to)
+ * subsystems. This class is implicitly convertible from std::initializer_list
+ * and std::span.
+ */
+class Requirements {
+ public:
+ // NOLINTNEXTLINE
+ /*implicit*/ Requirements(std::initializer_list<Subsystem*> requirements)
+ : m_subsystems{requirements.begin(), requirements.end()} {}
+
+ // NOLINTNEXTLINE
+ /*implicit*/ Requirements(std::span<Subsystem* const> requirements)
+ : m_subsystems{requirements.begin(), requirements.end()} {}
+
+ Requirements() = default;
+
+ Requirements(const Requirements&) = default;
+
+ std::vector<Subsystem*>::const_iterator begin() const {
+ return m_subsystems.begin();
+ }
+
+ std::vector<Subsystem*>::const_iterator end() const {
+ return m_subsystems.end();
+ }
+
+ private:
+ std::vector<Subsystem*> m_subsystems;
+};
+
+} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/RunCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/RunCommand.h
index 3bfecf7..49e4be5 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/RunCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/RunCommand.h
@@ -5,11 +5,10 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -29,18 +28,8 @@
* @param toRun the Runnable to run
* @param requirements the subsystems to require
*/
- RunCommand(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new RunCommand. The Runnable will be run continuously until the
- * command ends. Does not run when disabled.
- *
- * @param toRun the Runnable to run
- * @param requirements the subsystems to require
- */
explicit RunCommand(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
RunCommand(RunCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ScheduleCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ScheduleCommand.h
index 63cc3b3..3c960db 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/ScheduleCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/ScheduleCommand.h
@@ -6,11 +6,10 @@
#include <span>
-#include <wpi/SmallVector.h>
+#include <wpi/SmallSet.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
-#include "frc2/command/SetUtilities.h"
namespace frc2 {
/**
@@ -21,7 +20,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class ScheduleCommand : public CommandHelper<CommandBase, ScheduleCommand> {
+class ScheduleCommand : public CommandHelper<Command, ScheduleCommand> {
public:
/**
* Creates a new ScheduleCommand that schedules the given commands when
@@ -44,6 +43,6 @@
bool RunsWhenDisabled() const override;
private:
- wpi::SmallVector<Command*, 4> m_toSchedule;
+ wpi::SmallSet<Command*, 4> m_toSchedule;
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/SelectCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/SelectCommand.h
index 7079afe..d425d76 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/SelectCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/SelectCommand.h
@@ -9,23 +9,23 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
+#include <functional>
#include <memory>
#include <string>
-#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include <wpi/sendable/SendableBuilder.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/PrintCommand.h"
namespace frc2 {
/**
- * A command composition that runs one of a selection of commands, either using
- * a selector and a key to command mapping, or a supplier that returns the
- * command directly at runtime.
+ * A command composition that runs one of a selection of commands using a
+ * selector and a key to command mapping.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
@@ -35,7 +35,7 @@
* This class is provided by the NewCommands VendorDep
*/
template <typename Key>
-class SelectCommand : public CommandHelper<CommandBase, SelectCommand<Key>> {
+class SelectCommand : public CommandHelper<Command, SelectCommand<Key>> {
public:
/**
* Creates a new SelectCommand.
@@ -43,21 +43,21 @@
* @param commands the map of commands to choose from
* @param selector the selector to determine which command to run
*/
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
+ template <std::derived_from<Command>... Commands>
explicit SelectCommand(std::function<Key()> selector,
- std::pair<Key, Types>... commands)
+ std::pair<Key, Commands>... commands)
: m_selector{std::move(selector)} {
std::vector<std::pair<Key, std::unique_ptr<Command>>> foo;
- ((void)foo.emplace_back(commands.first,
- std::make_unique<std::remove_reference_t<Types>>(
- std::move(commands.second))),
+ ((void)foo.emplace_back(
+ commands.first,
+ std::make_unique<std::decay_t<Commands>>(std::move(commands.second))),
...);
+ m_defaultCommand.SetComposed(true);
for (auto&& command : foo) {
CommandScheduler::GetInstance().RequireUngrouped(command.second.get());
+ command.second.get()->SetComposed(true);
}
for (auto&& command : foo) {
@@ -75,8 +75,10 @@
std::function<Key()> selector,
std::vector<std::pair<Key, std::unique_ptr<Command>>>&& commands)
: m_selector{std::move(selector)} {
+ m_defaultCommand.SetComposed(true);
for (auto&& command : commands) {
CommandScheduler::GetInstance().RequireUngrouped(command.second.get());
+ command.second.get()->SetComposed(true);
}
for (auto&& command : commands) {
@@ -96,17 +98,6 @@
// Prevent template expansion from emulating copy ctor
SelectCommand(SelectCommand&) = delete;
- /**
- * Creates a new selectcommand.
- *
- * @param toRun a supplier providing the command to run
- * @deprecated Replace with {@link ProxyCommand},
- * composing multiple of them in a {@link ParallelRaceGroup} if needed.
- */
- WPI_DEPRECATED("Replace with ProxyCommand")
- explicit SelectCommand(std::function<Command*()> toRun)
- : m_toRun{std::move(toRun)} {}
-
SelectCommand(SelectCommand&& other) = default;
void Initialize() override;
@@ -126,7 +117,7 @@
}
void InitSendable(wpi::SendableBuilder& builder) override {
- CommandBase::InitSendable(builder);
+ Command::InitSendable(builder);
builder.AddStringProperty(
"selected",
@@ -148,25 +139,22 @@
private:
std::unordered_map<Key, std::unique_ptr<Command>> m_commands;
std::function<Key()> m_selector;
- std::function<Command*()> m_toRun;
Command* m_selectedCommand;
bool m_runsWhenDisabled = true;
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
+
+ PrintCommand m_defaultCommand{
+ "SelectCommand selector value does not correspond to any command!"};
};
template <typename T>
void SelectCommand<T>::Initialize() {
- if (m_selector) {
- auto find = m_commands.find(m_selector());
- if (find == m_commands.end()) {
- m_selectedCommand = new PrintCommand(
- "SelectCommand selector value does not correspond to any command!");
- return;
- }
- m_selectedCommand = find->second.get();
+ auto find = m_commands.find(m_selector());
+ if (find == m_commands.end()) {
+ m_selectedCommand = &m_defaultCommand;
} else {
- m_selectedCommand = m_toRun();
+ m_selectedCommand = find->second.get();
}
m_selectedCommand->Initialize();
}
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/SequentialCommandGroup.h b/wpilibNewCommands/src/main/native/include/frc2/command/SequentialCommandGroup.h
index ba85b6a..fdcd1bc 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/SequentialCommandGroup.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/SequentialCommandGroup.h
@@ -9,14 +9,16 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <limits>
#include <memory>
-#include <span>
#include <type_traits>
#include <utility>
#include <vector>
-#include "frc2/command/CommandGroupBase.h"
+#include <wpi/DecayedDerivedFrom.h>
+
+#include "frc2/command/CommandBase.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -34,7 +36,7 @@
* This class is provided by the NewCommands VendorDep
*/
class SequentialCommandGroup
- : public CommandHelper<CommandGroupBase, SequentialCommandGroup> {
+ : public CommandHelper<Command, SequentialCommandGroup> {
public:
/**
* Creates a new SequentialCommandGroup. The given commands will be run
@@ -53,11 +55,9 @@
*
* @param commands the commands to include in this composition.
*/
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- explicit SequentialCommandGroup(Types&&... commands) {
- AddCommands(std::forward<Types>(commands)...);
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ explicit SequentialCommandGroup(Commands&&... commands) {
+ AddCommands(std::forward<Commands>(commands)...);
}
SequentialCommandGroup(SequentialCommandGroup&& other) = default;
@@ -68,13 +68,16 @@
// Prevent template expansion from emulating copy ctor
SequentialCommandGroup(SequentialCommandGroup&) = delete;
- template <class... Types,
- typename = std::enable_if_t<std::conjunction_v<
- std::is_base_of<Command, std::remove_reference_t<Types>>...>>>
- void AddCommands(Types&&... commands) {
+ /**
+ * Adds the given commands to the group.
+ *
+ * @param commands Commands to add, in order of execution.
+ */
+ template <wpi::DecayedDerivedFrom<Command>... Commands>
+ void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
- ((void)foo.emplace_back(std::make_unique<std::remove_reference_t<Types>>(
- std::forward<Types>(commands))),
+ ((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
+ std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
@@ -94,7 +97,7 @@
void InitSendable(wpi::SendableBuilder& builder) override;
private:
- void AddCommands(std::vector<std::unique_ptr<Command>>&& commands) final;
+ void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
wpi::SmallVector<std::unique_ptr<Command>, 4> m_commands;
size_t m_currentCommandIndex{invalid_index};
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/SetUtilities.h b/wpilibNewCommands/src/main/native/include/frc2/command/SetUtilities.h
deleted file mode 100644
index e70e17b..0000000
--- a/wpilibNewCommands/src/main/native/include/frc2/command/SetUtilities.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 <span>
-
-#include <wpi/SmallVector.h>
-
-namespace frc2 {
-template <typename T>
-void SetInsert(wpi::SmallVectorImpl<T*>& vector, std::span<T* const> toAdd) {
- for (auto addCommand : toAdd) {
- bool exists = false;
- for (auto existingCommand : vector) {
- if (addCommand == existingCommand) {
- exists = true;
- break;
- }
- }
- if (!exists) {
- vector.emplace_back(addCommand);
- }
- }
-}
-} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/StartEndCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/StartEndCommand.h
index b1f56b2..2367be8 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/StartEndCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/StartEndCommand.h
@@ -5,11 +5,10 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -33,18 +32,7 @@
* @param requirements the subsystems required by this command
*/
StartEndCommand(std::function<void()> onInit, std::function<void()> onEnd,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Creates a new StartEndCommand. Will run the given runnables when the
- * command starts and when it ends.
- *
- * @param onInit the Runnable to run on command init
- * @param onEnd the Runnable to run on command end
- * @param requirements the subsystems required by this command
- */
- StartEndCommand(std::function<void()> onInit, std::function<void()> onEnd,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
StartEndCommand(StartEndCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/Subsystem.h b/wpilibNewCommands/src/main/native/include/frc2/command/Subsystem.h
index 0c3a2a3..cdac0c0 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/Subsystem.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/Subsystem.h
@@ -4,9 +4,12 @@
#pragma once
-#include <type_traits>
+#include <concepts>
+#include <functional>
#include <utility>
+#include <wpi/FunctionExtras.h>
+
#include "frc2/command/CommandScheduler.h"
namespace frc2 {
@@ -65,8 +68,7 @@
*
* @param defaultCommand the default command to associate with this subsystem
*/
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
+ template <std::derived_from<Command> T>
void SetDefaultCommand(T&& defaultCommand) {
CommandScheduler::GetInstance().SetDefaultCommand(
this, std::forward<T>(defaultCommand));
@@ -84,6 +86,12 @@
void SetDefaultCommand(CommandPtr&& defaultCommand);
/**
+ * Removes the default command for the subsystem. This will not cancel the
+ * default command if it is currently running.
+ */
+ void RemoveDefaultCommand();
+
+ /**
* Gets the default command for this subsystem. Returns null if no default
* command is currently associated with the subsystem.
*
@@ -111,7 +119,8 @@
*
* @param action the action to run
*/
- [[nodiscard]] CommandPtr RunOnce(std::function<void()> action);
+ [[nodiscard]]
+ CommandPtr RunOnce(std::function<void()> action);
/**
* Constructs a command that runs an action every iteration until interrupted.
@@ -119,7 +128,8 @@
*
* @param action the action to run
*/
- [[nodiscard]] CommandPtr Run(std::function<void()> action);
+ [[nodiscard]]
+ CommandPtr Run(std::function<void()> action);
/**
* Constructs a command that runs an action once and another action when the
@@ -128,8 +138,8 @@
* @param start the action to run on start
* @param end the action to run on interrupt
*/
- [[nodiscard]] CommandPtr StartEnd(std::function<void()> start,
- std::function<void()> end);
+ [[nodiscard]]
+ CommandPtr StartEnd(std::function<void()> start, std::function<void()> end);
/**
* Constructs a command that runs an action every iteration until interrupted,
@@ -138,7 +148,17 @@
* @param run the action to run every iteration
* @param end the action to run on interrupt
*/
- [[nodiscard]] CommandPtr RunEnd(std::function<void()> run,
- std::function<void()> end);
+ [[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
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.h
index d51ae1e..ae928b8 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.h
@@ -4,9 +4,7 @@
#include <cmath>
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <frc/Timer.h>
#include <frc/controller/HolonomicDriveController.h>
@@ -21,8 +19,9 @@
#include <units/time.h>
#include <units/voltage.h>
-#include "CommandBase.h"
-#include "CommandHelper.h"
+#include "frc2/command/Command.h"
+#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
#pragma once
@@ -51,7 +50,7 @@
*/
template <size_t NumModules>
class SwerveControllerCommand
- : public CommandHelper<CommandBase, SwerveControllerCommand<NumModules>> {
+ : public CommandHelper<Command, SwerveControllerCommand<NumModules>> {
using voltsecondspermeter =
units::compound_unit<units::voltage::volt, units::second,
units::inverse<units::meter>>;
@@ -89,12 +88,12 @@
SwerveControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
+ frc::PIDController xController, frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
output,
- std::initializer_list<Subsystem*> requirements);
+ Requirements requirements = {});
/**
* Constructs a new SwerveControllerCommand that when executed will follow the
@@ -128,86 +127,11 @@
SwerveControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
+ frc::PIDController xController, frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new SwerveControllerCommand that when executed will follow the
- * provided trajectory. This command will not return output voltages but
- * rather raw module states from the position controllers which need to be put
- * into a velocity PID.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path- this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param desiredRotation The angle that the drivetrain should be
- * facing. This is sampled at each time step.
- * @param output The raw output module states from the
- * position controllers.
- * @param requirements The subsystems to require.
- */
- SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
- output,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Constructs a new SwerveControllerCommand that when executed will follow the
- * provided trajectory. This command will not return output voltages but
- * rather raw module states from the position controllers which need to be put
- * into a velocity PID.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path- this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- * <p>Note 2: The final rotation of the robot will be set to the rotation of
- * the final pose in the trajectory. The robot will not follow the rotations
- * from the poses at each timestep. If alternate rotation behavior is desired,
- * the other constructor with a supplier for rotation should be used.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param xController The Trajectory Tracker PID controller
- * for the robot's x position.
- * @param yController The Trajectory Tracker PID controller
- * for the robot's y position.
- * @param thetaController The Trajectory Tracker PID controller
- * for angle for the robot.
- * @param output The raw output module states from the
- * position controllers.
- * @param requirements The subsystems to require.
- */
- SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
- output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
/**
* Constructs a new SwerveControllerCommand that when executed will follow the
@@ -237,7 +161,7 @@
std::function<frc::Rotation2d()> desiredRotation,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
output,
- std::initializer_list<Subsystem*> requirements);
+ Requirements requirements = {});
/**
* Constructs a new SwerveControllerCommand that when executed will follow the
@@ -269,70 +193,7 @@
frc::HolonomicDriveController controller,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
output,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Constructs a new SwerveControllerCommand that when executed will follow the
- * provided trajectory. This command will not return output voltages but
- * rather raw module states from the position controllers which need to be put
- * into a velocity PID.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path- this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param controller The HolonomicDriveController for the robot.
- * @param desiredRotation The angle that the drivetrain should be
- * facing. This is sampled at each time step.
- * @param output The raw output module states from the
- * position controllers.
- * @param requirements The subsystems to require.
- */
- SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc::HolonomicDriveController controller,
- std::function<frc::Rotation2d()> desiredRotation,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
- output,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Constructs a new SwerveControllerCommand that when executed will follow the
- * provided trajectory. This command will not return output voltages but
- * rather raw module states from the position controllers which need to be put
- * into a velocity PID.
- *
- * <p>Note: The controllers will *not* set the outputVolts to zero upon
- * completion of the path- this is left to the user, since it is not
- * appropriate for paths with nonstationary endstates.
- *
- * <p>Note 2: The final rotation of the robot will be set to the rotation of
- * the final pose in the trajectory. The robot will not follow the rotations
- * from the poses at each timestep. If alternate rotation behavior is desired,
- * the other constructor with a supplier for rotation should be used.
- *
- * @param trajectory The trajectory to follow.
- * @param pose A function that supplies the robot pose,
- * provided by the odometry class.
- * @param kinematics The kinematics for the robot drivetrain.
- * @param controller The HolonomicDriveController for the drivetrain.
- * @param output The raw output module states from the
- * position controllers.
- * @param requirements The subsystems to require.
- */
- SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc::HolonomicDriveController controller,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)>
- output,
- std::span<Subsystem* const> requirements = {});
+ Requirements requirements = {});
void Initialize() override;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.inc b/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.inc
index a644057..d0c34af 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.inc
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/SwerveControllerCommand.inc
@@ -4,6 +4,7 @@
#pragma once
+#include <functional>
#include <memory>
#include <utility>
@@ -15,11 +16,11 @@
SwerveControllerCommand<NumModules>::SwerveControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
+ frc::PIDController xController, frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<frc::Rotation2d()> desiredRotation,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -33,44 +34,10 @@
SwerveControllerCommand<NumModules>::SwerveControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
+ frc::PIDController xController, frc::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::initializer_list<Subsystem*> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_outputStates(output) {
- this->AddRequirements(requirements);
-}
-
-template <size_t NumModules>
-SwerveControllerCommand<NumModules>::SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<frc::Rotation2d()> desiredRotation,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(xController, yController, thetaController),
- m_desiredRotation(std::move(desiredRotation)),
- m_outputStates(output) {
- this->AddRequirements(requirements);
-}
-
-template <size_t NumModules>
-SwerveControllerCommand<NumModules>::SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc2::PIDController xController, frc2::PIDController yController,
- frc::ProfiledPIDController<units::radians> thetaController,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -86,7 +53,7 @@
frc::HolonomicDriveController controller,
std::function<frc::Rotation2d()> desiredRotation,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::initializer_list<Subsystem*> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -102,39 +69,7 @@
frc::SwerveDriveKinematics<NumModules> kinematics,
frc::HolonomicDriveController controller,
std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::initializer_list<Subsystem*> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(std::move(controller)),
- m_outputStates(output) {
- this->AddRequirements(requirements);
-}
-
-template <size_t NumModules>
-SwerveControllerCommand<NumModules>::SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc::HolonomicDriveController controller,
- std::function<frc::Rotation2d()> desiredRotation,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::span<Subsystem* const> requirements)
- : m_trajectory(std::move(trajectory)),
- m_pose(std::move(pose)),
- m_kinematics(kinematics),
- m_controller(std::move(controller)),
- m_desiredRotation(std::move(desiredRotation)),
- m_outputStates(output) {
- this->AddRequirements(requirements);
-}
-
-template <size_t NumModules>
-SwerveControllerCommand<NumModules>::SwerveControllerCommand(
- frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
- frc::SwerveDriveKinematics<NumModules> kinematics,
- frc::HolonomicDriveController controller,
- std::function<void(std::array<frc::SwerveModuleState, NumModules>)> output,
- std::span<Subsystem* const> requirements)
+ Requirements requirements)
: m_trajectory(std::move(trajectory)),
m_pose(std::move(pose)),
m_kinematics(kinematics),
@@ -150,8 +85,7 @@
return m_trajectory.States().back().pose.Rotation();
};
}
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
}
template <size_t NumModules>
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileCommand.h
index 413553b..69cc8d8 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileCommand.h
@@ -5,14 +5,13 @@
#pragma once
#include <functional>
-#include <initializer_list>
-#include <span>
#include <frc/Timer.h>
#include <frc/trajectory/TrapezoidProfile.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/Requirements.h"
namespace frc2 {
/**
@@ -25,7 +24,7 @@
*/
template <class Distance>
class TrapezoidProfileCommand
- : public CommandHelper<CommandBase, TrapezoidProfileCommand<Distance>> {
+ : public CommandHelper<Command, TrapezoidProfileCommand<Distance>> {
using Distance_t = units::unit_t<Distance>;
using Velocity =
units::compound_unit<Distance, units::inverse<units::seconds>>;
@@ -39,13 +38,21 @@
*
* @param profile The motion profile to execute.
* @param output The consumer for the profile output.
+ * @param goal The supplier for the desired state
+ * @param currentState The current state
* @param requirements The list of requirements.
*/
TrapezoidProfileCommand(frc::TrapezoidProfile<Distance> profile,
std::function<void(State)> output,
- std::initializer_list<Subsystem*> requirements)
- : m_profile(profile), m_output(output) {
+ std::function<State()> goal,
+ std::function<State()> currentState,
+ Requirements requirements = {})
+ : m_profile(profile),
+ m_output(output),
+ m_goal(goal),
+ m_currentState(currentState) {
this->AddRequirements(requirements);
+ m_newAPI = true;
}
/**
@@ -55,20 +62,25 @@
* @param profile The motion profile to execute.
* @param output The consumer for the profile output.
* @param requirements The list of requirements.
+ * @deprecated The new constructor allows you to pass in a supplier for
+ * desired and current state. This allows you to change goals at runtime.
*/
+ WPI_DEPRECATED(
+ "The new constructor allows you to pass in a supplier for desired and "
+ "current state. This allows you to change goals at runtime.")
TrapezoidProfileCommand(frc::TrapezoidProfile<Distance> profile,
std::function<void(State)> output,
- std::span<Subsystem* const> requirements = {})
+ Requirements requirements = {})
: m_profile(profile), m_output(output) {
this->AddRequirements(requirements);
+ m_newAPI = false;
}
- void Initialize() override {
- m_timer.Reset();
- m_timer.Start();
- }
+ void Initialize() override { m_timer.Restart(); }
- void Execute() override { m_output(m_profile.Calculate(m_timer.Get())); }
+ void Execute() override {
+ m_output(m_profile.Calculate(m_timer.Get(), m_goal(), m_currentState()));
+ }
void End(bool interrupted) override { m_timer.Stop(); }
@@ -79,7 +91,9 @@
private:
frc::TrapezoidProfile<Distance> m_profile;
std::function<void(State)> m_output;
-
+ std::function<State()> m_goal;
+ std::function<State()> m_currentState;
+ bool m_newAPI; // TODO: Remove
frc::Timer m_timer;
};
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileSubsystem.h b/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileSubsystem.h
index abce33c..344aefc 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileSubsystem.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/TrapezoidProfileSubsystem.h
@@ -39,15 +39,13 @@
explicit TrapezoidProfileSubsystem(Constraints constraints,
Distance_t initialPosition = Distance_t{0},
units::second_t period = 20_ms)
- : m_constraints(constraints),
+ : m_profile(constraints),
m_state{initialPosition, Velocity_t(0)},
m_goal{initialPosition, Velocity_t{0}},
m_period(period) {}
void Periodic() override {
- auto profile =
- frc::TrapezoidProfile<Distance>(m_constraints, m_goal, m_state);
- m_state = profile.Calculate(m_period);
+ m_state = m_profile.Calculate(m_period, m_goal, m_state);
if (m_enabled) {
UseState(m_state);
}
@@ -87,7 +85,7 @@
void Disable() { m_enabled = false; }
private:
- Constraints m_constraints;
+ frc::TrapezoidProfile<Distance> m_profile;
State m_state;
State m_goal;
units::second_t m_period;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/WaitCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/WaitCommand.h
index 54eddfb..e28615e 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/WaitCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/WaitCommand.h
@@ -7,18 +7,16 @@
#include <frc/Timer.h>
#include <units/time.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command that does nothing but takes a specified amount of time to finish.
- * Useful for CommandGroups. Can also be subclassed to make a command with an
- * internal timer.
*
* This class is provided by the NewCommands VendorDep
*/
-class WaitCommand : public CommandHelper<CommandBase, WaitCommand> {
+class WaitCommand : public CommandHelper<Command, WaitCommand> {
public:
/**
* Creates a new WaitCommand. This command will do nothing, and end after the
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/WaitUntilCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/WaitUntilCommand.h
index 3b26999..377a1ba 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/WaitUntilCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/WaitUntilCommand.h
@@ -8,7 +8,7 @@
#include <units/time.h>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -18,7 +18,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class WaitUntilCommand : public CommandHelper<CommandBase, WaitUntilCommand> {
+class WaitUntilCommand : public CommandHelper<Command, WaitUntilCommand> {
public:
/**
* Creates a new WaitUntilCommand that ends after a given condition becomes
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/WrapperCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/WrapperCommand.h
index 71dd02f..98e8b20 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/WrapperCommand.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/WrapperCommand.h
@@ -9,10 +9,11 @@
#pragma warning(disable : 4521)
#endif
+#include <concepts>
#include <memory>
#include <utility>
-#include "frc2/command/CommandBase.h"
+#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
@@ -23,7 +24,7 @@
* <p>Wrapped commands may only be used through the wrapper, trying to directly
* schedule them or add them to a group will throw an exception.
*/
-class WrapperCommand : public CommandHelper<CommandBase, WrapperCommand> {
+class WrapperCommand : public CommandHelper<Command, WrapperCommand> {
public:
/**
* Wrap a command.
@@ -39,11 +40,11 @@
* @param command the command being wrapped. Trying to directly schedule this
* command or add it to a group will throw an exception.
*/
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
+ template <std::derived_from<Command> T>
+ // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit WrapperCommand(T&& command)
- : WrapperCommand(std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))) {}
+ : WrapperCommand(
+ std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
WrapperCommand(WrapperCommand&& other) = default;
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h
deleted file mode 100644
index 0142c44..0000000
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h
+++ /dev/null
@@ -1,274 +0,0 @@
-// 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 <functional>
-#include <initializer_list>
-#include <span>
-#include <utility>
-
-#include <wpi/deprecated.h>
-
-#include "Trigger.h"
-#include "frc2/command/CommandPtr.h"
-
-namespace frc2 {
-class Command;
-/**
- * A class used to bind command scheduling to button presses. Can be composed
- * with other buttons with the operators in Trigger.
- *
- * This class is provided by the NewCommands VendorDep
- *
- * @see Trigger
- */
-class Button : public Trigger {
- public:
- /**
- * Create a new button that is pressed when the given condition is true.
- *
- * @param isPressed Whether the button is pressed.
- * @deprecated Replace with Trigger
- */
- WPI_DEPRECATED("Replace with Trigger")
- explicit Button(std::function<bool()> isPressed);
-
- /**
- * Create a new button that is pressed active (default constructor) - activity
- * can be further determined by subclass code.
- * @deprecated Replace with Trigger
- */
- WPI_DEPRECATED("Replace with Trigger")
- Button() = default;
-
- /**
- * Binds a command to start when the button is pressed. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Replace with Trigger::OnTrue()
- */
- WPI_DEPRECATED("Replace with Trigger#OnTrue()")
- Button WhenPressed(Command* command);
-
- /**
- * Binds a command to start when the button is pressed. Transfers
- * command ownership to the button scheduler, so the user does not have to
- * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be
- * *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Replace with Trigger::OnTrue()
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Replace with Trigger#OnTrue()")
- Button WhenPressed(T&& command) {
- WhenActive(std::forward<T>(command));
- return *this;
- }
-
- /**
- * Binds a runnable to execute when the button is pressed.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::OnTrue(cmd::RunOnce())
- */
- WPI_DEPRECATED("Replace with Trigger#OnTrue(cmd::RunOnce())")
- Button WhenPressed(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute when the button is pressed.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::OnTrue(cmd::RunOnce())
- */
- WPI_DEPRECATED("Replace with Trigger#OnTrue(cmd::RunOnce())")
- Button WhenPressed(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to be started repeatedly while the button is pressed, and
- * canceled when it is released. Takes a raw pointer, and so is non-owning;
- * users are responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::WhileTrue(command.Repeatedly())
- */
- WPI_DEPRECATED("Replace with Trigger#WhileTrue(command.Repeatedly())")
- Button WhileHeld(Command* command);
-
- /**
- * Binds a command to be started repeatedly while the button is pressed, and
- * canceled when it is released. Transfers command ownership to the button
- * scheduler, so the user does not have to worry about lifespan - rvalue refs
- * will be *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::WhileTrue(command.Repeatedly())
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Replace with Trigger#WhileTrue(command.Repeatedly())")
- Button WhileHeld(T&& command) {
- WhileActiveContinous(std::forward<T>(command));
- return *this;
- }
-
- /**
- * Binds a runnable to execute repeatedly while the button is pressed.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::WhileTrue(cmd::Run())
- */
- WPI_DEPRECATED("Replace with Trigger#WhileTrue(cmd::Run())")
- Button WhileHeld(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute repeatedly while the button is pressed.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::WhileTrue(cmd::Run())
- */
- WPI_DEPRECATED("Replace with Trigger#WhileTrue(cmd::Run())")
- Button WhileHeld(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to be started when the button is pressed, and canceled
- * when it is released. Takes a raw pointer, and so is non-owning; users are
- * responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::WhileTrue()
- */
- WPI_DEPRECATED("Replace with Trigger#WhileTrue()")
- Button WhenHeld(Command* command);
-
- /**
- * Binds a command to be started when the button is pressed, and canceled
- * when it is released. Transfers command ownership to the button scheduler,
- * so the user does not have to worry about lifespan - rvalue refs will be
- * *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::WhileTrue()
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Replace with Trigger#WhileTrue()")
- Button WhenHeld(T&& command) {
- WhileActiveOnce(std::forward<T>(command));
- return *this;
- }
-
- /**
- * Binds a command to start when the button is released. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * of the command.
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::OnFalse()
- */
- WPI_DEPRECATED("Replace with Trigger#OnFalse()")
- Button WhenReleased(Command* command);
-
- /**
- * Binds a command to start when the button is pressed. Transfers
- * command ownership to the button scheduler, so the user does not have to
- * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be
- * *copied.*
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::OnFalse()
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Replace with Trigger#OnFalse()")
- Button WhenReleased(T&& command) {
- WhenInactive(std::forward<T>(command));
- return *this;
- }
-
- /**
- * Binds a runnable to execute when the button is released.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::OnFalse(cmd::RunOnce())
- */
- WPI_DEPRECATED("Replace with Trigger#OnFalse(cmd::RunOnce())")
- Button WhenReleased(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute when the button is released.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Replace with Trigger::OnFalse(cmd::RunOnce())
- */
- WPI_DEPRECATED("Replace with Trigger#OnFalse(cmd::RunOnce())")
- Button WhenReleased(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to start when the button is pressed, and be canceled when
- * it is pressed again. Takes a raw pointer, and so is non-owning; users are
- * responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::ToggleOnTrue()
- */
- WPI_DEPRECATED("Replace with Trigger#ToggleOnTrue()")
- Button ToggleWhenPressed(Command* command);
-
- /**
- * Binds a command to start when the button is pressed, and be canceled when
- * it is pressed again. Transfers command ownership to the button scheduler,
- * so the user does not have to worry about lifespan - rvalue refs will be
- * *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Replace with Trigger::ToggleOnTrue()
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Replace with Trigger#ToggleOnTrue()")
- Button ToggleWhenPressed(T&& command) {
- ToggleWhenActive(std::forward<T>(command));
- return *this;
- }
-
- /**
- * Binds a command to be canceled when the button is pressed. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * and scheduling of the command.
- *
- * @param command The command to bind.
- * @return The button, for chained calls.
- * @deprecated Pass this as a command end condition with Until() instead.
- */
- WPI_DEPRECATED("Pass this as a command end condition with Until() instead.")
- Button CancelWhenPressed(Command* command);
-};
-} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandJoystick.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandJoystick.h
index c335f89..5b51e86 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandJoystick.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandJoystick.h
@@ -10,7 +10,7 @@
namespace frc2 {
/**
- * A subclass of {@link Joystick} with {@link Trigger} factories for
+ * A version of {@link Joystick} with {@link Trigger} factories for
* command-based.
*
* @see Joystick
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS4Controller.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS4Controller.h
index befb667..22c54ad 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS4Controller.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS4Controller.h
@@ -10,7 +10,7 @@
namespace frc2 {
/**
- * A subclass of {@link PS4Controller} with {@link Trigger} factories for
+ * A version of {@link PS4Controller} with {@link Trigger} factories for
* command-based.
*
* @see PS4Controller
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS5Controller.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS5Controller.h
new file mode 100644
index 0000000..d86d383
--- /dev/null
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandPS5Controller.h
@@ -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
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandXboxController.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandXboxController.h
index 337ec2f..94a3c2c 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandXboxController.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/CommandXboxController.h
@@ -10,7 +10,7 @@
namespace frc2 {
/**
- * A subclass of {@link XboxController} with {@link Trigger} factories for
+ * A version of {@link XboxController} with {@link Trigger} factories for
* command-based.
*
* @see XboxController
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/JoystickButton.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/JoystickButton.h
index b5280c0..a0d04e7 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/JoystickButton.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/JoystickButton.h
@@ -4,9 +4,8 @@
#pragma once
#include <frc/GenericHID.h>
-#include <wpi/deprecated.h>
-#include "Button.h"
+#include "Trigger.h"
namespace frc2 {
/**
@@ -17,7 +16,7 @@
*
* @see Trigger
*/
-class JoystickButton : public Button {
+class JoystickButton : public Trigger {
public:
/**
* Creates a JoystickButton that commands can be bound to.
@@ -25,11 +24,9 @@
* @param joystick The joystick on which the button is located.
* @param buttonNumber The number of the button on the joystick.
*/
- WPI_IGNORE_DEPRECATED
explicit JoystickButton(frc::GenericHID* joystick, int buttonNumber)
- : Button([joystick, buttonNumber] {
+ : Trigger([joystick, buttonNumber] {
return joystick->GetRawButton(buttonNumber);
}) {}
- WPI_UNIGNORE_DEPRECATED
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/NetworkButton.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/NetworkButton.h
index 3d0378d..673821e 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/NetworkButton.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/NetworkButton.h
@@ -11,7 +11,7 @@
#include <networktables/NetworkTable.h>
#include <networktables/NetworkTableInstance.h>
-#include "Button.h"
+#include "Trigger.h"
namespace frc2 {
/**
@@ -19,7 +19,7 @@
*
* This class is provided by the NewCommands VendorDep
*/
-class NetworkButton : public Button {
+class NetworkButton : public Trigger {
public:
/**
* Creates a NetworkButton that commands can be bound to.
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/POVButton.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/POVButton.h
index 7ee1590..00723be 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/POVButton.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/POVButton.h
@@ -3,10 +3,10 @@
// the WPILib BSD license file in the root directory of this project.
#pragma once
-#include <frc/GenericHID.h>
-#include <wpi/deprecated.h>
-#include "Button.h"
+#include <frc/GenericHID.h>
+
+#include "Trigger.h"
namespace frc2 {
/**
@@ -17,7 +17,7 @@
*
* @see Trigger
*/
-class POVButton : public Button {
+class POVButton : public Trigger {
public:
/**
* Creates a POVButton that commands can be bound to.
@@ -26,11 +26,9 @@
* @param angle The angle of the POV corresponding to a button press.
* @param povNumber The number of the POV on the joystick.
*/
- WPI_IGNORE_DEPRECATED
POVButton(frc::GenericHID* joystick, int angle, int povNumber = 0)
- : Button([joystick, angle, povNumber] {
+ : Trigger([joystick, angle, povNumber] {
return joystick->GetPOV(povNumber) == angle;
}) {}
- WPI_UNIGNORE_DEPRECATED
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
index c3a5e86..533e0a6 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
@@ -4,17 +4,15 @@
#pragma once
+#include <concepts>
#include <functional>
-#include <initializer_list>
#include <memory>
-#include <span>
#include <utility>
#include <frc/event/BooleanEvent.h>
#include <frc/event/EventLoop.h>
#include <frc/filter/Debouncer.h>
#include <units/time.h>
-#include <wpi/deprecated.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandScheduler.h"
@@ -194,8 +192,7 @@
Trigger ToggleOnFalse(Command* command);
/**
- * Toggles a command when the condition changes from `true` to the low
- * state.
+ * Toggles a command when the condition changes from `true` to `false`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
@@ -206,308 +203,6 @@
Trigger ToggleOnFalse(CommandPtr&& command);
/**
- * Binds a command to start when the trigger becomes active. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use OnTrue(Command) instead
- */
- WPI_DEPRECATED("Use OnTrue(Command) instead")
- Trigger WhenActive(Command* command);
-
- /**
- * Binds a command to start when the trigger becomes active. Transfers
- * command ownership to the button scheduler, so the user does not have to
- * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be
- * *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use OnTrue(Command) instead
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Use OnTrue(Command) instead")
- Trigger WhenActive(T&& command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- command->Schedule();
- }
-
- previous = current;
- });
- return *this;
- }
-
- /**
- * Binds a runnable to execute when the trigger becomes active.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use OnTrue(Command) instead and construct the InstantCommand
- * manually
- */
- WPI_DEPRECATED(
- "Use OnTrue(Command) instead and construct the InstantCommand manually")
- Trigger WhenActive(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute when the trigger becomes active.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use OnTrue(Command) instead and construct the InstantCommand
- * manually
- */
- WPI_DEPRECATED(
- "Use OnTrue(Command) instead and construct the InstantCommand manually")
- Trigger WhenActive(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to be started repeatedly while the trigger is active, and
- * canceled when it becomes inactive. Takes a raw pointer, and so is
- * non-owning; users are responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use WhileTrue(Command) with RepeatCommand, or bind
- command::Schedule with IfHigh(std::function<void()>).
- */
- WPI_DEPRECATED(
- "Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
- "with IfHigh(std::function<void()>).")
- Trigger WhileActiveContinous(Command* command);
-
- /**
- * Binds a command to be started repeatedly while the trigger is active, and
- * canceled when it becomes inactive. Transfers command ownership to the
- * button scheduler, so the user does not have to worry about lifespan -
- * rvalue refs will be *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use WhileTrue(Command) with RepeatCommand, or bind
- command::Schedule with IfHigh(std::function<void()>).
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED(
- "Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
- "with IfHigh(std::function<void()>).")
- Trigger WhileActiveContinous(T&& command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))]() mutable {
- bool current = condition();
-
- if (current) {
- command->Schedule();
- } else if (previous && !current) {
- command->Cancel();
- }
-
- previous = current;
- });
-
- return *this;
- }
-
- /**
- * Binds a runnable to execute repeatedly while the trigger is active.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use WhileTrue(Command) and construct a RunCommand manually
- */
- WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually")
- Trigger WhileActiveContinous(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute repeatedly while the trigger is active.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use WhileTrue(Command) and construct a RunCommand manually
- */
- WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually")
- Trigger WhileActiveContinous(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to be started when the trigger becomes active, and
- * canceled when it becomes inactive. Takes a raw pointer, and so is
- * non-owning; users are responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use WhileTrue(Command) instead.
- */
- WPI_DEPRECATED("Use WhileTrue(Command) instead.")
- Trigger WhileActiveOnce(Command* command);
-
- /**
- * Binds a command to be started when the trigger becomes active, and
- * canceled when it becomes inactive. Transfers command ownership to the
- * button scheduler, so the user does not have to worry about lifespan -
- * rvalue refs will be *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use WhileTrue(Command) instead.
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Use WhileTrue(Command) instead.")
- Trigger WhileActiveOnce(T&& command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- command->Schedule();
- } else if (previous && !current) {
- command->Cancel();
- }
-
- previous = current;
- });
- return *this;
- }
-
- /**
- * Binds a command to start when the trigger becomes inactive. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use OnFalse(Command) instead.
- */
- WPI_DEPRECATED("Use OnFalse(Command) instead.")
- Trigger WhenInactive(Command* command);
-
- /**
- * Binds a command to start when the trigger becomes inactive. Transfers
- * command ownership to the button scheduler, so the user does not have to
- * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be
- * *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use OnFalse(Command) instead.
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Use OnFalse(Command) instead.")
- Trigger WhenInactive(T&& command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))]() mutable {
- bool current = condition();
-
- if (previous && !current) {
- command->Schedule();
- }
-
- previous = current;
- });
- return *this;
- }
-
- /**
- * Binds a runnable to execute when the trigger becomes inactive.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use OnFalse(Command) instead and construct the InstantCommand
- * manually
- */
- WPI_DEPRECATED(
- "Use OnFalse(Command) instead and construct the InstantCommand manually")
- Trigger WhenInactive(std::function<void()> toRun,
- std::initializer_list<Subsystem*> requirements);
-
- /**
- * Binds a runnable to execute when the trigger becomes inactive.
- *
- * @param toRun the runnable to execute.
- * @param requirements the required subsystems.
- * @deprecated Use OnFalse(Command) instead and construct the InstantCommand
- * manually
- */
- WPI_DEPRECATED(
- "Use OnFalse(Command) instead and construct the InstantCommand manually")
- Trigger WhenInactive(std::function<void()> toRun,
- std::span<Subsystem* const> requirements = {});
-
- /**
- * Binds a command to start when the trigger becomes active, and be canceled
- * when it again becomes active. Takes a raw pointer, and so is non-owning;
- * users are responsible for the lifespan of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use ToggleOnTrue(Command) instead.
- */
- WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
- Trigger ToggleWhenActive(Command* command);
-
- /**
- * Binds a command to start when the trigger becomes active, and be canceled
- * when it again becomes active. Transfers command ownership to the button
- * scheduler, so the user does not have to worry about lifespan - rvalue refs
- * will be *moved*, lvalue refs will be *copied.*
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Use ToggleOnTrue(Command) instead.
- */
- template <class T, typename = std::enable_if_t<std::is_base_of_v<
- Command, std::remove_reference_t<T>>>>
- WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
- Trigger ToggleWhenActive(T&& command) {
- m_loop->Bind([condition = m_condition, previous = m_condition(),
- command = std::make_unique<std::remove_reference_t<T>>(
- std::forward<T>(command))]() mutable {
- bool current = condition();
-
- if (!previous && current) {
- if (command->IsScheduled()) {
- command->Cancel();
- } else {
- command->Schedule();
- }
- }
-
- previous = current;
- });
-
- return *this;
- }
-
- /**
- * Binds a command to be canceled when the trigger becomes active. Takes a
- * raw pointer, and so is non-owning; users are responsible for the lifespan
- * and scheduling of the command.
- *
- * @param command The command to bind.
- * @return The trigger, for chained calls.
- * @deprecated Pass this as a command end condition with Until() instead.
- */
- WPI_DEPRECATED("Pass this as a command end condition with Until() instead.")
- Trigger CancelWhenActive(Command* command);
-
- /**
* Composes two triggers with logical AND.
*
* @return A trigger which is active when both component triggers are active.
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandDecoratorTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandDecoratorTest.java
index 392c23c..0f66acd 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandDecoratorTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandDecoratorTest.java
@@ -58,6 +58,22 @@
}
@Test
+ void onlyWhileTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicBoolean condition = new AtomicBoolean(true);
+
+ Command command = new WaitCommand(10).onlyWhile(condition::get);
+
+ scheduler.schedule(command);
+ scheduler.run();
+ assertTrue(scheduler.isScheduled(command));
+ condition.set(false);
+ scheduler.run();
+ assertFalse(scheduler.isScheduled(command));
+ }
+ }
+
+ @Test
void ignoringDisableTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
var command = new RunCommand(() -> {}).ignoringDisable(true);
@@ -184,23 +200,6 @@
}
}
- @SuppressWarnings("removal") // Command.perpetually()
- @Test
- void perpetuallyTest() {
- try (CommandScheduler scheduler = new CommandScheduler()) {
- Command command = new InstantCommand();
-
- Command perpetual = command.perpetually();
-
- scheduler.schedule(perpetual);
- scheduler.run();
- scheduler.run();
- scheduler.run();
-
- assertTrue(scheduler.isScheduled(perpetual));
- }
- }
-
@Test
void unlessTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -222,6 +221,26 @@
}
@Test
+ void onlyIfTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicBoolean onlyIfCondition = new AtomicBoolean(false);
+ AtomicBoolean hasRunCondition = new AtomicBoolean(false);
+
+ Command command =
+ new InstantCommand(() -> hasRunCondition.set(true)).onlyIf(onlyIfCondition::get);
+
+ scheduler.schedule(command);
+ scheduler.run();
+ assertFalse(hasRunCondition.get());
+
+ onlyIfCondition.set(true);
+ scheduler.schedule(command);
+ scheduler.run();
+ assertTrue(hasRunCondition.get());
+ }
+ }
+
+ @Test
void finallyDoTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
AtomicInteger first = new AtomicInteger(0);
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandScheduleTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandScheduleTest.java
index c0295f5..793ad95 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandScheduleTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandScheduleTest.java
@@ -11,6 +11,8 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import org.junit.jupiter.api.Test;
class CommandScheduleTest extends CommandTestBase {
@@ -116,4 +118,27 @@
assertDoesNotThrow(() -> scheduler.cancel(mockCommand));
}
}
+
+ @Test
+ void smartDashboardCancelTest() {
+ try (CommandScheduler scheduler = new CommandScheduler();
+ var inst = NetworkTableInstance.create()) {
+ SmartDashboard.setNetworkTableInstance(inst);
+ SmartDashboard.putData("Scheduler", scheduler);
+ SmartDashboard.updateValues();
+
+ MockCommandHolder holder = new MockCommandHolder(true);
+ Command mockCommand = holder.getMock();
+ scheduler.schedule(mockCommand);
+ scheduler.run();
+ SmartDashboard.updateValues();
+ assertTrue(scheduler.isScheduled(mockCommand));
+
+ var table = inst.getTable("SmartDashboard");
+ table.getEntry("Scheduler/Cancel").setIntegerArray(new long[] {mockCommand.hashCode()});
+ SmartDashboard.updateValues();
+ scheduler.run();
+ assertFalse(scheduler.isScheduled(mockCommand));
+ }
+ }
}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandSendableButtonTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandSendableButtonTest.java
new file mode 100644
index 0000000..c89ed7f
--- /dev/null
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandSendableButtonTest.java
@@ -0,0 +1,114 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj2.command;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.networktables.BooleanPublisher;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class CommandSendableButtonTest extends CommandTestBase {
+ private NetworkTableInstance m_inst;
+ private AtomicInteger m_schedule;
+ private AtomicInteger m_cancel;
+ private BooleanPublisher m_publish;
+ private Command m_command;
+
+ @BeforeEach
+ void setUp() {
+ m_inst = NetworkTableInstance.create();
+ SmartDashboard.setNetworkTableInstance(m_inst);
+ m_schedule = new AtomicInteger();
+ m_cancel = new AtomicInteger();
+ m_command = Commands.startEnd(m_schedule::incrementAndGet, m_cancel::incrementAndGet);
+ m_publish = m_inst.getBooleanTopic("/SmartDashboard/command/running").publish();
+ SmartDashboard.putData("command", m_command);
+ SmartDashboard.updateValues();
+ }
+
+ @Test
+ void trueAndNotScheduledSchedules() {
+ // Not scheduled and true -> scheduled
+ CommandScheduler.getInstance().run();
+ SmartDashboard.updateValues();
+ assertFalse(m_command.isScheduled());
+ assertEquals(0, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+
+ m_publish.set(true);
+ SmartDashboard.updateValues();
+ CommandScheduler.getInstance().run();
+ assertTrue(m_command.isScheduled());
+ assertEquals(1, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+ }
+
+ @Test
+ void trueAndScheduledNoOp() {
+ // Scheduled and true -> no-op
+ m_command.schedule();
+ CommandScheduler.getInstance().run();
+ SmartDashboard.updateValues();
+ assertTrue(m_command.isScheduled());
+ assertEquals(1, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+
+ m_publish.set(true);
+ SmartDashboard.updateValues();
+ CommandScheduler.getInstance().run();
+ assertTrue(m_command.isScheduled());
+ assertEquals(1, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+ }
+
+ @Test
+ void falseAndNotScheduledNoOp() {
+ // Not scheduled and false -> no-op
+ CommandScheduler.getInstance().run();
+ SmartDashboard.updateValues();
+ assertFalse(m_command.isScheduled());
+ assertEquals(0, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+
+ m_publish.set(false);
+ SmartDashboard.updateValues();
+ CommandScheduler.getInstance().run();
+ assertFalse(m_command.isScheduled());
+ assertEquals(0, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+ }
+
+ @Test
+ void falseAndScheduledCancel() {
+ // Scheduled and false -> cancel
+ m_command.schedule();
+ CommandScheduler.getInstance().run();
+ SmartDashboard.updateValues();
+ assertTrue(m_command.isScheduled());
+ assertEquals(1, m_schedule.get());
+ assertEquals(0, m_cancel.get());
+
+ m_publish.set(false);
+ SmartDashboard.updateValues();
+ CommandScheduler.getInstance().run();
+ assertFalse(m_command.isScheduled());
+ assertEquals(1, m_schedule.get());
+ assertEquals(1, m_cancel.get());
+ }
+
+ @AfterEach
+ void tearDown() {
+ m_publish.close();
+ m_inst.close();
+ SmartDashboard.setNetworkTableInstance(NetworkTableInstance.getDefault());
+ }
+}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandTestBase.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandTestBase.java
index 1d46fb5..13f6597 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandTestBase.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/CommandTestBase.java
@@ -23,6 +23,7 @@
CommandScheduler.getInstance().enable();
CommandScheduler.getInstance().getActiveButtonLoop().clear();
CommandScheduler.getInstance().clearComposedCommands();
+ CommandScheduler.getInstance().unregisterAllSubsystems();
setDSEnabled(true);
}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/ConditionalCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/ConditionalCommandTest.java
index 420a8a7..4659f0e 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/ConditionalCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/ConditionalCommandTest.java
@@ -4,11 +4,19 @@
package edu.wpi.first.wpilibj2.command;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import edu.wpi.first.wpilibj2.command.Command.InterruptionBehavior;
+import java.util.function.BooleanSupplier;
+import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
class ConditionalCommandTest extends CommandTestBase {
@Test
@@ -60,4 +68,92 @@
verify(command2, never()).end(true);
}
}
+
+ static Stream<Arguments> interruptible() {
+ return Stream.of(
+ arguments(
+ "AllCancelSelf",
+ InterruptionBehavior.kCancelSelf,
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelSelf),
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelSelf),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "AllCancelIncoming",
+ InterruptionBehavior.kCancelIncoming,
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "OneCancelSelfOneIncoming",
+ InterruptionBehavior.kCancelSelf,
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelSelf),
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "OneCancelIncomingOneSelf",
+ InterruptionBehavior.kCancelSelf,
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
+ new WaitUntilCommand(() -> false)
+ .withInterruptBehavior(InterruptionBehavior.kCancelSelf),
+ (BooleanSupplier) () -> true));
+ }
+
+ @MethodSource
+ @ParameterizedTest(name = "interruptible[{index}]: {0}")
+ void interruptible(
+ @SuppressWarnings("unused") String name,
+ InterruptionBehavior expected,
+ Command command1,
+ Command command2,
+ BooleanSupplier selector) {
+ var command = Commands.either(command1, command2, selector);
+ assertEquals(expected, command.getInterruptionBehavior());
+ }
+
+ static Stream<Arguments> runsWhenDisabled() {
+ return Stream.of(
+ arguments(
+ "AllFalse",
+ false,
+ new WaitUntilCommand(() -> false).ignoringDisable(false),
+ new WaitUntilCommand(() -> false).ignoringDisable(false),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "AllTrue",
+ true,
+ new WaitUntilCommand(() -> false).ignoringDisable(true),
+ new WaitUntilCommand(() -> false).ignoringDisable(true),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "OneTrueOneFalse",
+ false,
+ new WaitUntilCommand(() -> false).ignoringDisable(true),
+ new WaitUntilCommand(() -> false).ignoringDisable(false),
+ (BooleanSupplier) () -> true),
+ arguments(
+ "OneFalseOneTrue",
+ false,
+ new WaitUntilCommand(() -> false).ignoringDisable(false),
+ new WaitUntilCommand(() -> false).ignoringDisable(true),
+ (BooleanSupplier) () -> true));
+ }
+
+ @MethodSource
+ @ParameterizedTest(name = "runsWhenDisabled[{index}]: {0}")
+ void runsWhenDisabled(
+ @SuppressWarnings("unused") String name,
+ boolean expected,
+ Command command1,
+ Command command2,
+ BooleanSupplier selector) {
+ var command = Commands.either(command1, command2, selector);
+ assertEquals(expected, command.runsWhenDisabled());
+ }
}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/DeferredCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/DeferredCommandTest.java
new file mode 100644
index 0000000..259ba0f
--- /dev/null
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/DeferredCommandTest.java
@@ -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);
+ });
+ }
+}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommandTest.java
index b8ccea5..3ca1101 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/MecanumControllerCommandTest.java
@@ -118,8 +118,7 @@
this::setWheelSpeeds,
subsystem);
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
command.initialize();
while (!command.isFinished()) {
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/PerpetualCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/PerpetualCommandTest.java
deleted file mode 100644
index 6b9690b..0000000
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/PerpetualCommandTest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-class PerpetualCommandTest extends CommandTestBase {
- @SuppressWarnings("removal") // PerpetualCommand
- @Test
- void perpetualCommandScheduleTest() {
- try (CommandScheduler scheduler = new CommandScheduler()) {
- PerpetualCommand command = new PerpetualCommand(new InstantCommand());
-
- scheduler.schedule(command);
- scheduler.run();
-
- assertTrue(scheduler.isScheduled(command));
- }
- }
-}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RepeatCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RepeatCommandTest.java
index f082ddb..53abdd8 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RepeatCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RepeatCommandTest.java
@@ -14,54 +14,69 @@
implements SingleCompositionTestBase<RepeatCommand> {
@Test
void callsMethodsCorrectly() {
- var initCounter = new AtomicInteger(0);
- var exeCounter = new AtomicInteger(0);
- var isFinishedCounter = new AtomicInteger(0);
- var endCounter = new AtomicInteger(0);
- var isFinishedHook = new AtomicBoolean(false);
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ var initCounter = new AtomicInteger(0);
+ var exeCounter = new AtomicInteger(0);
+ var isFinishedCounter = new AtomicInteger(0);
+ var endCounter = new AtomicInteger(0);
+ var isFinishedHook = new AtomicBoolean(false);
- final var command =
- new FunctionalCommand(
- initCounter::incrementAndGet,
- exeCounter::incrementAndGet,
- interrupted -> endCounter.incrementAndGet(),
- () -> {
- isFinishedCounter.incrementAndGet();
- return isFinishedHook.get();
- })
- .repeatedly();
+ final var command =
+ new FunctionalCommand(
+ initCounter::incrementAndGet,
+ exeCounter::incrementAndGet,
+ interrupted -> endCounter.incrementAndGet(),
+ () -> {
+ isFinishedCounter.incrementAndGet();
+ return isFinishedHook.get();
+ })
+ .repeatedly();
- assertEquals(0, initCounter.get());
- assertEquals(0, exeCounter.get());
- assertEquals(0, isFinishedCounter.get());
- assertEquals(0, endCounter.get());
+ assertEquals(0, initCounter.get());
+ assertEquals(0, exeCounter.get());
+ assertEquals(0, isFinishedCounter.get());
+ assertEquals(0, endCounter.get());
- CommandScheduler.getInstance().schedule(command);
- assertEquals(1, initCounter.get());
- assertEquals(0, exeCounter.get());
- assertEquals(0, isFinishedCounter.get());
- assertEquals(0, endCounter.get());
+ scheduler.schedule(command);
+ assertEquals(1, initCounter.get());
+ assertEquals(0, exeCounter.get());
+ assertEquals(0, isFinishedCounter.get());
+ assertEquals(0, endCounter.get());
- isFinishedHook.set(false);
- CommandScheduler.getInstance().run();
- assertEquals(1, initCounter.get());
- assertEquals(1, exeCounter.get());
- assertEquals(1, isFinishedCounter.get());
- assertEquals(0, endCounter.get());
+ isFinishedHook.set(false);
+ scheduler.run();
+ assertEquals(1, initCounter.get());
+ assertEquals(1, exeCounter.get());
+ assertEquals(1, isFinishedCounter.get());
+ assertEquals(0, endCounter.get());
- isFinishedHook.set(true);
- CommandScheduler.getInstance().run();
- assertEquals(1, initCounter.get());
- assertEquals(2, exeCounter.get());
- assertEquals(2, isFinishedCounter.get());
- assertEquals(1, endCounter.get());
+ isFinishedHook.set(true);
+ scheduler.run();
+ assertEquals(1, initCounter.get());
+ assertEquals(2, exeCounter.get());
+ assertEquals(2, isFinishedCounter.get());
+ assertEquals(1, endCounter.get());
- isFinishedHook.set(false);
- CommandScheduler.getInstance().run();
- assertEquals(2, initCounter.get());
- assertEquals(3, exeCounter.get());
- assertEquals(3, isFinishedCounter.get());
- assertEquals(1, endCounter.get());
+ isFinishedHook.set(false);
+ scheduler.run();
+ assertEquals(2, initCounter.get());
+ assertEquals(3, exeCounter.get());
+ assertEquals(3, isFinishedCounter.get());
+ assertEquals(1, endCounter.get());
+
+ isFinishedHook.set(true);
+ scheduler.run();
+ assertEquals(2, initCounter.get());
+ assertEquals(4, exeCounter.get());
+ assertEquals(4, isFinishedCounter.get());
+ assertEquals(2, endCounter.get());
+
+ scheduler.cancel(command);
+ assertEquals(2, initCounter.get());
+ assertEquals(4, exeCounter.get());
+ assertEquals(4, isFinishedCounter.get());
+ assertEquals(2, endCounter.get());
+ }
}
@Override
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RobotDisabledCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RobotDisabledCommandTest.java
index 0914c25..a248810 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RobotDisabledCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/RobotDisabledCommandTest.java
@@ -141,8 +141,8 @@
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);
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulerTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulerTest.java
index 7a62f5e..1e0b333 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulerTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulerTest.java
@@ -6,6 +6,9 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
@@ -44,12 +47,110 @@
}
@Test
+ void schedulerInterruptNoCauseLambdaTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+
+ scheduler.onCommandInterrupt(
+ (interrupted, cause) -> {
+ assertFalse(cause.isPresent());
+ counter.incrementAndGet();
+ });
+
+ Command command = Commands.run(() -> {});
+
+ scheduler.schedule(command);
+ scheduler.cancel(command);
+
+ assertEquals(1, counter.get());
+ }
+ }
+
+ @Test
+ void schedulerInterruptCauseLambdaTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+
+ Subsystem subsystem = new Subsystem() {};
+ Command command = subsystem.run(() -> {});
+ Command interruptor = subsystem.runOnce(() -> {});
+
+ scheduler.onCommandInterrupt(
+ (interrupted, cause) -> {
+ assertTrue(cause.isPresent());
+ assertSame(interruptor, cause.get());
+ counter.incrementAndGet();
+ });
+
+ scheduler.schedule(command);
+ scheduler.schedule(interruptor);
+
+ assertEquals(1, counter.get());
+ }
+ }
+
+ @Test
+ void schedulerInterruptCauseLambdaInRunLoopTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+
+ Subsystem subsystem = new Subsystem() {};
+ Command command = subsystem.run(() -> {});
+ Command interruptor = subsystem.runOnce(() -> {});
+ // This command will schedule interruptor in execute() inside the run loop
+ Command interruptorScheduler = Commands.runOnce(() -> scheduler.schedule(interruptor));
+
+ scheduler.onCommandInterrupt(
+ (interrupted, cause) -> {
+ assertTrue(cause.isPresent());
+ assertSame(interruptor, cause.get());
+ counter.incrementAndGet();
+ });
+
+ scheduler.schedule(command);
+ scheduler.schedule(interruptorScheduler);
+
+ scheduler.run();
+
+ assertEquals(1, counter.get());
+ }
+ }
+
+ @Test
+ void registerSubsystemTest() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger(0);
+ Subsystem system =
+ new SubsystemBase() {
+ @Override
+ public void periodic() {
+ counter.incrementAndGet();
+ }
+ };
+
+ assertDoesNotThrow(() -> scheduler.registerSubsystem(system));
+
+ scheduler.run();
+ assertEquals(1, counter.get());
+ }
+ }
+
+ @Test
void unregisterSubsystemTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
- Subsystem system = new SubsystemBase() {};
-
+ AtomicInteger counter = new AtomicInteger(0);
+ Subsystem system =
+ new SubsystemBase() {
+ @Override
+ public void periodic() {
+ counter.incrementAndGet();
+ }
+ };
scheduler.registerSubsystem(system);
assertDoesNotThrow(() -> scheduler.unregisterSubsystem(system));
+
+ scheduler.run();
+ assertEquals(0, counter.get());
}
}
@@ -59,6 +160,7 @@
AtomicInteger counter = new AtomicInteger();
scheduler.onCommandInterrupt(command -> counter.incrementAndGet());
+ scheduler.onCommandInterrupt((command, interruptor) -> assertFalse(interruptor.isPresent()));
Command command = new WaitCommand(10);
Command command2 = new WaitCommand(10);
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulingRecursionTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulingRecursionTest.java
index 28e9e6f..5e8fd39 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulingRecursionTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SchedulingRecursionTest.java
@@ -25,9 +25,10 @@
void cancelFromInitialize(InterruptionBehavior interruptionBehavior) {
try (CommandScheduler scheduler = new CommandScheduler()) {
AtomicBoolean hasOtherRun = new AtomicBoolean();
+ AtomicInteger counter = new AtomicInteger();
Subsystem requirement = new SubsystemBase() {};
Command selfCancels =
- new CommandBase() {
+ new Command() {
{
addRequirements(requirement);
}
@@ -38,6 +39,11 @@
}
@Override
+ public void end(boolean interrupted) {
+ counter.incrementAndGet();
+ }
+
+ @Override
public InterruptionBehavior getInterruptionBehavior() {
return interruptionBehavior;
}
@@ -52,6 +58,47 @@
});
assertFalse(scheduler.isScheduled(selfCancels));
assertTrue(scheduler.isScheduled(other));
+ assertEquals(1, counter.get());
+ scheduler.run();
+ assertTrue(hasOtherRun.get());
+ }
+ }
+
+ @EnumSource(InterruptionBehavior.class)
+ @ParameterizedTest
+ void cancelFromInitializeAction(InterruptionBehavior interruptionBehavior) {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicBoolean hasOtherRun = new AtomicBoolean();
+ AtomicInteger counter = new AtomicInteger();
+ Subsystem requirement = new Subsystem() {};
+ Command selfCancels =
+ new Command() {
+ {
+ addRequirements(requirement);
+ }
+
+ @Override
+ public void end(boolean interrupted) {
+ counter.incrementAndGet();
+ }
+
+ @Override
+ public InterruptionBehavior getInterruptionBehavior() {
+ return interruptionBehavior;
+ }
+ };
+ Command other = new RunCommand(() -> hasOtherRun.set(true), requirement);
+
+ assertDoesNotThrow(
+ () -> {
+ scheduler.onCommandInitialize(cmd -> scheduler.cancel(selfCancels));
+ scheduler.schedule(selfCancels);
+ scheduler.run();
+ scheduler.schedule(other);
+ });
+ assertFalse(scheduler.isScheduled(selfCancels));
+ assertTrue(scheduler.isScheduled(other));
+ assertEquals(1, counter.get());
scheduler.run();
assertTrue(hasOtherRun.get());
}
@@ -62,9 +109,10 @@
void defaultCommandGetsRescheduledAfterSelfCanceling(InterruptionBehavior interruptionBehavior) {
try (CommandScheduler scheduler = new CommandScheduler()) {
AtomicBoolean hasOtherRun = new AtomicBoolean();
+ AtomicInteger counter = new AtomicInteger();
Subsystem requirement = new SubsystemBase() {};
Command selfCancels =
- new CommandBase() {
+ new Command() {
{
addRequirements(requirement);
}
@@ -75,6 +123,11 @@
}
@Override
+ public void end(boolean interrupted) {
+ counter.incrementAndGet();
+ }
+
+ @Override
public InterruptionBehavior getInterruptionBehavior() {
return interruptionBehavior;
}
@@ -90,6 +143,7 @@
scheduler.run();
assertFalse(scheduler.isScheduled(selfCancels));
assertTrue(scheduler.isScheduled(other));
+ assertEquals(1, counter.get());
scheduler.run();
assertTrue(hasOtherRun.get());
}
@@ -100,7 +154,7 @@
try (CommandScheduler scheduler = new CommandScheduler()) {
AtomicInteger counter = new AtomicInteger();
Command selfCancels =
- new CommandBase() {
+ new Command() {
@Override
public void end(boolean interrupted) {
counter.incrementAndGet();
@@ -116,23 +170,176 @@
}
@Test
+ void cancelFromInterruptAction() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ Command selfCancels = new RunCommand(() -> {});
+ scheduler.onCommandInterrupt(
+ cmd -> {
+ counter.incrementAndGet();
+ scheduler.cancel(selfCancels);
+ });
+ scheduler.schedule(selfCancels);
+
+ assertDoesNotThrow(() -> scheduler.cancel(selfCancels));
+ assertEquals(1, counter.get());
+ assertFalse(scheduler.isScheduled(selfCancels));
+ }
+ }
+
+ @Test
+ void cancelFromEndLoop() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ FunctionalCommand dCancelsAll =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancelAll();
+ },
+ () -> true);
+ FunctionalCommand cCancelsD =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(dCancelsAll);
+ },
+ () -> true);
+ FunctionalCommand bCancelsC =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(cCancelsD);
+ },
+ () -> true);
+ FunctionalCommand aCancelsB =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(bCancelsC);
+ },
+ () -> true);
+
+ scheduler.schedule(aCancelsB);
+ scheduler.schedule(bCancelsC);
+ scheduler.schedule(cCancelsD);
+ scheduler.schedule(dCancelsAll);
+
+ assertDoesNotThrow(() -> scheduler.cancel(aCancelsB));
+ assertEquals(4, counter.get());
+ assertFalse(scheduler.isScheduled(aCancelsB));
+ assertFalse(scheduler.isScheduled(bCancelsC));
+ assertFalse(scheduler.isScheduled(cCancelsD));
+ assertFalse(scheduler.isScheduled(dCancelsAll));
+ }
+ }
+
+ @Test
+ void cancelFromEndLoopWhileInRunLoop() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ FunctionalCommand dCancelsAll =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancelAll();
+ },
+ () -> true);
+ FunctionalCommand cCancelsD =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(dCancelsAll);
+ },
+ () -> true);
+ FunctionalCommand bCancelsC =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(cCancelsD);
+ },
+ () -> true);
+ FunctionalCommand aCancelsB =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.cancel(bCancelsC);
+ },
+ () -> true);
+
+ scheduler.schedule(aCancelsB);
+ scheduler.schedule(bCancelsC);
+ scheduler.schedule(cCancelsD);
+ scheduler.schedule(dCancelsAll);
+
+ assertDoesNotThrow(() -> scheduler.run());
+ assertEquals(4, counter.get());
+ assertFalse(scheduler.isScheduled(aCancelsB));
+ assertFalse(scheduler.isScheduled(bCancelsC));
+ assertFalse(scheduler.isScheduled(cCancelsD));
+ assertFalse(scheduler.isScheduled(dCancelsAll));
+ }
+ }
+
+ @Test
+ void multiCancelFromEnd() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ FunctionalCommand bIncrementsCounter =
+ new FunctionalCommand(
+ () -> {}, () -> {}, interrupted -> counter.incrementAndGet(), () -> true);
+ Command aCancelsB =
+ new Command() {
+ @Override
+ public void end(boolean interrupted) {
+ counter.incrementAndGet();
+ scheduler.cancel(bIncrementsCounter);
+ scheduler.cancel(this);
+ }
+ };
+
+ scheduler.schedule(aCancelsB);
+ scheduler.schedule(bIncrementsCounter);
+
+ assertDoesNotThrow(() -> scheduler.cancel(aCancelsB));
+ assertEquals(2, counter.get());
+ assertFalse(scheduler.isScheduled(aCancelsB));
+ assertFalse(scheduler.isScheduled(bIncrementsCounter));
+ }
+ }
+
+ @Test
void scheduleFromEndCancel() {
try (CommandScheduler scheduler = new CommandScheduler()) {
AtomicInteger counter = new AtomicInteger();
Subsystem requirement = new SubsystemBase() {};
InstantCommand other = new InstantCommand(() -> {}, requirement);
- Command selfCancels =
- new CommandBase() {
- {
- addRequirements(requirement);
- }
-
- @Override
- public void end(boolean interrupted) {
- counter.incrementAndGet();
- scheduler.schedule(other);
- }
- };
+ FunctionalCommand selfCancels =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.schedule(other);
+ },
+ () -> false,
+ requirement);
scheduler.schedule(selfCancels);
@@ -148,19 +355,38 @@
AtomicInteger counter = new AtomicInteger();
Subsystem requirement = new SubsystemBase() {};
InstantCommand other = new InstantCommand(() -> {}, requirement);
- Command selfCancels =
- new CommandBase() {
- {
- addRequirements(requirement);
- }
+ FunctionalCommand selfCancels =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.schedule(other);
+ },
+ () -> false,
+ requirement);
- @Override
- public void end(boolean interrupted) {
- counter.incrementAndGet();
- scheduler.schedule(other);
- }
- };
+ scheduler.schedule(selfCancels);
+ assertDoesNotThrow(() -> scheduler.schedule(other));
+ assertEquals(1, counter.get());
+ assertFalse(scheduler.isScheduled(selfCancels));
+ assertTrue(scheduler.isScheduled(other));
+ }
+ }
+
+ @Test
+ void scheduleFromEndInterruptAction() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ Subsystem requirement = new Subsystem() {};
+ InstantCommand other = new InstantCommand(() -> {}, requirement);
+ InstantCommand selfCancels = new InstantCommand(() -> {}, requirement);
+ scheduler.onCommandInterrupt(
+ cmd -> {
+ counter.incrementAndGet();
+ scheduler.schedule(other);
+ });
scheduler.schedule(selfCancels);
assertDoesNotThrow(() -> scheduler.schedule(other));
@@ -178,18 +404,16 @@
Subsystem requirement = new SubsystemBase() {};
Command other =
new InstantCommand(() -> {}, requirement).withInterruptBehavior(interruptionBehavior);
- Command defaultCommand =
- new CommandBase() {
- {
- addRequirements(requirement);
- }
-
- @Override
- public void initialize() {
- counter.incrementAndGet();
- scheduler.schedule(other);
- }
- };
+ FunctionalCommand defaultCommand =
+ new FunctionalCommand(
+ () -> {
+ counter.incrementAndGet();
+ scheduler.schedule(other);
+ },
+ () -> {},
+ interrupted -> {},
+ () -> false,
+ requirement);
scheduler.setDefaultCommand(requirement, defaultCommand);
@@ -201,4 +425,41 @@
assertTrue(scheduler.isScheduled(other));
}
}
+
+ @Test
+ void cancelDefaultCommandFromEnd() {
+ try (CommandScheduler scheduler = new CommandScheduler()) {
+ AtomicInteger counter = new AtomicInteger();
+ Subsystem requirement = new Subsystem() {};
+ Command defaultCommand =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> counter.incrementAndGet(),
+ () -> false,
+ requirement);
+ Command other = new InstantCommand(() -> {}, requirement);
+ Command cancelDefaultCommand =
+ new FunctionalCommand(
+ () -> {},
+ () -> {},
+ interrupted -> {
+ counter.incrementAndGet();
+ scheduler.schedule(other);
+ },
+ () -> false);
+
+ assertDoesNotThrow(
+ () -> {
+ scheduler.schedule(cancelDefaultCommand);
+ scheduler.setDefaultCommand(requirement, defaultCommand);
+
+ scheduler.run();
+ scheduler.cancel(cancelDefaultCommand);
+ });
+ assertEquals(2, counter.get());
+ assertFalse(scheduler.isScheduled(defaultCommand));
+ assertTrue(scheduler.isScheduled(other));
+ }
+ }
}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SelectCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SelectCommandTest.java
index 736f120..0ce3b79 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SelectCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SelectCommandTest.java
@@ -13,7 +13,8 @@
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 @@
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 @@
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 @@
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 @@
}
@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);
}
}
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommandTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommandTest.java
index 1367e51..9dd03ae 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommandTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/SwerveControllerCommandTest.java
@@ -114,8 +114,7 @@
this::setModuleStates,
subsystem);
- m_timer.reset();
- m_timer.start();
+ m_timer.restart();
command.initialize();
while (!command.isFinished()) {
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
index 82d359c..87f8d16 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
@@ -194,34 +194,6 @@
assertEquals(1, endCounter.get());
}
- // Binding runnables directly is deprecated -- users should create the command manually
- @SuppressWarnings("deprecation")
- @Test
- void runnableBindingTest() {
- InternalButton buttonWhenActive = new InternalButton();
- InternalButton buttonWhileActiveContinuous = new InternalButton();
- InternalButton buttonWhenInactive = new InternalButton();
-
- buttonWhenActive.setPressed(false);
- buttonWhileActiveContinuous.setPressed(true);
- buttonWhenInactive.setPressed(true);
-
- AtomicInteger counter = new AtomicInteger(0);
-
- buttonWhenActive.whenPressed(counter::incrementAndGet);
- buttonWhileActiveContinuous.whileActiveContinuous(counter::incrementAndGet);
- buttonWhenInactive.whenInactive(counter::incrementAndGet);
-
- CommandScheduler scheduler = CommandScheduler.getInstance();
-
- scheduler.run();
- buttonWhenActive.setPressed(true);
- buttonWhenInactive.setPressed(false);
- scheduler.run();
-
- assertEquals(counter.get(), 4);
- }
-
@Test
void triggerCompositionTest() {
InternalButton button1 = new InternalButton();
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/AddRequirementsTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/AddRequirementsTest.cpp
new file mode 100644
index 0000000..8ef5154
--- /dev/null
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/AddRequirementsTest.cpp
@@ -0,0 +1,144 @@
+// 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 <wpi/array.h>
+
+#include "CommandTestBase.h"
+#include "frc2/command/Command.h"
+#include "frc2/command/RunCommand.h"
+
+using namespace frc2;
+
+// Class to verify the overload resolution of Command::AddRequirements. This
+// does not derive from Command because AddRequirements is non-virtual,
+// preventing overriding anyways.
+class MockAddRequirements {
+ public:
+ MOCK_METHOD(void, AddRequirements, (Requirements), ());
+ MOCK_METHOD(void, AddRequirements, ((wpi::SmallSet<Subsystem*, 4>)), ());
+ MOCK_METHOD(void, AddRequirements, (Subsystem*), ());
+};
+
+TEST(AddRequirementsTest, InitializerListOverloadResolution) {
+ TestSubsystem requirement;
+
+ MockAddRequirements overloadResolver;
+
+ EXPECT_CALL(overloadResolver, AddRequirements(testing::An<Requirements>()));
+
+ overloadResolver.AddRequirements({&requirement, &requirement});
+}
+
+TEST(AddRequirementsTest, SpanOverloadResolution) {
+ std::span<Subsystem* const> requirementsSpan;
+
+ MockAddRequirements overloadResolver;
+
+ EXPECT_CALL(overloadResolver, AddRequirements(testing::An<Requirements>()));
+
+ overloadResolver.AddRequirements(requirementsSpan);
+}
+
+TEST(AddRequirementsTest, SmallSetOverloadResolution) {
+ wpi::SmallSet<Subsystem*, 4> requirementsSet;
+
+ MockAddRequirements overloadResolver;
+
+ EXPECT_CALL(overloadResolver,
+ AddRequirements(testing::An<wpi::SmallSet<Subsystem*, 4>>()));
+
+ overloadResolver.AddRequirements(requirementsSet);
+}
+
+TEST(AddRequirementsTest, SubsystemOverloadResolution) {
+ TestSubsystem requirement;
+
+ MockAddRequirements overloadResolver;
+
+ EXPECT_CALL(overloadResolver, AddRequirements(testing::An<Subsystem*>()));
+
+ overloadResolver.AddRequirements(&requirement);
+}
+
+TEST(AddRequirementsTest, InitializerListSemantics) {
+ TestSubsystem requirement1;
+ TestSubsystem requirement2;
+
+ RunCommand command([] {});
+ command.AddRequirements({&requirement1, &requirement2});
+ EXPECT_TRUE(command.HasRequirement(&requirement1));
+ EXPECT_TRUE(command.HasRequirement(&requirement2));
+ EXPECT_EQ(command.GetRequirements().size(), 2u);
+}
+
+TEST(AddRequirementsTest, InitializerListDuplicatesSemantics) {
+ TestSubsystem requirement;
+
+ RunCommand command([] {});
+ command.AddRequirements({&requirement, &requirement});
+ EXPECT_TRUE(command.HasRequirement(&requirement));
+ EXPECT_EQ(command.GetRequirements().size(), 1u);
+}
+
+TEST(AddRequirementsTest, SpanSemantics) {
+ TestSubsystem requirement1;
+ TestSubsystem requirement2;
+
+ wpi::array<Subsystem* const, 2> requirementsArray(&requirement1,
+ &requirement2);
+
+ RunCommand command([] {});
+ command.AddRequirements(std::span{requirementsArray});
+ EXPECT_TRUE(command.HasRequirement(&requirement1));
+ EXPECT_TRUE(command.HasRequirement(&requirement2));
+ EXPECT_EQ(command.GetRequirements().size(), 2u);
+}
+
+TEST(AddRequirementsTest, SpanDuplicatesSemantics) {
+ TestSubsystem requirement;
+
+ wpi::array<Subsystem* const, 2> requirementsArray(&requirement, &requirement);
+
+ RunCommand command([] {});
+ command.AddRequirements(std::span{requirementsArray});
+ EXPECT_TRUE(command.HasRequirement(&requirement));
+ EXPECT_EQ(command.GetRequirements().size(), 1u);
+}
+
+TEST(AddRequirementsTest, SmallSetSemantics) {
+ TestSubsystem requirement1;
+ TestSubsystem requirement2;
+
+ wpi::SmallSet<Subsystem*, 4> requirementsSet;
+ requirementsSet.insert(&requirement1);
+ requirementsSet.insert(&requirement2);
+
+ RunCommand command([] {});
+ command.AddRequirements(requirementsSet);
+ EXPECT_TRUE(command.HasRequirement(&requirement1));
+ EXPECT_TRUE(command.HasRequirement(&requirement2));
+ EXPECT_EQ(command.GetRequirements().size(), 2u);
+}
+
+TEST(AddRequirementsTest, SubsystemPointerSemantics) {
+ TestSubsystem requirement1;
+ TestSubsystem requirement2;
+
+ RunCommand command([] {});
+ command.AddRequirements(&requirement1);
+ command.AddRequirements(&requirement2);
+ EXPECT_TRUE(command.HasRequirement(&requirement1));
+ EXPECT_TRUE(command.HasRequirement(&requirement2));
+ EXPECT_EQ(command.GetRequirements().size(), 2u);
+}
+
+TEST(AddRequirementsTest, SubsystemPointerDuplicatesSemantics) {
+ TestSubsystem requirement;
+
+ RunCommand command([] {});
+ command.AddRequirements(&requirement);
+ command.AddRequirements(&requirement);
+ EXPECT_TRUE(command.HasRequirement(&requirement));
+ EXPECT_EQ(command.GetRequirements().size(), 1u);
+}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp
index 5ab184c..884d504 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp
@@ -9,7 +9,6 @@
#include "frc2/command/FunctionalCommand.h"
#include "frc2/command/InstantCommand.h"
#include "frc2/command/ParallelRaceGroup.h"
-#include "frc2/command/PerpetualCommand.h"
#include "frc2/command/RunCommand.h"
#include "frc2/command/SequentialCommandGroup.h"
@@ -54,6 +53,24 @@
EXPECT_FALSE(scheduler.IsScheduled(command));
}
+TEST_F(CommandDecoratorTest, OnlyWhile) {
+ CommandScheduler scheduler = GetScheduler();
+
+ bool run = true;
+
+ auto command = RunCommand([] {}, {}).OnlyWhile([&run] { return run; });
+
+ scheduler.Schedule(command);
+
+ scheduler.Run();
+ EXPECT_TRUE(scheduler.IsScheduled(command));
+
+ run = false;
+
+ scheduler.Run();
+ EXPECT_FALSE(scheduler.IsScheduled(command));
+}
+
TEST_F(CommandDecoratorTest, IgnoringDisable) {
CommandScheduler scheduler = GetScheduler();
@@ -104,21 +121,6 @@
EXPECT_TRUE(finished);
}
-TEST_F(CommandDecoratorTest, Perpetually) {
- CommandScheduler scheduler = GetScheduler();
-
- WPI_IGNORE_DEPRECATED
- auto command = InstantCommand([] {}, {}).Perpetually();
- WPI_UNIGNORE_DEPRECATED
-
- scheduler.Schedule(&command);
-
- scheduler.Run();
- scheduler.Run();
-
- EXPECT_TRUE(scheduler.IsScheduled(&command));
-}
-
TEST_F(CommandDecoratorTest, Unless) {
CommandScheduler scheduler = GetScheduler();
@@ -140,6 +142,27 @@
EXPECT_TRUE(hasRun);
}
+TEST_F(CommandDecoratorTest, OnlyIf) {
+ CommandScheduler scheduler = GetScheduler();
+
+ bool hasRun = false;
+ bool onlyIfBool = false;
+
+ auto command =
+ InstantCommand([&hasRun] { hasRun = true; }, {}).OnlyIf([&onlyIfBool] {
+ return onlyIfBool;
+ });
+
+ scheduler.Schedule(command);
+ scheduler.Run();
+ EXPECT_FALSE(hasRun);
+
+ onlyIfBool = true;
+ scheduler.Schedule(command);
+ scheduler.Run();
+ EXPECT_TRUE(hasRun);
+}
+
TEST_F(CommandDecoratorTest, FinallyDo) {
CommandScheduler scheduler = GetScheduler();
int first = 0;
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp
index 26077f2..6c57c7f 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp
@@ -27,6 +27,7 @@
EXPECT_NO_FATAL_FAILURE(scheduler.Cancel(movedTo));
EXPECT_THROW(scheduler.Schedule(movedFrom), frc::RuntimeError);
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
EXPECT_THROW(movedFrom.IsScheduled(), frc::RuntimeError);
EXPECT_THROW(static_cast<void>(std::move(movedFrom).Repeatedly()),
frc::RuntimeError);
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp
index 79a472f..b46bb8b 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp
@@ -12,7 +12,6 @@
#include "frc2/command/ParallelCommandGroup.h"
#include "frc2/command/ParallelDeadlineGroup.h"
#include "frc2/command/ParallelRaceGroup.h"
-#include "frc2/command/SelectCommand.h"
#include "frc2/command/SequentialCommandGroup.h"
using namespace frc2;
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandScheduleTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandScheduleTest.cpp
index cb16b48..9178677 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandScheduleTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandScheduleTest.cpp
@@ -2,6 +2,9 @@
// 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/smartdashboard/SmartDashboard.h>
+#include <networktables/NetworkTableInstance.h>
+
#include "CommandTestBase.h"
using namespace frc2;
@@ -98,3 +101,24 @@
EXPECT_NO_FATAL_FAILURE(scheduler.Cancel(&command));
}
+
+TEST_F(CommandScheduleTest, SmartDashboardCancel) {
+ CommandScheduler scheduler = GetScheduler();
+ frc::SmartDashboard::PutData("Scheduler", &scheduler);
+ frc::SmartDashboard::UpdateValues();
+
+ MockCommand command;
+ scheduler.Schedule(&command);
+ scheduler.Run();
+ frc::SmartDashboard::UpdateValues();
+ EXPECT_TRUE(scheduler.IsScheduled(&command));
+
+ uintptr_t ptrTmp = reinterpret_cast<uintptr_t>(&command);
+ nt::NetworkTableInstance::GetDefault()
+ .GetEntry("/SmartDashboard/Scheduler/Cancel")
+ .SetIntegerArray(
+ std::span<const int64_t>{{static_cast<int64_t>(ptrTmp)}});
+ frc::SmartDashboard::UpdateValues();
+ scheduler.Run();
+ EXPECT_FALSE(scheduler.IsScheduled(&command));
+}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandSendableButtonTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandSendableButtonTest.cpp
new file mode 100644
index 0000000..08caa5c
--- /dev/null
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandSendableButtonTest.cpp
@@ -0,0 +1,98 @@
+// 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/Commands.h>
+
+#include <frc/smartdashboard/SmartDashboard.h>
+#include <networktables/BooleanTopic.h>
+#include <networktables/NetworkTableInstance.h>
+
+#include "CommandTestBase.h"
+
+using namespace frc2;
+
+class CommandSendableButtonTest : public CommandTestBase {
+ protected:
+ int m_schedule;
+ int m_cancel;
+ nt::BooleanPublisher m_publish;
+ std::optional<CommandPtr> m_command;
+
+ void SetUp() override {
+ m_schedule = 0;
+ m_cancel = 0;
+ m_command = cmd::StartEnd([this] { m_schedule++; }, [this] { m_cancel++; });
+ m_publish = nt::NetworkTableInstance::GetDefault()
+ .GetBooleanTopic("/SmartDashboard/command/running")
+ .Publish();
+ frc::SmartDashboard::PutData("command", m_command->get());
+ frc::SmartDashboard::UpdateValues();
+ }
+};
+
+TEST_F(CommandSendableButtonTest, trueAndNotScheduledSchedules) {
+ // Not scheduled and true -> scheduled
+ GetScheduler().Run();
+ frc::SmartDashboard::UpdateValues();
+ EXPECT_FALSE(m_command->IsScheduled());
+ EXPECT_EQ(0, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+
+ m_publish.Set(true);
+ frc::SmartDashboard::UpdateValues();
+ GetScheduler().Run();
+ EXPECT_TRUE(m_command->IsScheduled());
+ EXPECT_EQ(1, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+}
+
+TEST_F(CommandSendableButtonTest, trueAndScheduledNoOp) {
+ // Scheduled and true -> no-op
+ m_command->Schedule();
+ GetScheduler().Run();
+ frc::SmartDashboard::UpdateValues();
+ EXPECT_TRUE(m_command->IsScheduled());
+ EXPECT_EQ(1, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+
+ m_publish.Set(true);
+ frc::SmartDashboard::UpdateValues();
+ GetScheduler().Run();
+ EXPECT_TRUE(m_command->IsScheduled());
+ EXPECT_EQ(1, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+}
+
+TEST_F(CommandSendableButtonTest, falseAndNotScheduledNoOp) {
+ // Not scheduled and false -> no-op
+ GetScheduler().Run();
+ frc::SmartDashboard::UpdateValues();
+ EXPECT_FALSE(m_command->IsScheduled());
+ EXPECT_EQ(0, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+
+ m_publish.Set(false);
+ frc::SmartDashboard::UpdateValues();
+ GetScheduler().Run();
+ EXPECT_FALSE(m_command->IsScheduled());
+ EXPECT_EQ(0, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+}
+
+TEST_F(CommandSendableButtonTest, falseAndScheduledCancel) {
+ // Scheduled and false -> cancel
+ m_command->Schedule();
+ GetScheduler().Run();
+ frc::SmartDashboard::UpdateValues();
+ EXPECT_TRUE(m_command->IsScheduled());
+ EXPECT_EQ(1, m_schedule);
+ EXPECT_EQ(0, m_cancel);
+
+ m_publish.Set(false);
+ frc::SmartDashboard::UpdateValues();
+ GetScheduler().Run();
+ EXPECT_FALSE(m_command->IsScheduled());
+ EXPECT_EQ(1, m_schedule);
+ EXPECT_EQ(1, m_cancel);
+}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.cpp
index 6e27d24..1bd180c 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.cpp
@@ -11,22 +11,22 @@
scheduler.CancelAll();
scheduler.Enable();
scheduler.GetActiveButtonLoop()->Clear();
+ scheduler.UnregisterAllSubsystems();
+
+ SetDSEnabled(true);
+}
+
+CommandTestBase::~CommandTestBase() {
+ CommandScheduler::GetInstance().GetActiveButtonLoop()->Clear();
+ CommandScheduler::GetInstance().UnregisterAllSubsystems();
}
CommandScheduler CommandTestBase::GetScheduler() {
return CommandScheduler();
}
-void CommandTestBase::SetUp() {
- frc::sim::DriverStationSim::SetEnabled(true);
- frc::sim::DriverStationSim::NotifyNewData();
-}
-
-void CommandTestBase::TearDown() {
- CommandScheduler::GetInstance().GetActiveButtonLoop()->Clear();
-}
-
void CommandTestBase::SetDSEnabled(bool enabled) {
+ frc::sim::DriverStationSim::SetDsAttached(true);
frc::sim::DriverStationSim::SetEnabled(enabled);
frc::sim::DriverStationSim::NotifyNewData();
}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.h b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.h
index a1ab1de..586432d 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.h
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandTestBase.h
@@ -4,92 +4,99 @@
#pragma once
+#include <functional>
#include <memory>
#include <utility>
#include <frc/simulation/DriverStationSim.h>
+#include <gtest/gtest.h>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/CommandScheduler.h"
-#include "frc2/command/SetUtilities.h"
+#include "frc2/command/Requirements.h"
#include "frc2/command/SubsystemBase.h"
#include "gmock/gmock.h"
-#include "gtest/gtest.h"
#include "make_vector.h"
namespace frc2 {
+class TestSubsystem : public SubsystemBase {
+ public:
+ explicit TestSubsystem(std::function<void()> periodic = [] {})
+ : m_periodic{periodic} {}
+ void Periodic() override { m_periodic(); }
+
+ private:
+ std::function<void()> m_periodic;
+};
+
+/**
+ * NOTE: Moving mock objects causes EXPECT_CALL to not work correctly!
+ */
+class MockCommand : public CommandHelper<Command, MockCommand> {
+ public:
+ MOCK_CONST_METHOD0(GetRequirements, wpi::SmallSet<Subsystem*, 4>());
+ MOCK_METHOD0(IsFinished, bool());
+ MOCK_CONST_METHOD0(RunsWhenDisabled, bool());
+ MOCK_METHOD0(Initialize, void());
+ MOCK_METHOD0(Execute, void());
+ MOCK_METHOD1(End, void(bool interrupted));
+
+ MockCommand() {
+ m_requirements = {};
+ EXPECT_CALL(*this, GetRequirements())
+ .WillRepeatedly(::testing::Return(m_requirements));
+ EXPECT_CALL(*this, IsFinished()).WillRepeatedly(::testing::Return(false));
+ EXPECT_CALL(*this, RunsWhenDisabled())
+ .WillRepeatedly(::testing::Return(true));
+ }
+
+ explicit MockCommand(Requirements requirements, bool finished = false,
+ bool runWhenDisabled = true) {
+ m_requirements.insert(requirements.begin(), requirements.end());
+ EXPECT_CALL(*this, GetRequirements())
+ .WillRepeatedly(::testing::Return(m_requirements));
+ EXPECT_CALL(*this, IsFinished())
+ .WillRepeatedly(::testing::Return(finished));
+ EXPECT_CALL(*this, RunsWhenDisabled())
+ .WillRepeatedly(::testing::Return(runWhenDisabled));
+ }
+
+ MockCommand(MockCommand&& other) {
+ EXPECT_CALL(*this, IsFinished())
+ .WillRepeatedly(::testing::Return(other.IsFinished()));
+ EXPECT_CALL(*this, RunsWhenDisabled())
+ .WillRepeatedly(::testing::Return(other.RunsWhenDisabled()));
+ std::swap(m_requirements, other.m_requirements);
+ EXPECT_CALL(*this, GetRequirements())
+ .WillRepeatedly(::testing::Return(m_requirements));
+ }
+
+ MockCommand(const MockCommand& other) : CommandHelper{other} {}
+
+ void SetFinished(bool finished) {
+ EXPECT_CALL(*this, IsFinished())
+ .WillRepeatedly(::testing::Return(finished));
+ }
+
+ ~MockCommand() { // NOLINT
+ auto& scheduler = CommandScheduler::GetInstance();
+ scheduler.Cancel(this);
+ }
+
+ private:
+ wpi::SmallSet<Subsystem*, 4> m_requirements;
+};
+
class CommandTestBase : public ::testing::Test {
public:
CommandTestBase();
- class TestSubsystem : public SubsystemBase {};
+ ~CommandTestBase() override;
protected:
- /**
- * NOTE: Moving mock objects causes EXPECT_CALL to not work correctly!
- */
- class MockCommand : public CommandHelper<CommandBase, MockCommand> {
- public:
- MOCK_CONST_METHOD0(GetRequirements, wpi::SmallSet<Subsystem*, 4>());
- MOCK_METHOD0(IsFinished, bool());
- MOCK_CONST_METHOD0(RunsWhenDisabled, bool());
- MOCK_METHOD0(Initialize, void());
- MOCK_METHOD0(Execute, void());
- MOCK_METHOD1(End, void(bool interrupted));
-
- MockCommand() {
- m_requirements = {};
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- EXPECT_CALL(*this, IsFinished()).WillRepeatedly(::testing::Return(false));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(true));
- }
-
- MockCommand(std::initializer_list<Subsystem*> requirements,
- bool finished = false, bool runWhenDisabled = true) {
- m_requirements.insert(requirements.begin(), requirements.end());
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(finished));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(runWhenDisabled));
- }
-
- MockCommand(MockCommand&& other) {
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(other.IsFinished()));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(other.RunsWhenDisabled()));
- std::swap(m_requirements, other.m_requirements);
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- }
-
- MockCommand(const MockCommand& other) : CommandHelper{other} {}
-
- void SetFinished(bool finished) {
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(finished));
- }
-
- ~MockCommand() { // NOLINT
- auto& scheduler = CommandScheduler::GetInstance();
- scheduler.Cancel(this);
- }
-
- private:
- wpi::SmallSet<Subsystem*, 4> m_requirements;
- };
-
CommandScheduler GetScheduler();
- void SetUp() override;
-
- void TearDown() override;
-
void SetDSEnabled(bool enabled);
};
@@ -101,81 +108,23 @@
scheduler.CancelAll();
scheduler.Enable();
scheduler.GetActiveButtonLoop()->Clear();
+ scheduler.UnregisterAllSubsystems();
+
+ SetDSEnabled(true);
}
- class TestSubsystem : public SubsystemBase {};
+ ~CommandTestBaseWithParam() override {
+ CommandScheduler::GetInstance().GetActiveButtonLoop()->Clear();
+ CommandScheduler::GetInstance().UnregisterAllSubsystems();
+ }
protected:
- class MockCommand : public Command {
- public:
- MOCK_CONST_METHOD0(GetRequirements, wpi::SmallSet<Subsystem*, 4>());
- MOCK_METHOD0(IsFinished, bool());
- MOCK_CONST_METHOD0(RunsWhenDisabled, bool());
- MOCK_METHOD0(Initialize, void());
- MOCK_METHOD0(Execute, void());
- MOCK_METHOD1(End, void(bool interrupted));
-
- MockCommand() {
- m_requirements = {};
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- EXPECT_CALL(*this, IsFinished()).WillRepeatedly(::testing::Return(false));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(true));
- }
-
- MockCommand(std::initializer_list<Subsystem*> requirements,
- bool finished = false, bool runWhenDisabled = true) {
- m_requirements.insert(requirements.begin(), requirements.end());
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(finished));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(runWhenDisabled));
- }
-
- MockCommand(MockCommand&& other) {
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(other.IsFinished()));
- EXPECT_CALL(*this, RunsWhenDisabled())
- .WillRepeatedly(::testing::Return(other.RunsWhenDisabled()));
- std::swap(m_requirements, other.m_requirements);
- EXPECT_CALL(*this, GetRequirements())
- .WillRepeatedly(::testing::Return(m_requirements));
- }
-
- MockCommand(const MockCommand& other) : Command{other} {}
-
- void SetFinished(bool finished) {
- EXPECT_CALL(*this, IsFinished())
- .WillRepeatedly(::testing::Return(finished));
- }
-
- ~MockCommand() { // NOLINT
- auto& scheduler = CommandScheduler::GetInstance();
- scheduler.Cancel(this);
- }
-
- protected:
- std::unique_ptr<Command> TransferOwnership() && { // NOLINT
- return std::make_unique<MockCommand>(std::move(*this));
- }
-
- private:
- wpi::SmallSet<Subsystem*, 4> m_requirements;
- };
-
CommandScheduler GetScheduler() { return CommandScheduler(); }
- void SetUp() override { frc::sim::DriverStationSim::SetEnabled(true); }
-
- void TearDown() override {
- CommandScheduler::GetInstance().GetActiveButtonLoop()->Clear();
- }
-
void SetDSEnabled(bool enabled) {
+ frc::sim::DriverStationSim::SetDsAttached(true);
frc::sim::DriverStationSim::SetEnabled(enabled);
+ frc::sim::DriverStationSim::NotifyNewData();
}
};
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CompositionTestBase.h b/wpilibNewCommands/src/test/native/cpp/frc2/command/CompositionTestBase.h
index c12922f..58fbcc3 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CompositionTestBase.h
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CompositionTestBase.h
@@ -7,9 +7,10 @@
#include <memory>
#include <utility>
+#include <gtest/gtest.h>
+
#include "CommandTestBase.h"
#include "frc2/command/Commands.h"
-#include "gtest/gtest.h"
#include "make_vector.h"
namespace frc2 {
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp
index 27b89e5..d7bbd26 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp
@@ -3,9 +3,9 @@
// the WPILib BSD license file in the root directory of this project.
#include "CommandTestBase.h"
+#include "frc2/command/Commands.h"
#include "frc2/command/ConditionalCommand.h"
#include "frc2/command/InstantCommand.h"
-#include "frc2/command/SelectCommand.h"
using namespace frc2;
class ConditionalCommandTest : public CommandTestBase {};
@@ -51,3 +51,87 @@
EXPECT_TRUE(scheduler.IsScheduled(&command3));
EXPECT_FALSE(scheduler.IsScheduled(&conditional));
}
+
+TEST_F(ConditionalCommandTest, AllTrue) {
+ CommandPtr command =
+ cmd::Either(cmd::WaitUntil([] { return false; }).IgnoringDisable(true),
+ cmd::WaitUntil([] { return false; }).IgnoringDisable(true),
+ [] { return true; });
+ EXPECT_EQ(true, command.get()->RunsWhenDisabled());
+}
+
+TEST_F(ConditionalCommandTest, AllFalse) {
+ CommandPtr command =
+ cmd::Either(cmd::WaitUntil([] { return false; }).IgnoringDisable(false),
+ cmd::WaitUntil([] { return false; }).IgnoringDisable(false),
+ [] { return true; });
+ EXPECT_EQ(false, command.get()->RunsWhenDisabled());
+}
+
+TEST_F(ConditionalCommandTest, OneTrueOneFalse) {
+ CommandPtr command =
+ cmd::Either(cmd::WaitUntil([] { return false; }).IgnoringDisable(true),
+ cmd::WaitUntil([] { return false; }).IgnoringDisable(false),
+ [] { return true; });
+ EXPECT_EQ(false, command.get()->RunsWhenDisabled());
+}
+
+TEST_F(ConditionalCommandTest, TwoFalseOneTrue) {
+ CommandPtr command =
+ cmd::Either(cmd::WaitUntil([] { return false; }).IgnoringDisable(false),
+ cmd::WaitUntil([] { return false; }).IgnoringDisable(true),
+ [] { return true; });
+ EXPECT_EQ(false, command.get()->RunsWhenDisabled());
+}
+
+TEST_F(ConditionalCommandTest, AllCancelSelf) {
+ CommandPtr command = cmd::Either(
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelSelf),
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelSelf),
+ [] { return true; });
+ EXPECT_EQ(Command::InterruptionBehavior::kCancelSelf,
+ command.get()->GetInterruptionBehavior());
+}
+
+TEST_F(ConditionalCommandTest, AllCancelIncoming) {
+ CommandPtr command = cmd::Either(
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelIncoming),
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelIncoming),
+ [] { return false; });
+ EXPECT_EQ(Command::InterruptionBehavior::kCancelIncoming,
+ command.get()->GetInterruptionBehavior());
+}
+
+TEST_F(ConditionalCommandTest, OneCancelSelfOneIncoming) {
+ CommandPtr command = cmd::Either(
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelSelf),
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelIncoming),
+ [] { return false; });
+ EXPECT_EQ(Command::InterruptionBehavior::kCancelSelf,
+ command.get()->GetInterruptionBehavior());
+}
+
+TEST_F(ConditionalCommandTest, OneCancelIncomingOneSelf) {
+ CommandPtr command = cmd::Either(
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelIncoming),
+ cmd::WaitUntil([] {
+ return false;
+ }).WithInterruptBehavior(Command::InterruptionBehavior::kCancelSelf),
+ [] { return false; });
+ EXPECT_EQ(Command::InterruptionBehavior::kCancelSelf,
+ command.get()->GetInterruptionBehavior());
+}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/DeferredCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/DeferredCommandTest.cpp
new file mode 100644
index 0000000..1af8ae4
--- /dev/null
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/DeferredCommandTest.cpp
@@ -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));
+}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/MecanumControllerCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/MecanumControllerCommandTest.cpp
index 7f5b590..c79432d 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/MecanumControllerCommandTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/MecanumControllerCommandTest.cpp
@@ -16,8 +16,9 @@
#include <frc/kinematics/MecanumDriveOdometry.h>
#include <frc/simulation/SimHooks.h>
#include <frc/trajectory/TrajectoryGenerator.h>
+#include <gtest/gtest.h>
-#include "gtest/gtest.h"
+#include "CommandTestBase.h"
#define EXPECT_NEAR_UNITS(val1, val2, eps) \
EXPECT_LE(units::math::abs(val1 - val2), eps)
@@ -87,7 +88,7 @@
};
TEST_F(MecanumControllerCommandTest, ReachesReference) {
- frc2::Subsystem subsystem;
+ frc2::TestSubsystem subsystem;
auto waypoints =
std::vector{frc::Pose2d{0_m, 0_m, 0_rad}, frc::Pose2d{1_m, 5_m, 3_rad}};
@@ -99,7 +100,7 @@
auto command = frc2::MecanumControllerCommand(
trajectory, [&]() { return getRobotPose(); }, m_kinematics,
- frc2::PIDController(0.6, 0, 0), frc2::PIDController(0.6, 0, 0),
+ frc::PIDController(0.6, 0, 0), frc::PIDController(0.6, 0, 0),
m_rotController, 8.8_mps,
[&](units::meters_per_second_t frontLeft,
units::meters_per_second_t rearLeft,
@@ -112,8 +113,7 @@
},
{&subsystem});
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
command.Initialize();
while (!command.IsFinished()) {
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/POVButtonTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/POVButtonTest.cpp
index bcb7dec..035fd49 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/POVButtonTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/POVButtonTest.cpp
@@ -4,13 +4,13 @@
#include <frc/Joystick.h>
#include <frc/simulation/JoystickSim.h>
+#include <gtest/gtest.h>
#include "CommandTestBase.h"
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/RunCommand.h"
#include "frc2/command/WaitUntilCommand.h"
#include "frc2/command/button/POVButton.h"
-#include "gtest/gtest.h"
using namespace frc2;
class POVButtonTest : public CommandTestBase {};
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/PerpetualCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/PerpetualCommandTest.cpp
deleted file mode 100644
index b53835b..0000000
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/PerpetualCommandTest.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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/InstantCommand.h"
-#include "frc2/command/PerpetualCommand.h"
-
-using namespace frc2;
-class PerpetualCommandTest : public CommandTestBase {};
-
-TEST_F(PerpetualCommandTest, PerpetualCommandSchedule) {
- CommandScheduler scheduler = GetScheduler();
-
- bool check = false;
-
- WPI_IGNORE_DEPRECATED
- PerpetualCommand command{InstantCommand([&check] { check = true; }, {})};
- WPI_UNIGNORE_DEPRECATED
-
- scheduler.Schedule(&command);
- scheduler.Run();
- EXPECT_TRUE(scheduler.IsScheduled(&command));
- EXPECT_TRUE(check);
-}
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/RepeatCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/RepeatCommandTest.cpp
index b715983..b5456fa 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/RepeatCommandTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/RepeatCommandTest.cpp
@@ -60,6 +60,19 @@
EXPECT_EQ(3, exeCounter);
EXPECT_EQ(3, isFinishedCounter);
EXPECT_EQ(1, endCounter);
+
+ isFinishedHook = true;
+ scheduler.Run();
+ EXPECT_EQ(2, initCounter);
+ EXPECT_EQ(4, exeCounter);
+ EXPECT_EQ(4, isFinishedCounter);
+ EXPECT_EQ(2, endCounter);
+
+ command.Cancel();
+ EXPECT_EQ(2, initCounter);
+ EXPECT_EQ(4, exeCounter);
+ EXPECT_EQ(4, isFinishedCounter);
+ EXPECT_EQ(2, endCounter);
}
INSTANTIATE_SINGLE_COMMAND_COMPOSITION_TEST_SUITE(RepeatCommandTest,
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulerTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulerTest.cpp
index ce02ba0..ef97bb0 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulerTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulerTest.cpp
@@ -43,14 +43,98 @@
EXPECT_EQ(counter, 1);
}
+TEST_F(SchedulerTest, SchedulerLambdaInterruptNoCause) {
+ CommandScheduler scheduler = GetScheduler();
+
+ int counter = 0;
+
+ scheduler.OnCommandInterrupt(
+ [&counter](const Command&, const std::optional<Command*>& interruptor) {
+ EXPECT_FALSE(interruptor);
+ counter++;
+ });
+
+ RunCommand command([] {});
+
+ scheduler.Schedule(&command);
+ scheduler.Cancel(&command);
+
+ EXPECT_EQ(1, counter);
+}
+
+TEST_F(SchedulerTest, SchedulerLambdaInterruptCause) {
+ CommandScheduler scheduler = GetScheduler();
+
+ int counter = 0;
+
+ TestSubsystem subsystem{};
+ RunCommand command([] {}, {&subsystem});
+ InstantCommand interruptor([] {}, {&subsystem});
+
+ scheduler.OnCommandInterrupt(
+ [&](const Command&, const std::optional<Command*>& cause) {
+ ASSERT_TRUE(cause);
+ EXPECT_EQ(&interruptor, *cause);
+ counter++;
+ });
+
+ scheduler.Schedule(&command);
+ scheduler.Schedule(&interruptor);
+
+ EXPECT_EQ(1, counter);
+}
+
+TEST_F(SchedulerTest, SchedulerLambdaInterruptCauseInRunLoop) {
+ CommandScheduler scheduler = GetScheduler();
+
+ int counter = 0;
+
+ TestSubsystem subsystem{};
+ RunCommand command([] {}, {&subsystem});
+ InstantCommand interruptor([] {}, {&subsystem});
+ // This command will schedule interruptor in execute() inside the run loop
+ InstantCommand interruptorScheduler(
+ [&] { scheduler.Schedule(&interruptor); });
+
+ scheduler.OnCommandInterrupt(
+ [&](const Command&, const std::optional<Command*>& cause) {
+ ASSERT_TRUE(cause);
+ EXPECT_EQ(&interruptor, *cause);
+ counter++;
+ });
+
+ scheduler.Schedule(&command);
+ scheduler.Schedule(&interruptorScheduler);
+
+ scheduler.Run();
+
+ EXPECT_EQ(1, counter);
+}
+
+TEST_F(SchedulerTest, RegisterSubsystem) {
+ CommandScheduler scheduler = GetScheduler();
+
+ int counter = 0;
+ TestSubsystem system{[&counter] { counter++; }};
+
+ EXPECT_NO_FATAL_FAILURE(scheduler.RegisterSubsystem(&system));
+
+ scheduler.Run();
+ EXPECT_EQ(counter, 1);
+}
+
TEST_F(SchedulerTest, UnregisterSubsystem) {
CommandScheduler scheduler = GetScheduler();
- TestSubsystem system;
+ int counter = 0;
+ TestSubsystem system{[&counter] { counter++; }};
scheduler.RegisterSubsystem(&system);
EXPECT_NO_FATAL_FAILURE(scheduler.UnregisterSubsystem(&system));
+
+ scheduler.Run();
+ ASSERT_EQ(counter, 0);
}
TEST_F(SchedulerTest, SchedulerCancelAll) {
@@ -62,6 +146,10 @@
int counter = 0;
scheduler.OnCommandInterrupt([&counter](const Command&) { counter++; });
+ scheduler.OnCommandInterrupt(
+ [](const Command&, const std::optional<Command*>& interruptor) {
+ EXPECT_FALSE(interruptor);
+ });
scheduler.Schedule(&command);
scheduler.Schedule(&command2);
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp
index 4aa5199..3735303 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp
@@ -2,11 +2,13 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
+#include <gtest/gtest.h>
+
#include "CommandTestBase.h"
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
+#include "frc2/command/FunctionalCommand.h"
#include "frc2/command/RunCommand.h"
-#include "gtest/gtest.h"
using namespace frc2;
@@ -14,23 +16,29 @@
: public CommandTestBaseWithParam<Command::InterruptionBehavior> {};
class SelfCancellingCommand
- : public CommandHelper<CommandBase, SelfCancellingCommand> {
+ : public CommandHelper<Command, SelfCancellingCommand> {
public:
- SelfCancellingCommand(CommandScheduler* scheduler, Subsystem* requirement,
+ SelfCancellingCommand(CommandScheduler* scheduler, int& counter,
+ Subsystem* requirement,
Command::InterruptionBehavior interruptionBehavior =
Command::InterruptionBehavior::kCancelSelf)
- : m_scheduler(scheduler), m_interrupt(interruptionBehavior) {
+ : m_scheduler(scheduler),
+ m_counter(counter),
+ m_interrupt(interruptionBehavior) {
AddRequirements(requirement);
}
void Initialize() override { m_scheduler->Cancel(this); }
+ void End(bool interrupted) override { m_counter++; }
+
InterruptionBehavior GetInterruptionBehavior() const override {
return m_interrupt;
}
private:
CommandScheduler* m_scheduler;
+ int& m_counter;
InterruptionBehavior m_interrupt;
};
@@ -38,13 +46,14 @@
* Checks <a
* href="https://github.com/wpilibsuite/allwpilib/issues/4259">wpilibsuite/allwpilib#4259</a>.
*/
-TEST_F(SchedulingRecursionTest, CancelFromInitialize) {
+TEST_P(SchedulingRecursionTest, CancelFromInitialize) {
CommandScheduler scheduler = GetScheduler();
bool hasOtherRun = false;
+ int counter = 0;
TestSubsystem requirement;
- auto selfCancels = SelfCancellingCommand(&scheduler, &requirement);
- RunCommand other =
- RunCommand([&hasOtherRun] { hasOtherRun = true; }, {&requirement});
+ SelfCancellingCommand selfCancels{&scheduler, counter, &requirement,
+ GetParam()};
+ RunCommand other{[&hasOtherRun] { hasOtherRun = true; }, {&requirement}};
scheduler.Schedule(&selfCancels);
scheduler.Run();
@@ -52,19 +61,45 @@
EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
EXPECT_TRUE(scheduler.IsScheduled(&other));
+ EXPECT_EQ(1, counter);
+ scheduler.Run();
+ EXPECT_TRUE(hasOtherRun);
+}
+
+TEST_F(SchedulingRecursionTest, CancelFromInitializeAction) {
+ CommandScheduler scheduler = GetScheduler();
+ bool hasOtherRun = false;
+ int counter = 0;
+ TestSubsystem requirement;
+ FunctionalCommand selfCancels{[] {},
+ [] {},
+ [&counter](bool) { counter++; },
+ [] { return false; },
+ {&requirement}};
+ RunCommand other{[&hasOtherRun] { hasOtherRun = true; }, {&requirement}};
+ scheduler.OnCommandInitialize([&scheduler, &selfCancels](const Command&) {
+ scheduler.Cancel(&selfCancels);
+ });
+ scheduler.Schedule(&selfCancels);
+ scheduler.Run();
+ scheduler.Schedule(&other);
+
+ EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
+ EXPECT_TRUE(scheduler.IsScheduled(&other));
+ EXPECT_EQ(1, counter);
scheduler.Run();
EXPECT_TRUE(hasOtherRun);
}
TEST_P(SchedulingRecursionTest,
- DISABLED_DefaultCommandGetsRescheduledAfterSelfCanceling) {
+ DefaultCommandGetsRescheduledAfterSelfCanceling) {
CommandScheduler scheduler = GetScheduler();
bool hasOtherRun = false;
+ int counter = 0;
TestSubsystem requirement;
- auto selfCancels =
- SelfCancellingCommand(&scheduler, &requirement, GetParam());
- RunCommand other =
- RunCommand([&hasOtherRun] { hasOtherRun = true; }, {&requirement});
+ SelfCancellingCommand selfCancels{&scheduler, counter, &requirement,
+ GetParam()};
+ RunCommand other{[&hasOtherRun] { hasOtherRun = true; }, {&requirement}};
scheduler.SetDefaultCommand(&requirement, std::move(other));
scheduler.Schedule(&selfCancels);
@@ -72,11 +107,12 @@
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
EXPECT_TRUE(scheduler.IsScheduled(scheduler.GetDefaultCommand(&requirement)));
+ EXPECT_EQ(1, counter);
scheduler.Run();
EXPECT_TRUE(hasOtherRun);
}
-class CancelEndCommand : public CommandHelper<CommandBase, CancelEndCommand> {
+class CancelEndCommand : public CommandHelper<Command, CancelEndCommand> {
public:
CancelEndCommand(CommandScheduler* scheduler, int& counter)
: m_scheduler(scheduler), m_counter(counter) {}
@@ -103,6 +139,204 @@
EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
}
+TEST_F(SchedulingRecursionTest, CancelFromInterruptAction) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ FunctionalCommand selfCancels{[] {}, [] {}, [](bool) {},
+ [] { return false; }};
+ scheduler.OnCommandInterrupt([&](const Command&) {
+ counter++;
+ scheduler.Cancel(&selfCancels);
+ });
+ scheduler.Schedule(&selfCancels);
+
+ EXPECT_NO_THROW({ scheduler.Cancel(&selfCancels); });
+ EXPECT_EQ(1, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
+}
+
+class EndCommand : public CommandHelper<Command, EndCommand> {
+ public:
+ explicit EndCommand(std::function<void(bool)> end) : m_end(end) {}
+ void End(bool interrupted) override { m_end(interrupted); }
+ bool IsFinished() override { return true; }
+
+ private:
+ std::function<void(bool)> m_end;
+};
+
+TEST_F(SchedulingRecursionTest, CancelFromEndLoop) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ EndCommand dCancelsAll([&](bool) {
+ counter++;
+ scheduler.CancelAll();
+ });
+ EndCommand cCancelsD([&](bool) {
+ counter++;
+ scheduler.Cancel(&dCancelsAll);
+ });
+ EndCommand bCancelsC([&](bool) {
+ counter++;
+ scheduler.Cancel(&cCancelsD);
+ });
+ EndCommand aCancelsB([&](bool) {
+ counter++;
+ scheduler.Cancel(&bCancelsC);
+ });
+ scheduler.Schedule(&aCancelsB);
+ scheduler.Schedule(&bCancelsC);
+ scheduler.Schedule(&cCancelsD);
+ scheduler.Schedule(&dCancelsAll);
+
+ EXPECT_NO_THROW({ scheduler.Cancel(&aCancelsB); });
+ EXPECT_EQ(4, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&aCancelsB));
+ EXPECT_FALSE(scheduler.IsScheduled(&bCancelsC));
+ EXPECT_FALSE(scheduler.IsScheduled(&cCancelsD));
+ EXPECT_FALSE(scheduler.IsScheduled(&dCancelsAll));
+}
+
+TEST_F(SchedulingRecursionTest, CancelFromEndLoopWhileInRunLoop) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ EndCommand dCancelsAll([&](bool) {
+ counter++;
+ scheduler.CancelAll();
+ });
+ EndCommand cCancelsD([&](bool) {
+ counter++;
+ scheduler.Cancel(&dCancelsAll);
+ });
+ EndCommand bCancelsC([&](bool) {
+ counter++;
+ scheduler.Cancel(&cCancelsD);
+ });
+ EndCommand aCancelsB([&](bool) {
+ counter++;
+ scheduler.Cancel(&bCancelsC);
+ });
+ scheduler.Schedule(&aCancelsB);
+ scheduler.Schedule(&bCancelsC);
+ scheduler.Schedule(&cCancelsD);
+ scheduler.Schedule(&dCancelsAll);
+
+ EXPECT_NO_THROW({ scheduler.Run(); });
+ EXPECT_EQ(4, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&aCancelsB));
+ EXPECT_FALSE(scheduler.IsScheduled(&bCancelsC));
+ EXPECT_FALSE(scheduler.IsScheduled(&cCancelsD));
+ EXPECT_FALSE(scheduler.IsScheduled(&dCancelsAll));
+}
+
+class MultiCancelCommand : public CommandHelper<Command, MultiCancelCommand> {
+ public:
+ MultiCancelCommand(CommandScheduler* scheduler, int& counter,
+ Command* command)
+ : m_scheduler(scheduler), m_counter(counter), m_command(command) {}
+
+ void End(bool interrupted) override {
+ m_counter++;
+ m_scheduler->Cancel(m_command);
+ m_scheduler->Cancel(this);
+ }
+
+ private:
+ CommandScheduler* m_scheduler;
+ int& m_counter;
+ Command* m_command;
+};
+
+TEST_F(SchedulingRecursionTest, MultiCancelFromEnd) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ EndCommand bIncrementsCounter([&counter](bool) { counter++; });
+ MultiCancelCommand aCancelsB{&scheduler, counter, &bIncrementsCounter};
+
+ scheduler.Schedule(&aCancelsB);
+ scheduler.Schedule(&bIncrementsCounter);
+
+ EXPECT_NO_THROW({ scheduler.Cancel(&aCancelsB); });
+ EXPECT_EQ(2, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&aCancelsB));
+ EXPECT_FALSE(scheduler.IsScheduled(&bIncrementsCounter));
+}
+
+TEST_P(SchedulingRecursionTest, ScheduleFromEndCancel) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ TestSubsystem requirement;
+ SelfCancellingCommand selfCancels{&scheduler, counter, &requirement,
+ GetParam()};
+ RunCommand other{[] {}, {&requirement}};
+
+ scheduler.Schedule(&selfCancels);
+ EXPECT_NO_THROW({ scheduler.Cancel(&selfCancels); });
+ EXPECT_EQ(1, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
+}
+
+TEST_P(SchedulingRecursionTest, ScheduleFromEndInterrupt) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ TestSubsystem requirement;
+ SelfCancellingCommand selfCancels{&scheduler, counter, &requirement,
+ GetParam()};
+ RunCommand other{[] {}, {&requirement}};
+
+ scheduler.Schedule(&selfCancels);
+ EXPECT_NO_THROW({ scheduler.Schedule(&other); });
+ EXPECT_EQ(1, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
+ EXPECT_TRUE(scheduler.IsScheduled(&other));
+}
+
+TEST_F(SchedulingRecursionTest, ScheduleFromEndInterruptAction) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ TestSubsystem requirement;
+ RunCommand selfCancels{[] {}, {&requirement}};
+ RunCommand other{[] {}, {&requirement}};
+ scheduler.OnCommandInterrupt([&](const Command&) {
+ counter++;
+ scheduler.Schedule(&other);
+ });
+ scheduler.Schedule(&selfCancels);
+ EXPECT_NO_THROW({ scheduler.Schedule(&other); });
+ EXPECT_EQ(1, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&selfCancels));
+ EXPECT_TRUE(scheduler.IsScheduled(&other));
+}
+
+TEST_F(SchedulingRecursionTest, CancelDefaultCommandFromEnd) {
+ CommandScheduler scheduler = GetScheduler();
+ int counter = 0;
+ TestSubsystem requirement;
+ FunctionalCommand defaultCommand{[] {},
+ [] {},
+ [&counter](bool) { counter++; },
+ [] { return false; },
+ {&requirement}};
+ RunCommand other{[] {}, {&requirement}};
+ FunctionalCommand cancelDefaultCommand{[] {}, [] {},
+ [&](bool) {
+ counter++;
+ scheduler.Schedule(&other);
+ },
+ [] { return false; }};
+
+ EXPECT_NO_THROW({
+ scheduler.Schedule(&cancelDefaultCommand);
+ scheduler.SetDefaultCommand(&requirement, std::move(defaultCommand));
+
+ scheduler.Run();
+ scheduler.Cancel(&cancelDefaultCommand);
+ });
+ EXPECT_EQ(2, counter);
+ EXPECT_FALSE(scheduler.IsScheduled(&defaultCommand));
+ EXPECT_TRUE(scheduler.IsScheduled(&other));
+}
+
INSTANTIATE_TEST_SUITE_P(
SchedulingRecursionTests, SchedulingRecursionTest,
testing::Values(Command::InterruptionBehavior::kCancelSelf,
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SwerveControllerCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SwerveControllerCommandTest.cpp
index 531e9d2..b96a1e1 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SwerveControllerCommandTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SwerveControllerCommandTest.cpp
@@ -17,8 +17,9 @@
#include <frc/kinematics/SwerveModuleState.h>
#include <frc/simulation/SimHooks.h>
#include <frc/trajectory/TrajectoryGenerator.h>
+#include <gtest/gtest.h>
-#include "gtest/gtest.h"
+#include "CommandTestBase.h"
#define EXPECT_NEAR_UNITS(val1, val2, eps) \
EXPECT_LE(units::math::abs(val1 - val2), eps)
@@ -72,7 +73,7 @@
};
TEST_F(SwerveControllerCommandTest, ReachesReference) {
- frc2::Subsystem subsystem;
+ frc2::TestSubsystem subsystem;
auto waypoints =
std::vector{frc::Pose2d{0_m, 0_m, 0_rad}, frc::Pose2d{1_m, 5_m, 3_rad}};
@@ -84,12 +85,11 @@
auto command = frc2::SwerveControllerCommand<4>(
trajectory, [&]() { return getRobotPose(); }, m_kinematics,
- frc2::PIDController(0.6, 0, 0), frc2::PIDController(0.6, 0, 0),
+ frc::PIDController(0.6, 0, 0), frc::PIDController(0.6, 0, 0),
m_rotController,
[&](auto moduleStates) { m_moduleStates = moduleStates; }, {&subsystem});
- m_timer.Reset();
- m_timer.Start();
+ m_timer.Restart();
command.Initialize();
while (!command.IsFinished()) {
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/NetworkButtonTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/NetworkButtonTest.cpp
index 51da1d2..3f969ac 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/NetworkButtonTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/NetworkButtonTest.cpp
@@ -2,6 +2,7 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
+#include <gtest/gtest.h>
#include <networktables/NetworkTableInstance.h>
#include "../CommandTestBase.h"
@@ -9,7 +10,6 @@
#include "frc2/command/RunCommand.h"
#include "frc2/command/WaitUntilCommand.h"
#include "frc2/command/button/NetworkButton.h"
-#include "gtest/gtest.h"
using namespace frc2;
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp
index 1a0af51..4acaa66 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp
@@ -3,6 +3,7 @@
// the WPILib BSD license file in the root directory of this project.
#include <frc/simulation/SimHooks.h>
+#include <gtest/gtest.h>
#include "../CommandTestBase.h"
#include "frc2/command/CommandPtr.h"
@@ -11,7 +12,6 @@
#include "frc2/command/RunCommand.h"
#include "frc2/command/WaitUntilCommand.h"
#include "frc2/command/button/Trigger.h"
-#include "gtest/gtest.h"
using namespace frc2;
class TriggerTest : public CommandTestBase {};
@@ -206,24 +206,6 @@
EXPECT_TRUE(scheduler.IsScheduled(&command));
}
-// this type of binding is deprecated and identical to OnTrue
-WPI_IGNORE_DEPRECATED
-TEST_F(TriggerTest, RValueTrigger) {
- auto& scheduler = CommandScheduler::GetInstance();
- int counter = 0;
- bool pressed = false;
-
- RunCommand command([&counter] { counter++; }, {});
-
- Trigger([&pressed] { return pressed; }).WhenActive(std::move(command));
- scheduler.Run();
- EXPECT_EQ(counter, 0);
- pressed = true;
- scheduler.Run();
- EXPECT_EQ(counter, 1);
-}
-WPI_UNIGNORE_DEPRECATED
-
TEST_F(TriggerTest, Debounce) {
auto& scheduler = CommandScheduler::GetInstance();
bool pressed = false;
diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/make_vector.h b/wpilibNewCommands/src/test/native/cpp/frc2/command/make_vector.h
index 05adf8e..996ddba 100644
--- a/wpilibNewCommands/src/test/native/cpp/frc2/command/make_vector.h
+++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/make_vector.h
@@ -34,8 +34,12 @@
std::is_constructible_v<T, First> && std::is_convertible_v<First, T>,
all_constructible_and_convertible<T, Rest...>, std::false_type> {};
-template <typename T, typename... Args,
- typename std::enable_if_t<!std::is_trivially_copyable_v<T>, int> = 0>
+template <typename T, typename First, typename... Rest>
+inline constexpr bool all_constructible_and_convertible_v =
+ all_constructible_and_convertible<T, First, Rest...>::value;
+
+template <typename T, typename... Args>
+ requires(!std::is_trivially_copyable_v<T>)
std::vector<T> make_vector_impl(Args&&... args) {
std::vector<T> vec;
vec.reserve(sizeof...(Args));
@@ -44,19 +48,17 @@
return vec;
}
-template <typename T, typename... Args,
- typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
+template <typename T, typename... Args>
+ requires std::is_trivially_copyable_v<T>
std::vector<T> make_vector_impl(Args&&... args) {
return std::vector<T>{std::forward<Args>(args)...};
}
} // namespace detail
-template <
- typename T = void, typename... Args,
- typename V = detail::vec_type_helper_t<T, Args...>,
- typename std::enable_if_t<
- detail::all_constructible_and_convertible<V, Args...>::value, int> = 0>
+template <typename T = void, typename... Args,
+ typename V = detail::vec_type_helper_t<T, Args...>>
+ requires detail::all_constructible_and_convertible_v<V, Args...>
std::vector<V> make_vector(Args&&... args) {
return detail::make_vector_impl<V>(std::forward<Args>(args)...);
}
diff --git a/wpilibNewCommands/src/test/native/cpp/main.cpp b/wpilibNewCommands/src/test/native/cpp/main.cpp
index 6aea19a..d181e39 100644
--- a/wpilibNewCommands/src/test/native/cpp/main.cpp
+++ b/wpilibNewCommands/src/test/native/cpp/main.cpp
@@ -2,10 +2,9 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
+#include <gtest/gtest.h>
#include <hal/HALBase.h>
-#include "gtest/gtest.h"
-
int main(int argc, char** argv) {
HAL_Initialize(500, 0);
::testing::InitGoogleTest(&argc, argv);
diff --git a/wpilibNewCommands/wpilibNewCommands-config.cmake.in b/wpilibNewCommands/wpilibNewCommands-config.cmake.in
index 75aa6ad..8a8d8d8 100644
--- a/wpilibNewCommands/wpilibNewCommands-config.cmake.in
+++ b/wpilibNewCommands/wpilibNewCommands-config.cmake.in
@@ -1,5 +1,4 @@
include(CMakeFindDependencyMacro)
- @FILENAME_DEP_REPLACE@
@WPIUTIL_DEP_REPLACE@
@NTCORE_DEP_REPLACE@
@CSCORE_DEP_REPLACE@
@@ -8,4 +7,5 @@
@WPILIBC_DEP_REPLACE@
@WPIMATH_DEP_REPLACE@
+ @FILENAME_DEP_REPLACE@
include(${SELF_DIR}/wpilibNewCommands.cmake)